Loading repository dataβ¦
Loading repository dataβ¦
LeandroPG19 / repository
π¬ LinkedIn Easy Apply automation bot with advanced anti-detection bypass. Reverse engineering of LinkedIn's bot detection systems: stealth.js injection, DOM trap evasion, browser fingerprint spoofing, and AI-powered form filling. Built with Python 3.14, Playwright, and DeepSeek AI. Ethical hacking & security research β educational purposes only.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
π¬ Automated LinkedIn Easy Apply bot with advanced anti-detection bypass, reverse-engineered browser stealth, and AI-powered form filling β for ethical hacking education and security research only
This project is strictly for educational purposes in the fields of ethical hacking, reverse engineering, and web automation security research. Using bots on LinkedIn violates their Terms of Service and may result in account restrictions or suspension. Use at your own risk. Consider using a secondary account for testing.
This project demonstrates practical exploitation of web application anti-bot defenses through:
max_steps=10 without crashingstealth.js) injected into browser contextforce=True) to bypass DOM trapsnavigator.webdriver flag hiddenElementHandle, AsyncSession, SecretStrfrom __future__ import annotations)datetime.UTC β Modern alias instead of timezone.utcAsyncGenerator[T] β Without redundant second None parameterzip(strict=True) β Length validation on paired iterationsDatabaseManager | None)git clone https://github.com/LeandroPG19/linkedin-easyapply-antidetection-bot.git
cd linkedin-easyapply-antidetection-bot
python -m venv .venv && source .venv/bin/activate
pip install -e .
playwright install chromium
cp .env.example .env
Edit .env with your credentials:
DEEPSEEK_API_KEY=sk-your-key-here
LINKEDIN_EMAIL=your-email@example.com
LINKEDIN_PASSWORD=your-password
RESUME_PATH=./resume.pdf
DRY_RUN=true # Start with dry run!
Copy and edit the resume template:
cp resume.yaml.example resume.yaml
Edit search_config.yaml with your search preferences.
# Dry run (does not submit applications)
python -m linkedin_bot.main
# Live mode (actually submits)
# Set DRY_RUN=false in .env first
python -m linkedin_bot.main
# Or use the registered CLI
linkedin-apply
linkedin-easyapply-antidetection-bot/
βββ linkedin_bot/
β βββ __init__.py
β βββ main.py # Main orchestrator + CLI entry point
β βββ config.py # Pydantic Settings (.env) + SearchConfig (YAML)
β βββ logger.py # structlog (JSON structured logging)
β βββ enums.py # StrEnum: ApplicationStatus, CircuitState
β βββ exceptions.py # Hierarchy of 15 custom exceptions
β βββ stealth.js # Anti-detection JavaScript (injected into browser)
β βββ ai_engine.py # DeepSeek AI + Circuit Breaker + Retry
β βββ browser.py # Playwright session + stealth + human delays
β βββ linkedin_auth.py # Login + session verification
β βββ job_search.py # URL builder + listings extractor
β βββ applicator.py # Easy Apply form filler + multi-step navigation
β βββ tracker.py # Application tracking (dedup by job_id)
β βββ db/
β βββ __init__.py
β βββ models.py # SQLAlchemy 2.0 models (ApplicationRecord)
β βββ session.py # DatabaseManager singleton (async SQLite)
β βββ repository.py # Repository pattern (UPSERT + stats)
βββ cookies/ # Saved sessions (gitignored)
βββ logs/ # bot_database.db + logs (gitignored)
βββ resume.yaml.example # Resume template (edit and rename to resume.yaml)
βββ search_config.yaml # Search filters
βββ .env.example # Credentials template
βββ pyproject.toml # Dependencies + ruff + mypy config
βββ README.md
βββββββββββββββββββββββββββββββββββββββββββ
β main.py (Orchestrator) β
β CLI β Config β Auth β Search β Apply β
βββββββββββββββββββββββββββββββββββββββββββ€
β ai_engine.py β tracker.py β
β Circuit Breaker β Deduplication β
β Retry + Backoff β Stats (by enum) β
ββββββββββββββββββββββββΌβββββββββββββββββββ€
β browser.py β db/ β
β Playwright + Stealthβ SQLAlchemy 2.0 β
β Human delays β Repository β
β Cookie persistence β DatabaseManager β
ββββββββββββββββββββββββ΄βββββββββββββββββββ
.env β Credentials & Behavior| Variable | Description | Default |
|---|---|---|
DEEPSEEK_API_KEY | DeepSeek API key | Required |
DEEPSEEK_BASE_URL | API base URL | https://api.deepseek.com |
DEEPSEEK_MODEL | Model to use | deepseek-chat |
LINKEDIN_EMAIL | LinkedIn email | Required |
LINKEDIN_PASSWORD | LinkedIn password | Required |
RESUME_PATH | Path to resume PDF | (optional) |
MAX_APPLICATIONS_PER_SESSION | Max apps per run | 30 |
MAX_PAGES_PER_SEARCH | Max pages per keyword | 3 |
MIN_DELAY_SECONDS | Minimum delay between actions | 3.0 |
MAX_DELAY_SECONDS | Maximum delay between actions | 8.0 |
AI_MAX_RETRIES | AI retries per call | 3 |
AI_RETRY_DELAY | Base delay between retries | 2.0 |
DRY_RUN | Test mode (no submissions) | true |
HEADLESS | Headless browser | false |
search_config.yaml β Job Search Filterskeywords:
- "Software Engineer"
- "Backend Developer"
remote_only: true
experience_levels: [3, 4] # 2=Entry, 3=Associate, 4=Mid-Senior
date_posted: 2 # 1=24h, 2=week, 3=month
locations: [""] # Empty = no filter
blacklist_titles:
- "senior"
- "staff"
blacklist_companies:
- "Acme Corp"
min_match_score: 50 # 0-100 (AI threshold)
resume.yaml β Your ProfileSee resume.yaml.example for a complete template with all supported fields.
| Pattern | Implementation |
|---|---|
| Circuit Breaker | 5 consecutive failures β OPEN (30s cooldown) β HALF_OPEN (1 test) |
| Exponential Backoff | delay = min(base Γ 2^attempt, max_delay) + random jitter |
| Deduplication | Tracking by job_id (applied + dry_run + skipped) |
| Graceful Abort | Forms with >10 steps are aborted without crash |
| Modal Evasion | Auto-detects "Discard"/"Save" modals |
| UPSERT | If a job_id already exists in DB, updates status |
# Activate virtualenv
source .venv/bin/activate
# Linting (9 rules)
ruff check linkedin_bot/
# Type checking (strict mode)
mypy linkedin_bot/ --strict
# Cyclomatic complexity
radon cc linkedin_bot/ -a -nc
# All together
ruff check linkedin_bot/ && mypy linkedin_bot/ --strict && radon cc linkedin_bot/ -a -nc
pip install mypy types-PyYAML radon ruff
| Component | Technology | Version |
|---|---|---|
| Runtime | Python | β₯3.14 |
| Browser | Playwright | β₯1.49.0 |
| AI | OpenAI SDK (DeepSeek) | β₯1.58.0 |
| ORM | SQLAlchemy (async) | β₯2.0.30 |
| DB | SQLite (aiosqlite) | β₯0.20.0 |
| Config | Pydantic Settings | β₯2.7.0 |
| Logging | structlog | β₯25.1.0 |
| HTTP | httpx | β₯0.28.0 |
| CLI | Rich | β₯13.9.0 |
| YAML | PyYAML | β₯6.0.2 |
DeepSeek API is extremely affordable:
.env (gitignored)resume.yaml (gitignored).env.example and resume.yaml.example with placeholder datapathlib.resolve()MIT β See LICENSE for details.