| name | gtm-pipeline:outreach |
| description | Execute LinkedIn outreach — send connection requests and personalized messages/InMails to a contact list via PhantomBuster, one profile at a time on a timed loop. Use after people-enrichment when contacts are ready for outreach. Also triggers on "linkedin outreach", "send connection requests", "connect with leads on linkedin", "send linkedin messages", "send inmails", "start outreach", "launch outreach campaign", "put contacts on outreach". |
LinkedIn Outreach
Execute LinkedIn connection requests and personalized messages/InMails via PhantomBuster agents.
Read these files before executing:
.agents/skills/_shared/conventions.md
.agents/skills/_shared/phantombuster.md
When to Use
- Contacts are enriched and ready for LinkedIn outreach
- You want to send connection requests and/or InMails from a CSV
- You want to put outreach on a paced loop (every N minutes)
Inputs
| Input | Required | Source |
|---|
| Contacts CSV | Yes | People enrichment output or user-provided |
linkedin_profile_url column | Yes | Must be present |
linkedinMessage column | For messaging | Pre-generated by n8n message_agent or manually written |
inmailSubject column | For InMail | Pre-generated or user-provided |
If linkedinMessage / inmailSubject are missing, ask the user whether to generate them or use a single shared template message.
Agents
| Phase | Phantom Script | Local Config Key |
|---|
| 1 — Connection request | LinkedIn Auto Connect | PB_AGENT_CONNECT |
| 2 — Message / InMail | Sales Navigator Message Sender | PB_AGENT_MESSAGE |
Agent IDs are account-specific. Resolve via _shared/local.md (preferred) or PhantomBuster MCP (PHANTOMBUSTER_GET_AGENTS_FETCH_ALL → match by script name). See _shared/phantombuster.md.
Execution
Step 1: Inspect the CSV
Read 3–5 rows. Confirm:
linkedin_profile_url present and not empty
linkedinMessage and inmailSubject present if Phase 2 is needed
- Total row count
- Ask the user: run Phase 1 (connect), Phase 2 (message), or both?
Step 2: Generate scripts
Generate one Python script per phase, saved in the same directory as the CSV. Follow the script template in _shared/phantombuster.md exactly.
Script names:
pb_connect.py — connection requests
pb_message.py — messages / InMails
State files (auto-created alongside scripts):
pb_connect_state.json
pb_message_state.json
Use the argument templates from _shared/phantombuster.md. Do not save to the agent config permanently — always use the one-off argument override in the launch body.
Step 3: Test run each script
python3 "<path>/pb_connect.py"
python3 "<path>/pb_message.py"
Show full agent output. Look for:
✅ Connected successfully as [Your LinkedIn Name] — auth working
- Profile name in output — correct profile targeted
✅ 1 profile has been processed — success
If the output shows a type error (numberOfAddsPerLaunch => is the wrong type), the argument JSON has string values where booleans/ints are needed. Fix by ensuring json.dumps() is used on the argument dict.
Step 4: Suggest loop commands
After successful test runs, show the user:
✅ Both scripts tested successfully.
To process one profile every 20 minutes (10am–6pm Berlin time):
Phase 1 (connect):
/loop 20m python3 "<path>/pb_connect.py"
Phase 2 (message) — run after connections are accepted (typically 1–3 days):
/loop 20m python3 "<path>/pb_message.py"
Or run either script again immediately:
python3 "<path>/pb_connect.py"
State is tracked in pb_connect_state.json and pb_message_state.json —
each script picks up where it left off. Scripts exit cleanly when all profiles are done.
Rate Limit Guidance
| Agent | Safe Rate | Notes |
|---|
| LinkedIn Auto Connect | 1 per run, max ~14/day | 100/week LinkedIn hard limit. Pacing: every 20–30 min |
| Sales Navigator Message Sender | 1–3 per run | InMail credits apply for 3rd-degree / non-connections |
Example throughput: 43 contacts × 1/run × 20 min interval = ~24 runs/day (10am–6pm) → all connected in ~2 days.
Output
Append to run_log.md per conventions:
## Run Summary — outreach — {timestamp}
- Phase: {connect | message | both}
- Records in CSV: {total}
- Already processed: {done_count}
- Remaining: {total - done_count}
- Scripts: {paths}
- Loop commands: shown above