same-session recovery

CAPTCHA blocks a Browser Use task.
Keep the run.

A task may already have logged in, navigated several pages, and filled a form when verification appears. Restarting throws that context away. A safer boundary pauses the current Agent, keeps its BrowserSession, waits for authorized human action, and resumes only after fresh page evidence says the gate is gone.

01 / failure mode

A click is not a result.

The hard part is not noticing a widget. It is deciding when the original task may continue. A person returning control, a checkbox animation, or a callback saying “done” can all arrive while the page is still blocked—or after the browser has been replaced.

InvariantThe same task continues only when the current browser session produces a new clear or passed observation.

02 / recovery boundary

Pause. Hand off. Re-read. Resume.

  1. DetectInspect uncached URL, DOM, frame, text, and runtime evidence before the next agent step.
  2. PauseStop Browser Use from taking another step while leaving its existing browser available.
  3. Hand offNotify a person for an unknown or production challenge. Keep the task and browser identity with the request.
  4. VerifyAfter the wake-up, re-read the current page. If the browser changed or the gate remains, fail closed.
  5. ResumeReturn control once, only after fresh evidence clears the current challenge.

03 / install and attach

Borrow the Agent's session.

Install the version-pinned release wheel with the supported Browser Use adapter:

python -m pip install 'rea-captcha[browser-use] @ https://github.com/masakaai/rea-captcha/releases/download/v0.3.1/rea_captcha-0.3.1-py3-none-any.whl'

Attach the guard to the Agent that already owns the browser:

from browser_use import Agent
from rea_captcha import ChallengePlugin

agent = Agent(task="Complete the authorized workflow", llm=llm)

async def notify_human(finding, _agent):
    print(f"Action needed for {finding.kind} at {finding.url}")

challenge = ChallengePlugin(
    human_handoff=True,
    timeout=15 * 60,
    on_handoff=notify_human,
)
await challenge.attach(agent)

try:
    await agent.run()
finally:
    await challenge.detach()

The plugin borrows the current BrowserSession. It does not launch, replace, or close the browser, and its bounded human wait does not silently turn a timeout into success.

04 / fresh evidence

“Done” only wakes the guard.

After human action, the adapter requests a new Browser Use state summary and re-reads the current page before returning. If the detector is unavailable, the observation is malformed, the browser identity changed, or challenge evidence is still active, the task stays paused.

unsafehuman_done → resume
requiredhuman_done → re-read the current page → fresh clear evidence → resume

For an application that needs delayed-callback protection, bind the handoff to the task, tab/session, and challenge generation. A newer handoff makes an older callback stale, and an accepted resume identity is consumed once.

05 / choose the level

Use the smallest contract that is safe.

Python ChallengePlugin

Best when a person can complete the current Browser Use page and fresh page reinspection is enough. It provides pause, bounded wait, and same-session detection.

Stateful SDK or MCP controller

Use when you need task/tab/generation binding, one-shot resume, an authorized provider-test action, or an explicit server validation boundary.

CI installs the supported Browser Use dependency and exercises the adapter against real Agent and BrowserSession pause/resume APIs. Review the contract test and the full integration guide.

06 / scope

Recovery, not generic bypass.

Automatic actions are limited to official provider test credentials or explicitly authorized owned origins. Unknown and production third-party challenges remain human work. rea-captcha does not transfer cookies, provide a hosted solver, promise stealth, or treat OCR output as proof that a protected action succeeded.

Keep a Browser Use task alive through verification.Source, tests, examples, and the complete tool contract are public.
open GitHub ↗