How to automate LinkedIn outreach?
A step-by-step guide to LinkedIn outreach automation concepts using OpenOutreach, an open-source Playwright-based tool.
If you’ve been following my previous posts on cold outreach and personalized outbound campaigns, you know the infrastructure and targeting matter more than volume. LinkedIn automation is a logical next step—but it’s also where many people get their accounts nuked.
Disclaimer (read this first): This post is educational and not an endorsement to automate LinkedIn. Automation may violate LinkedIn’s Terms of Service and/or applicable laws depending on your jurisdiction and use case.
This post is a deep dive into LinkedIn outreach automation using OpenOutreach as a case study. I’m looking at it from a systems perspective (tooling, constraints, and failure modes). Before we get there, let’s establish what you’re actually risking.
LinkedIn’s Crackdown
LinkedIn has made its position crystal clear. In April 2025, the platform officially banned two of the largest automation platforms: Apollo.io and Seamless.ai.
These weren’t small accounts. These were enterprise tools used by thousands of sales teams. The message is unambiguous: LinkedIn sees automation as a threat to its user experience.
The detection mechanisms are sophisticated. LinkedIn doesn’t just look at volume. It analyzes:
- Timing patterns between actions (bots are predictable; humans aren’t)
- Message similarity across your outreach (variation is humanlike; templates are not)
- Account history and behavioral change (a dormant account suddenly sending 50 connections? Red flag)
Exceeding your connection request limits or getting caught using unapproved third-party tools can result in:
- Temporary account restrictions (most common)
- Permanent shadow-banning (your visibility tanks, but you don’t know why)
- Complete account suspension (nuclear option, but it happens)
Mitigating this risk: If you decide to experiment despite the risks, don’t do it on your main professional profile. Warm up new accounts slowly—spend a week engaging manually before doing anything aggressive. And respect the limits.
There is no official LinkedIn DM API
LinkedIn provides APIs for corporate use cases (recruiter tools, sales navigator), but there is no official DM or connection request API for individuals. This means every automation tool on the market—including OpenOutreach—relies on one of two approaches:
- Web browser-based automation (Selenium, Playwright)
- Android app-based automation (higher limits, but difficult to implement)
Web browser automation is more accessible and battle-tested. Android-based tools can hit higher rate limits because they mimic native app behavior, but they’re harder to maintain and less stable.
Why OpenOutreach?
Simply put, OpenOutreach is a solid, well-structured starting point for LinkedIn automation. I forked it for a few reasons:
- It’s purpose-built for a specific set of LinkedIn automations.
- I refactored it into a FastAPI server to drop CSV inputs, templating, and AI generation, so campaign logic can live elsewhere.
- I wanted it more atomic and modular—structured around an API layer, atomic touchpoints, and runs/scheduling/account-locking—so it can plug into a broader campaign manager.
- I wanted to use Patchright instead of Playwright Stealth.
Patchright is a fork of Playwright which uses a patched version of the chrome/chromium driver.
The server exposes touchpoints like profile_visit, connect, direct_message, post_react, post_comment, inmail, and profile_enrich (names may change in the future).
Prerequisites
- Docker and Docker Compose installed
- A LinkedIn account (preferably a dedicated one)
- VNC viewer (to monitor the browser, optional)
Installation
Clone the repository (choose one):
# Upstream project
# git clone https://github.com/eracle/OpenOutreach.git
# My API-server fork
git clone https://github.com/SarthakMishra/OpenOutreach.git
cd OpenOutreach
Build and run with Docker Compose:
docker compose build
docker compose up
By default, the API server runs on http://localhost:8000. VNC access for browser debugging is typically exposed on port 5900 (check docker-compose.yml in the repo you’re using).
Creating a LinkedIn automation pipeline
In my fork of OpenOutreach, you trigger actions via API calls (one touchpoint per run). This separation is what makes it easier to integrate into a broader campaign manager later.
Here is a simple example that:
- Loads leads from
input/leads.csvwithlinkedin_urlandnote - Creates a
profile_visitrun - Polls until the run is
completed(orfailed) - If the visit completes, creates a
connectrun with the note
This exact flow lives in my cold-email-tools repo under the LinkedIn automation pipeline: SarthakMishra/cold-email-tools.
1. Creating a run (one touchpoint per API call):
endpoint = f"{self.api_url}/api/v1/runs"
payload = {
"handle": handle,
"touchpoint": {
"type": touchpoint_type, # "profile_visit", "connect", etc.
**touchpoint_data, # url, note, duration_s, scroll_depth...
},
"dry_run": dry_run,
"tags": tags or {},
}
resp = requests.post(endpoint, headers=self.headers, json=payload, timeout=30)
resp.raise_for_status()
return resp.json()
2. Polling a run until it finishes (terminal state):
start_time = time.time()
last_status = None
while True:
if time.time() - start_time > timeout:
raise TimeoutError(f"Run {run_id} did not complete within {timeout}s")
run_data = self.get_run(run_id)
status = run_data.get("status")
if status != last_status:
logger.info("Run %s: %s → %s", run_data.get("run_id"), last_status or "initial", status)
last_status = status
if status in ["completed", "failed"]:
return run_data
time.sleep(poll_interval)
3. The pipeline control flow (visit first, then connect):
# Step 1: visit profile
visit = self.client.create_run(
handle=self.account_handle,
touchpoint_type="profile_visit",
touchpoint_data={
"url": linkedin_url,
"duration_s": PROFILE_VISIT_DURATION_S,
"scroll_depth": PROFILE_VISIT_SCROLL_DEPTH,
},
tags={"campaign": "linkedin_automation", "lead_idx": str(lead_idx)},
)
visit_final = self.client.poll_run_until_complete(visit["run_id"])
# Step 2: connect only if visit completed
if visit_final.get("status") == "completed":
connect = self.client.create_run(
handle=self.account_handle,
touchpoint_type="connect",
touchpoint_data={"url": linkedin_url, "note": note},
tags={"campaign": "linkedin_automation", "lead_idx": str(lead_idx)},
)
connect_final = self.client.poll_run_until_complete(connect["run_id"])
LinkedIn touchpoints you can automate
My fork of OpenOutreach supports several LinkedIn touchpoints. Here’s the priority ranking:
| Activity | Risk Level | Effectiveness | Recommendation |
|---|---|---|---|
| Profile Views | Low | Medium | Safe, use regularly |
| Connection Requests | Medium | High | Use with caution, |
| Post Reactions | Low | Low | Safe but limited impact |
| Direct Messages | High | High | Only if account is expendable |
| Comments | Medium | Medium | Somewhat safe |
| InMails | Very High | High | Use official credits only |
Connection requests are the highest-impact activity with manageable risk. DMs are tempting but riskier—LinkedIn monitors message patterns aggressively. Comments are safer but less direct.
My preferred workflow is:
- profile view
- like a recent post (if posted in the last 7 hours)
- connection request with a note
- direct messages (if the connection request is accepted)
LinkedIn limits all touchpoints, especially connection requests, to prevent abuse, and these limits keep changing. Always do your research and keep an eye on your logs to catch changes early.
- Free Account: 10/month with note (severely restricted)
- Premium: 100-200/week (depends on SSI score)
- Sales Navigator: 150-200/week (highest limit)
- High SSI Score: Up to 200/week (consistent engagement helps)
Best Practices for LinkedIn Automation
-
Use a dedicated account. Don’t automate your main profile. Create a secondary LinkedIn account specifically for outreach.
-
Always have a backup account. Assume your automation account will eventually get flagged. If you only have one account and it gets restricted, you’re forced into a dead period while you create a new account, warm it up, and rebuild trust. Keep a second account ready (and warmed) so you can switch without losing weeks.
-
Keep your behavior consistent. Avoid constantly switching devices, networks, and login patterns. For manual actions, use the mobile app. Avoid repeatedly signing in or creating new accounts on the web from multiple fresh sessions. Your automation already uses a web browser, and lots of web sign-ins/sign-ups can be a tell.
-
Warm up the account. Before running any automation, spend at least a week engaging manually. Like posts, comment on content, send a few manual connection requests. This builds a behavioral history that’s less suspicious.
-
Respect the weekly limits. Even if you think you can push higher, don’t. Send 80% of your weekly limit, not 100%. Leave buffer.
-
Randomize timing. OpenOutreach includes delay mechanisms. Use them. Connection requests should happen at different times—not always 9 AM, not always in batches of 10.
-
Personalize. Use AI to vary your messages. Minor variations in tone and reference points matter.
-
Mix manual and automated actions. Regularly approve connection requests, send replies, or engage with content manually. This reduces sudden behavioral shifts that can trigger restrictions.
-
Monitor your account health. Watch for warning signs:
- Connection requests showing “Pending” indefinitely (usually normal)
- Sudden inability to send requests (you’ve hit the limit; wait a week)
- Profile visibility dropping (possible shadow-ban; slow down immediately)
- Account restrictions message (stop automation; you’ve been flagged)
-
Have an exit plan. If your account gets restricted, don’t panic. Most temporary restrictions lift within a week. If it’s a permanent ban, accept it and move to your next account.
The ROI of it all
LinkedIn automation doesn’t scale the way email does.
You can send 1,000 personalized emails for practically nothing. You can have 100 people replying to your email sequences in parallel. With LinkedIn automation, you’re constrained to 100-200 connection requests per week, with unpredictable conversion rates (depends heavily on your profile, messaging, and targeting).
LinkedIn is best for:
- Building authority in your niche
- Creating warm introductions (LinkedIn connections are more likely to respond)
- B2B industries where decision-makers actively use LinkedIn
- Relationship-building over time (not immediate conversions)
LinkedIn is worst for:
- Bulk cold outreach (use email)
- High-volume lead generation (use email + forms)
- Startups with zero brand recognition (build on email first)
- Quick campaign testing (move too slowly)
The bottom line is, for most people, LinkedIn automation is a high-risk lever with a low ceiling. If you’re considering it at all, treat it as an experiment, keep expectations realistic, and don’t build your growth motion on something that can be shut down overnight.
What’s next?
This is part of a series of posts on building a modern cold outreach system:
- What works in cold outreach — infrastructure, targeting, and multi-channel strategy
- Scaling personalization with AI — enriching leads and generating personalized copy for under $5 per 1,000 leads
- Finding and validating work emails — generating email patterns and validating them at scale for under $0.001 per email
- How to automate LinkedIn outreach — LinkedIn outreach automation using open-source tools
Coming soon:
I’ll show you how to build a 100% automated appointment booking pipeline, end-to-end:
- Automatically finding leads from LinkedIn, Reddit, and other sources
- Automatically sending emails + LinkedIn DMs as a complete outbound sequence to get appointments booked
All built with Python, open-source tools, and cheap “pay-per-result” services.