# Build brief — a focused alternative to Dux-Soup

> **Verdict:** Partly, if you narrow it · **Buildability:** 63/100 · **Category:** Sales Outreach
> **Source:** https://www.canitbevibecoded.com/dux-soup
> Independent editorial assessment from Can It Be Vibe Coded? Not affiliated with, endorsed by, or derived from Dux-Soup. Verify current pricing and capabilities before acting.

## Context

**Dux-Soup** — Browser-based LinkedIn automation: visits profiles, sends connection requests and drip message sequences on your behalf. It currently costs $14.99/mo.

Mechanically this is a Playwright script that drives your own logged-in Chrome profile, clicks buttons, and waits a random number of seconds. An agent can get a working profile-visitor and connection-request sender running in a session, and a small campaign queue with daily caps by the end of a focused implementation. What you are actually buying from Dux-Soup is the accumulated caution: throttle curves that do not get your account restricted, selectors that keep working after LinkedIn reshuffles the DOM every few weeks, and a cloud mode so your laptop does not have to stay awake. Note that neither the paid tool nor your script is blessed by LinkedIn, so the ban risk is yours in both cases; you are just choosing who tunes the pacing. Build it if you want ten touches a day and enjoy fixing selectors, buy it if outreach volume is how you eat.

This brief describes a focused, single-operator replacement for the part of Dux-Soup that is genuinely reproducible. It is deliberately narrower than the product it replaces, and it says so in writing. Build the useful core; do not pretend to have rebuilt the rest.

## What you are building

Reads a CSV of LinkedIn profile URLs, drives your existing logged-in browser session to visit each one, optionally sends a connection request with a templated note, and logs outcomes to a local SQLite file with hard daily caps.

- Track contacts, sequence outreach, and log replies for a pipeline you own.
- A responsive interface with real empty, loading, success, and error states.

## Requirements

### Functional

- Node 20+ and a local Chrome or Chromium install.
- A LinkedIn account you are willing to risk, logged in via a persistent browser profile.
- A CSV of target profile URLs, sourced by you.
- A machine that stays awake during campaign windows.
- Tolerance for re-fixing selectors whenever LinkedIn ships a UI change.

### Non-functional

- Accessibility: semantic markup, labelled controls, visible focus, and reduced-motion support.
- Security: server-side secrets, validated input, and no credentials in the client bundle.
- Reliability: retries with backoff on external calls, and a clear failure state when a provider is down.
- Portability: the operator can export their data and leave without losing it.

## Implementation brief

Build a local LinkedIn outreach assistant that drives my own browser. Stack: TypeScript, Node 20, Playwright with a persistent Chromium user data dir, better-sqlite3 for state, no server, no cloud, no telemetry, no account system. CLI only.

Structure:
- src/browser.ts: launches Playwright chromium with userDataDir from .env (PROFILE_DIR), headed by default so I can watch and take over.
- src/login.ts: opens linkedin.com and waits for me to log in manually, then exits. Never handle or store my password. No credentials in code or .env.
- src/db.ts: SQLite schema for targets (url, name, status, added_at) and actions (target_url, action_type, result, ran_at).
- src/import.ts: reads targets.csv (column: profile_url, optional first_name) and inserts new rows as status 'queued'.
- src/run.ts: the campaign loop.

Campaign loop rules:
- Read config from config.json: daily_visit_cap, daily_connect_cap, active_hours (start and end, local time), min_delay_seconds, max_delay_seconds.
- Default caps low and boring: 20 visits, 10 connects.
- Sleep a random interval between min and max delay between every action, plus a longer random pause every 5 actions.
- Stop immediately and log if the page shows a captcha, a checkpoint, an 'unusual activity' interstitial, or a login redirect. Do not retry.
- Actions: visit profile, and optionally click Connect and add a note rendered from templates/connect.txt with {{first_name}} substitution. Truncate notes to the field limit.
- Everything runs in dry-run mode unless --live is passed. Dry run logs the exact action it would take.
- Idempotent: never act twice on the same target for the same action type.

Also include: src/report.ts printing counts by status and action outcome, a README that states plainly that this automates a logged-in session and may violate LinkedIn's user agreement and can get an account restricted, and a .env.example with PROFILE_DIR only.

Out of scope: scraping or guessing email addresses, bulk profile data export, running headless to evade detection, proxy rotation, multiple accounts, reply detection, CRM sync, any hosted component.

## Delivery standard

- Inspect the repository first, then write a short implementation plan before writing code.
- Deliver the smallest complete end-to-end workflow first; every primary control must work against persisted data.
- Use real validation and storage; never substitute fake dashboards, decorative controls, hard-coded success states, or mock integrations.
- Include responsive layouts plus genuine empty, loading, success, validation, and failure states.
- Keep secrets server-side in environment variables, provide .env.example, and never commit credentials or user data.
- Add structured logs around every external call and return actionable errors without leaking sensitive details.
- Write unit tests for the core logic and one automated test of the main user journey.
- Finish with a README covering setup, architecture, data location, backups, tests, deployment, and known limitations.

## Acceptance criteria

- [ ] A clean install starts the app using only the README and .env.example.
- [ ] The primary journey works from first visit through saved result, reload, edit, export, and deletion where applicable.
- [ ] Invalid input, missing configuration, provider failure, and an empty database each have a usable state.
- [ ] The interface works at 390px and 1440px, is keyboard navigable, and shows visible focus on every control.
- [ ] Tests, type checking, linting, and a production build all pass with no ignored failures.
- [ ] No part of the interface implies a live integration, security guarantee, or scale capability that was not actually built and verified.

## Non-goals

Do not build these, and do not claim to have replaced them:

- Pacing heuristics and safety limits tuned across a lot of accounts, not guessed at by you.
- Selector maintenance: when LinkedIn changes markup, someone else patches their extension and nobody patches yours.
- Cloud execution, so campaigns keep running with your laptop shut.
- Webhook and CRM plumbing into HubSpot, Pipedrive and friends, plus Zapier glue.
- Campaign reporting, reply detection and sequence branching that actually stops when someone answers.

## What you still own after launch

- Run migrations, backups, restores, and dependency updates.
- Test the critical journey after every model, API, or hosting change.
- Monitor failures and fix the edge cases a first prompt will miss.
- Maintain every third-party integration as APIs and OAuth rules change.

## Risk

**Operational risk.** The code is achievable; dependable data, integrations, and ongoing operations are the real cost.

Editorial confidence in this assessment: medium. No reviewed project implementation is linked yet.

---

Generated by [Can It Be Vibe Coded?](https://www.canitbevibecoded.com) · Full report: https://www.canitbevibecoded.com/dux-soup
