Skip to content

Auto-Apply: solve Lever CAPTCHA puzzle (currently disabled) #36

Description

@Mayank-glitch-cpu

Summary

Lever postings (*.lever.co) gate application submission behind a human-verification CAPTCHA (FriendlyCaptcha / hCaptcha-style "puzzle") that the headless Playwright agent cannot clear. Auto-Apply is therefore disabled for Lever for now:

  • Frontend (dashboard/src/components/Pipeline.tsx) — the Auto-Apply button is hidden for lever.co links and replaced with an "apply via Open" note (isLever()).
  • Backend (mcp-server/src/api/dashboard.ts) — POST /api/runs with agent: auto-apply rejects Lever links with HTTP 422 (detectAts(applyLink) === "lever").

Greenhouse and other ATSes keep Auto-Apply; their CAPTCHA / emailed-code gates already hand off to the user (needsCaptcha → open-apply notice, needsEmailCode → in-console code input).

Why it is hard

Lever embeds a proof-of-work / image CAPTCHA that:

  • renders in a sandboxed iframe (FriendlyCaptcha widget / hCaptcha) whose token must be present before the submit button posts;
  • is scored against headless + automation signals, so even when the widget is "solved" the token can be rejected;
  • its overlay intercepts the submit click, so the current clickSubmit() path times out.

Existing detection (detectCaptcha() in mcp-server/src/lib/browser-apply.ts) already recognises hCaptcha/reCAPTCHA/Turnstile iframes and bails with needsCaptcha; Lever needs to get past it, not just detect it.

How to solve it (proposed approaches, easiest to hardest)

  1. Human-in-the-loop handoff (ship first). Treat Lever like the existing needsCaptcha path but make it first-class: fill every field as a dry run, then surface the live session to the user to solve the puzzle and click Submit themselves. Requires a non-headless / streamable session (or a remote browser the user can drive) rather than tearing down on detection. Lowest risk, no ToS issues.
  2. Token-solving service. Integrate a CAPTCHA-solving provider such as 2Captcha, CapMonster, or Anti-Captcha — submit the sitekey plus page URL, receive a token, inject it into the widget's response field, then submit. Adds a paid dependency and a per-provider adapter; verify it actually covers FriendlyCaptcha (Lever's current widget), not just hCaptcha.
  3. Reduce bot signals. Run a non-headless Chromium (Xvfb in the container), use playwright-extra plus the stealth plugin, a residential proxy, and realistic timing so FriendlyCaptcha's proof-of-work passes without a challenge. Fragile and an arms race.

Recommended

Start with option 1 — wire Lever into the same review-then-handoff flow, but stream the live browser (the console already polls GET /api/runs/:id/live screenshots) and add an "I solved it — submit" action that calls clickSubmit() on the open session. Then evaluate option 2 for true autonomy.

Acceptance criteria

  • A Lever application can be filled by the agent and submitted after the user clears the CAPTCHA (handoff path), or autonomously via a solving service.
  • On confirmed submit the pipeline job is marked applied (reuse markApplied).
  • Re-enable Auto-Apply for Lever in Pipeline.tsx (isLever) and remove the 422 guard in dashboard.ts.

Related code

  • detectCaptcha, clickSubmit, fillAndSubmitmcp-server/src/lib/browser-apply.ts
  • needsCaptcha / needsEmailCode propagation — mcp-server/src/lib/agent/auto-apply-agent.ts, mcp-server/src/api/dashboard.ts
  • Console UI (captcha/code handling) — dashboard/src/components/Agents.tsx

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions