Skip to content
Β 
Β 

Latest commit

Β 

History

482 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

OpenOutreach Logo

The open-source growth engine that puts your LinkedIn B2B lead generation on autopilot.

GitHub stars GitHub forks License: GPLv3 Open Issues


Demo:

Demo Animation

πŸš€ What is OpenOutreach?

OpenOutreach is a self-hosted, open-source LinkedIn automation tool designed for B2B lead generation, without the risks and costs of cloud SaaS services.

It automates the entire outreach process in a stealthy, human-like way:

  • Discovers and enriches target profiles
  • Qualifies and ranks profiles using online Bayesian active learning (BALD acquisition + entropy-gated auto-decisions)
  • Sends personalized connection requests
  • Follows up with custom messages after acceptance
  • Tracks everything in a built-in CRM with web UI (full data ownership, resumable workflows)

Why choose OpenOutreach?

  • πŸ›‘οΈ Undetectable β€” Playwright + stealth plugins mimic real user behavior
  • 🐍 Fully customizable β€” Python-based campaigns for unlimited flexibility
  • πŸ’Ύ Local execution + CRM β€” You own your data, browse it in a web UI
  • 🐳 Easy deployment β€” Dockerized, one-command setup
  • ✨ AI-ready β€” Built-in templating for hyper-personalized messages (easy integration with latest models like GPT-5.3-Codex)

Perfect for founders, sales teams, and agencies who want powerful automation without account bans or subscription lock-in.


⚑ Quick Start (Docker β€” Recommended)

The fastest way to get started. Pre-built images are published to GitHub Container Registry on every push to master.

docker run --pull always -it -p 5900:5900 -v openoutreach_data:/app/assets ghcr.io/eracle/openoutreach:latest

The interactive onboarding will prompt you for LinkedIn credentials, LLM API key, and campaign details on first run. Your data persists in the openoutreach_data Docker volume across restarts.

Connect a VNC client to localhost:5900 to watch the browser live.

For Docker Compose, build-from-source, and more options see the Docker Guide.


βš™οΈ Local Installation (Development)

For contributors or if you prefer running directly on your machine.

Prerequisites

1. Clone & Set Up

git clone https://github.com/eracle/OpenOutreach.git
cd OpenOutreach

# Install deps, Playwright browsers, run migrations, and bootstrap CRM
make setup

2. Run the Daemon

make run

The interactive onboarding will prompt for LinkedIn credentials, LLM API key, and campaign details on first run. Fully resumable β€” stop/restart anytime without losing progress.

3. View Your Data (CRM Admin)

OpenOutreach includes a full CRM web interface powered by DjangoCRM:

# Create an admin account (first time only)
python manage.py createsuperuser

# Start the web server
make admin

Then open:


✨ Features

Feature Description
πŸ€– Advanced Browser Automation Powered by Playwright with stealth plugins for human-like, undetectable interactions.
πŸ›‘οΈ Reliable Data Scraping Uses LinkedIn's internal Voyager API for accurate, structured profile data (no fragile HTML parsing).
🐍 Python-Native Campaigns Write flexible, powerful automation sequences directly in Python.
🧠 ML-Driven Qualification Gaussian Process Classifier with BALD active learning qualifies and ranks profiles -- lazily re-fitted on all accumulated labels when predictions are needed.
πŸ”„ Stateful Workflow Engine Tracks profile states (DISCOVERED β†’ ENRICHED β†’ QUALIFIED β†’ PENDING β†’ CONNECTED β†’ COMPLETED) in a local DB -- resumable at any time.
⏱️ Smart Rate Limiting Configurable daily/weekly limits per action type, respects LinkedIn's own limits automatically.
πŸ’Ύ Built-in CRM Full data ownership via DjangoCRM with Django Admin UI -- browse Leads, Contacts, Companies, and Deals in your browser.
🐳 Containerized Setup One-command Docker + Make deployment.
πŸ–₯️ Visual Debugging Real-time browser view via built-in VNC server (localhost:5900).
✍️ AI-Ready Templating Jinja or AI-prompt templates for hyper-personalized messages (plug in latest models like GPT-5.3-Codex easily).

❀️ Support OpenOutreach – Keep the Leads Flowing!

This project is built in spare time to provide powerful, free open-source growth tools.

Maintaining stealth, fixing bugs, adding features (multi-account scaling, better templates, AI enhancements), and staying ahead of LinkedIn changes takes serious effort.

Your sponsorship funds faster updates and keeps it free for everyone.

Sponsor with GitHub


Popular Tiers & Perks:

Tier Monthly Benefits
β˜• Supporter $5 Huge thanks + name in README supporters list
πŸš€ Booster $25 All above + priority feature requests + early access to new campaigns
🦸 Hero $100 All above + personal 1-on-1 support + influence roadmap
πŸ’Ž Legend $500+ All above + custom feature development + shoutout in releases

Thank you to all sponsors β€” you're powering open-source B2B growth! πŸš€


πŸ—“οΈ Book a Free 15-Minute Call

Got a specific use case, feature request, or questions about setup?

Book a free 15-minute call β€” I’d love to hear your needs and improve the tool based on real feedback.

Book a 15-min call


πŸ“– Usage & Customization

The daemon (linkedin/daemon.py) priority-schedules five action lanes:

Lane What it does Rate limited?
Connect Ranks QUALIFIED profiles by GPC posterior probability, sends connection requests Daily + weekly limits
Check Pending Checks if PENDING requests were accepted Exponential backoff
Follow Up Sends personalized messages to CONNECTED profiles Daily limit
Enrich Scrapes DISCOVERED profiles via LinkedIn's Voyager API, computes embeddings Gap-filling
Qualify Qualifies ENRICHED profiles via Bayesian active learning (BALD selects, entropy gates LLM calls) Gap-filling
Search Discovers new profiles via LLM-generated LinkedIn People search keywords Lowest-priority gap-filler

Profile states: DISCOVERED β†’ ENRICHED β†’ QUALIFIED β†’ PENDING β†’ CONNECTED β†’ COMPLETED (or FAILED / IGNORED / DISQUALIFIED)

Pre-existing connections (already connected before automation) are automatically set to IGNORED during enrichment. If connection_degree was unknown at scrape time, they're caught during the connect step. Profiles rejected by the qualification pipeline are set to DISQUALIFIED.

Configure rate limits, timing, and behavior in the campaign: section of accounts.secrets.yaml.


πŸ“‚ Project Structure

β”œβ”€β”€ analytics/                       # dbt project (DuckDB analytics, ML training sets)
β”‚   β”œβ”€β”€ models/staging/              # Staging views (stg_leads, stg_deals, stg_stages)
β”‚   └── models/marts/                # ML training set (ml_connection_accepted)
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ accounts.secrets.yaml        # Credentials + campaign + LLM config (gitignored)
β”‚   β”œβ”€β”€ inputs/                      # Optional input files
β”‚   β”œβ”€β”€ campaign/                    # Onboarding files (product_docs.txt, campaign_objective.txt)
β”‚   └── data/                        # crm.db (SQLite), analytics.duckdb (embeddings + analytics)
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ architecture.md              # System architecture
β”‚   β”œβ”€β”€ configuration.md             # Configuration reference
β”‚   β”œβ”€β”€ docker.md                    # Docker setup guide
β”‚   β”œβ”€β”€ templating.md                # Message template guide
β”‚   └── testing.md                   # Testing strategy
β”œβ”€β”€ linkedin/
β”‚   β”œβ”€β”€ actions/                     # Browser actions (connect, message, scrape)
β”‚   β”œβ”€β”€ api/                         # Voyager API client + parser
β”‚   β”œβ”€β”€ conf.py                      # Configuration loading (secrets YAML + env vars)
β”‚   β”œβ”€β”€ daemon.py                    # Main daemon loop (priority-scheduled lanes)
β”‚   β”œβ”€β”€ db/crm_profiles.py           # CRM-backed profile CRUD (Lead, Contact, Company, Deal)
β”‚   β”œβ”€β”€ django_settings.py           # Django/CRM settings (SQLite at assets/data/crm.db)
β”‚   β”œβ”€β”€ lanes/                       # Action lanes (enrich, qualify, connect, check_pending, follow_up, search)
β”‚   β”œβ”€β”€ management/setup_crm.py      # Idempotent CRM bootstrap (Dept, Stages, Users)
β”‚   β”œβ”€β”€ ml/                          # Bayesian qualifier, DuckDB embeddings, profile text, search keywords
β”‚   β”œβ”€β”€ navigation/                  # Login, throttling, browser utilities, enums
β”‚   β”œβ”€β”€ onboarding.py                # Interactive onboarding (product docs + campaign objective)
β”‚   β”œβ”€β”€ gdpr.py                      # GDPR location detection for newsletter
β”‚   β”œβ”€β”€ rate_limiter.py              # Daily/weekly rate limiting
β”‚   β”œβ”€β”€ sessions/                    # Session management (AccountSession)
β”‚   └── templates/                   # Message rendering (Jinja2 / AI-prompt)
β”œβ”€β”€ manage.py                         # Entry point (no args = daemon, or Django commands)
β”œβ”€β”€ local.yml                        # Docker Compose
└── Makefile                         # Shortcuts (setup, run, admin, analytics, test)

πŸ“š Documentation


πŸ’¬ Community

Join for support and discussions:
Telegram Group


βš–οΈ License

GNU GPLv3 β€” see LICENCE.md


πŸ“œ Legal Disclaimer

Not affiliated with LinkedIn.

Automation may violate LinkedIn's terms (Section 8.2). Risk of account suspension exists.

Use at your own risk β€” no liability assumed.

Accounts in non-GDPR jurisdictions are auto-subscribed to the OpenOutreach newsletter on first run. You can disable this via subscribe_newsletter in your account config.


Made with ❀️

About

Linkedin Automation Tool: Visit Profile, Connect, Message with AI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages