Send LinkedIn connection requests to a list of people via browser automation and track status in a CSV/TSV file. Use when the user wants to bulk-connect with a list of people on LinkedIn (founders, speakers, leads, etc.) from a spreadsheet or list containing LinkedIn profile URLs. Handles Connect button, Follow-mode profiles, already-connected detection, stale URL fallback via LinkedIn search and Google search, and incremental status tracking.
94
Does it follow best practices?
Validation for skill structure
Automates sending LinkedIn connection requests from a list and tracks results in a data file.
Before doing anything else, confirm all of the following with the user. Do not proceed until each item is confirmed.
Ask the user to provide their spreadsheet/CSV/TSV file and confirm it has (or can have) these columns:
If the file lacks any column, tell the user which columns are missing and offer to add them.
Ask which browser setup they're using:
Option A — Chrome Browser Relay (recommended for accounts flagged for automation)
profile="chrome" for all browser tool calls in this modeOption B — OpenClaw Isolated Browser (openclaw profile)
https://www.linkedin.com and let the user log in; cookies persist across sessionsprofile="openclaw" for all browser tool calls in this modeConfirm which option they've set up. Default to Option A (Chrome Relay) if the user's account has been flagged or warned about automation.
Only proceed once the user says:
Set the profile variable based on user's choice in the Pre-flight Checklist:
profile="chrome" — reuse the relay-attached tab; get targetId via browser action=tabsprofile="openclaw" — OpenClaw-managed isolated Chrome instanceDo not mix profiles mid-run. Pick one and use it consistently for every browser tool call.
Ensure the tracking file has a Connection Status column. If missing, add it:
import csv
rows = []
with open('file.tsv', 'r') as f:
reader = csv.DictReader(f, delimiter='\t')
fieldnames = reader.fieldnames + ['Connection Status']
rows = list(reader)
with open('file.tsv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter='\t')
writer.writeheader()
for row in rows:
row['Connection Status'] = ''
writer.writerow(row)Always try in this order. Move to the next tier only if the current one fails.
Navigate directly to the LinkedIn profile URL from the data file.
Search Google for "Founder Name" "Brand/Company" linkedin.
https://www.google.com/search?q=<Name>+<Company>+linkedinRun a LinkedIn people search for the founder + brand directly inside LinkedIn.
https://www.linkedin.com/search/results/people/?keywords=<Name>+<Company>Connect buttons first; otherwise open the profile from search resultsProfile Not FoundSee references/browser-workflow.md for detailed browser steps for each tier.
Once on the correct profile, two patterns exist:
Pattern A - Direct Connect button visible on profile → click it → confirm dialog → Send without a note
Pattern B - Follow mode (no Connect button, only Follow + Message + More) → click More actions → use selector .artdeco-dropdown__content--is-open to get dropdown → click Invite [Name] to connect → confirm dialog → Send without a note
If neither Connect nor Invite is available → mark Follow Only.
| Status | Meaning |
|---|---|
Request Sent | Connection request sent this session |
Already Connected | 1st degree - no action needed |
Pending | Request already sent previously |
Follow Only | No Connect option available on this profile |
Profile Not Found | All three tiers failed |
Skipped | Intentionally skipped |
When a TSV row has multiple founders, track per-founder status separated by |:
Founder1Slug: Request Sent | Founder2Slug: Already Connected⚠️ LinkedIn flags accounts that jump directly between profile URLs. Always visit the feed between profiles — no exceptions.
/feed/ before every single profile, without exception. See references/browser-workflow.md for the exact call. This is the primary anti-detection measure.Use a linkedin_progress.json sidecar file:
{ "statuses": { "https://www.linkedin.com/in/username/": "Request Sent" } }Update the TSV from this dict every 10 profiles or at the end.
references/browser-workflow.md - Detailed browser steps for all three tiers and both connect patternse3f10d1
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.