JobyBotsAI Job Hunter

Opt-in feature · Beta

LinkedIn Easy Apply, automated — with your full review.

Filter, open, fill, screenshot, stop. The bot walks each LinkedIn Easy Apply form in a visible Chromium window so you watch it work — and you flip the "actually submit" switch only when you trust it.

Off by default. Requires ENABLE_EASY_APPLY=true in your .env.

What you get

  • Filtered to your targets

    Date posted, experience level, skip-companies blacklist, required keywords, skip keywords, max years required.

  • Smart question answering

    Pattern-based for the 30 common questions, Gemini AI for the weird ones, cached forever after first answer.

  • Dry-run by default

    Fills the form, screenshots it, stops at the Submit button. You audit. You decide. Then flip the flag.

  • Hard 10/day cap

    Below LinkedIn's detection threshold. Can't be bypassed by a config typo — enforced in code.

  • Visible browser

    Chromium opens on your desktop. You see every click. Stop the bot by closing the window — no hidden background process.

  • Full audit log

    Every attempt logged to easy_apply_log: applied / skipped / needs_review / failed, with screenshots for failures.

The algorithm, step by step

Every step lives in core/easy_apply.py. Open it in Notepad to verify — it's ~450 lines of commented Python.

  1. 1

    Navigate to a filtered LinkedIn search

    We build a URL with your target titles, your primary market's cities, and four LinkedIn filters: f_AL=true (Easy Apply only), f_TPR=… (date posted: 24h / 7d / 30d), f_E=… (experience levels you target), sortBy=DD (newest first). Same query a human would type — just typed for you.

  2. 2

    Lazy-scroll until ~25 cards are loaded

    LinkedIn lazy-loads results on scroll. We nudge the left rail 0.9 viewport-heights at a time, 4 times max, with 800ms between scrolls to mimic a human browsing. Never more aggressive than that.

  3. 3

    Deduplicate against your local history

    Every job you've already applied to (or already attempted) is stored in your local easy_apply_log. Cards you've seen before are skipped instantly — no double-applications, ever.

  4. 4

    Apply the description filters

    Open the right-rail. Drop the job if its description contains any EASY_APPLY_SKIP_KEYWORDS (default: us-citizen, security clearance, senior director), if EASY_APPLY_REQUIRED_KEYWORDS are missing, or if a 'X+ years required' line exceeds your EASY_APPLY_MAX_YEARS.

  5. 5

    Click 'Easy Apply'

    Only if a button labeled exactly 'Easy Apply' is visible. We never click any other apply button (we don't auto-fill third-party career sites — too risky).

  6. 6

    Walk the multi-step form

    For each visible input on the modal: read its label, canonicalise it (lowercase + strip punctuation), look up the answer in PATTERNS → cache → AI fallback. Type the answer into the right control (text / select / radio / checkbox / textarea).

  7. 7

    Click 'Next' or 'Review' and repeat

    LinkedIn typically has 2–5 steps. We keep walking until we either see the 'Submit application' button or hit step 12 (hard ceiling — anything beyond that is probably broken).

  8. 8

    (Dry-run by default) Stop at 'Submit'

    On the very first run, EASY_APPLY_DRY_RUN=true. We screenshot the form ready to submit and stop. You audit, then flip the flag once you trust the bot. With dry-run off, we untick 'Follow company' (avoids spam) and click Submit.

  9. 9

    Wait 20–60 seconds. Repeat.

    Random jittered delay between every application. The hard cap (EASY_APPLY_DAILY_CAP, default 10) is checked at the top of each iteration — when it hits, the whole run stops and you get a summary in the dashboard.

How question answering works

Four layers — fastest and most deterministic first, AI last. 99% of questions never reach the AI.

  1. Layer 1

    Pattern map (deterministic)

    30+ regex rules covering 99% of real Easy Apply questions: first/last name, email, phone, years of experience, work authorization, sponsorship, notice period, salary, cover letter, LinkedIn URL, city, country. Lives in core/easy_apply_questions.py — open it in Notepad and you can edit it.

  2. Layer 2

    Q&A cache (per-user, per-question)

    First time we answer 'Do you have a security clearance?' we store the answer locally in easy_apply_answers. Every subsequent form uses the same answer — consistency, no drift, no AI re-rolls.

  3. Layer 3

    Gemini Flash fallback (free tier)

    If we hit a question that doesn't match any pattern and your GEMINI_API_KEY is set, we send only the question text + a short profile blurb to Gemini. System prompt forces a short, plain-text answer. No résumé, no .env, no PII beyond what's already on your LinkedIn.

  4. Layer 4

    'Needs review' fallback

    If both pattern AND AI fail (e.g. AI key missing, or the question is genuinely weird), we screenshot the modal and log the application as needs_review. Your dashboard surfaces it; you finish the application manually in 30 seconds.

Privacy: The AI call goes directly from your laptop to Google AI Studio with your own API key. Never via JobyBots servers. We never see the questions or the answers.

Honest risks (read before opting in)

LinkedIn account restriction

Impact: Moderate

LinkedIn ToS §8.2 prohibits automation. Their detection is fuzzy — most automation users report no issues at <25 apps/day, but some have been temporarily restricted. Our 10/day cap + 20–60s jitter is well below the detection threshold reported by the community, but it is NEVER zero risk.

Wrong-question answers

Impact: Low (dry-run)

When the bot hits a question it has never seen, the AI may guess wrong. The dry-run default means you catch every wrong answer before any application is submitted. Once you've trained the bot for a week of dry-runs, the cache is warm and full-auto is safe.

Over-application

Impact: Low (capped)

The hard daily cap (default 10) is checked before every application. It cannot be bypassed by a config typo because it's enforced in db.easy_applies_today(). The .env value can only LOWER the cap, never raise it past 50.

How to enable it

  1. 1. Set the flag in .env

    ENABLE_EASY_APPLY=true
    EASY_APPLY_DRY_RUN=true     # keep this true for the first week
    EASY_APPLY_DAILY_CAP=10
    LINKEDIN_COOKIE=AQEDAS...   # your li_at cookie
  2. 2. One-time install (~150MB Chromium)

    .venv\Scripts\python.exe -m pip install playwright google-generativeai
    .venv\Scripts\python.exe -m playwright install chromium
  3. 3. Run it (dry-run)

    EASY_APPLY.bat                 # Windows
    mac/EasyApply.command          # Mac

    Chromium opens. Watch the bot fill each form. Screenshots land in data/easyapply_screenshots/.

  4. 4. When you trust it, flip the switch

    # Either: set EASY_APPLY_DRY_RUN=false in .env
    # Or:     run with the --no-dry-run flag
    .venv\Scripts\python.exe jobybot.py easy-apply --no-dry-run

FAQ

Is this legal?+
Easy Apply automation violates LinkedIn's ToS but is not illegal in most jurisdictions. The risk is to your LinkedIn account, not to you legally. We surface this honestly because most competitors don't.
Will my account get banned?+
Bans are rare at our default 10/day cap. Restrictions (a 24-72h pause on job-applications) are slightly more common. If you see a CAPTCHA in the Chromium window, the bot stops automatically.
Can I use my Workspace LinkedIn account?+
Yes. The bot doesn't care about account type. It uses your li_at cookie regardless.
Does the bot follow companies?+
No. We explicitly untick "Follow [Company]" before clicking Submit — it's the #1 LinkedIn spam complaint and doesn't help your application.
What happens if my cookie expires?+
The bot detects the login wall and stops cleanly. Get a fresh cookie from Chrome devtools → Application → Cookies → li_at.
Are you using the GodsScion/Auto_job_applier_linkedIn code?+
No. That project is AGPL-3.0 licensed, which would require us to open-source JobyBots in full. Our Easy Apply module is a clean-room implementation written from scratch based on publicly documented LinkedIn DOM patterns.