From dealdeploy
DOM selectors, timing, JS patterns, and gotchas for LinkedIn browser automation
How this skill is triggered — by the user, by Claude, or both
Slash command
/dealdeploy:linkedin-browserThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Field-tested patterns and gotchas for automating LinkedIn via browser automation tools.
Field-tested patterns and gotchas for automating LinkedIn via browser automation tools.
headless: false (or equivalent). Headless mode will not work.--remote-debugging-port=9222.a[href*="/in/"] — profile links. The most reliable selector on LinkedIn search results. Class names like entity-result__title-text change frequently.document.querySelectorAll('button') filtered by innerText — buttons. More stable than class-based selectors.@e20) — the most reliable way to target elements. Always prefer these over coordinates.reusable-search__result-container, entity-result__*) across deploys. Don't depend on them.• 1st, • 2nd) appears in link text on search result cards, not as a separate element.Inline JS with quotes (single or double) gets mangled by shell escaping when passed to browser automation CLIs. Write JS to a temp file first:
cat > /tmp/extract.js << 'JSEOF'
JSON.stringify(
Array.from(document.querySelectorAll('a[href*="/in/"]'))
.map(a => ({ text: a.textContent.trim().substring(0, 200), url: a.href.split('?')[0] }))
.filter(a => a.url.includes('/in/') && !a.url.includes('{target_slug}'))
.reduce((acc, a) => { if (!acc.some(x => x.url === a.url)) acc.push(a); return acc; }, [])
)
JSEOF
Then evaluate the file contents in the browser context using whatever tool is available.
This temp-file pattern works reliably regardless of the automation tool's quoting rules.
Profile URLs from search results:
Array.from(document.querySelectorAll('a[href*="/in/"]'))
.map(a => ({ text: a.textContent.trim(), url: a.href.split('?')[0] }))
.filter(a => a.url.includes('/in/'))
.reduce((acc, a) => { if (!acc.some(x => x.url === a.url)) acc.push(a); return acc; }, [])
The link text on search result cards contains name, degree, title, location, and mutual connection names all concatenated. Parse with string splitting rather than relying on child element selectors.
fill vs type on the connection note modalfill (or equivalent set-value methods) on the connection note textarea. It causes the modal to dismiss unexpectedly — the note appears entered but the modal disappears.type, keyboard.type, etc.) instead. This keeps the modal open and enables the Send button correctly.fill works fine on other LinkedIn fields (e.g., the messaging panel compose box). The issue is specific to the "Add a note" modal.LinkedIn caps connection notes at 300 characters. Truncate to 297 + "..." if needed.
Clicking pagination buttons on LinkedIn search results can trigger "Frame was detached" errors, killing the browser connection entirely.
Detection: After clicking a page button, if snapshot returns empty or errors with "Target page, context or browser has been closed", the frame was detached.
Recovery:
Page 1, Page 2, etc. plus a Next buttonNext is absent, you're on the last pagenpx claudepluginhub dealdeploy/dd-plugin --plugin dealdeployAutomates LinkedIn via CLI: fetch profiles, search people/companies, send messages, manage connections, create posts, react, comment, and use Sales Navigator for outreach/research workflows.
Recon-first browser automation that explores a site, saves a guide, then delegates execution. Use for tasks like /browser-work, browser task, or automate this site.
Scans companies from your LinkedIn contacts for job openings matching resume and preferences. Caches careers pages for fast weekly checks. Invoke with contact count or 'all'.