CAPTCHA Handling
Learn about Headless Browser CAPTCHA detection and handling mechanisms and how to use them.
By default, Oxylabs Headless Browser does not handle CAPTCHAs automatically. To enable automatic detection and handling as soon as a page loads, add solve_captcha=true to your connection URL.
If a target site displays challenges dynamically during multi-step interactions, or if you require advanced event monitoring and speed optimizations, you can use the parameters, events, and techniques documented below.
Monitoring CAPTCHA events
You can monitor the solver's lifecycle. The internal oxylabs-runtime browser extension broadcasts status events directly to the browser's window object. By registering a custom "message" event listener, your script can trace these events to pause and resume actions.
oxylabs-captcha-start
Solver has detected a CAPTCHA and initiated the handling process.
oxylabs-captcha-end
Solver completed successfully and handled the challenge.
oxylabs-captcha-solve-end
Alternate completion event emitted after success.
oxylabs-captcha-error
Solver failed to handle the challenge.
Code examples
These examples show how to inject an init script to capture runtime CAPTCHA events before page navigation so your script pauses during active handling.
from playwright.sync_api import sync_playwright
username = "USERNAME_abc12"
password = "PASSWORD"
endpoint = "hb.oxylabs.io"
# solve_captcha=true enables handling and event emission (off by default)
browser_url = f"wss://{username}:{password}@{endpoint}?solve_captcha=true"
def run():
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(browser_url)
ctx = browser.contexts[0]
page = ctx.new_page()
# Inject listener BEFORE navigation
ctx.add_init_script("""
window.addEventListener("message", (event) => {
if (event.data && event.data.source === "oxylabs-runtime") {
window.__extensionStatus = event.data.type;
}
});
""")
page.goto("https://example.com/captcha-page", wait_until="domcontentloaded")
# Wait for solver to complete (polls status flag)
page.wait_for_function(
"""() => {
const status = window.__extensionStatus;
if (status === "oxylabs-captcha-error") {
throw new Error("CAPTCHA solving failed");
}
return status === "oxylabs-captcha-solve-end" || status === "oxylabs-captcha-end";
}""",
timeout=60000
)
print("CAPTCHA solved. Resuming automation...")
browser.close()
if __name__ == "__main__":
run()Dynamic manual triggers
Some targets only display CAPTCHA challenges following user actions (e.g., after clicking an interactive form submission button or performing dynamic scrolling).
You can trigger the Headless Browser's CAPTCHA handler programmatically at any point in your session using window.postMessage event directly to the window object:
Standard trigger pattern
For typical elements, trigger the solver immediately after executing the user action:
Speed optimization
Handling CAPTCHAs adds mechanical execution latency. When scraping targets that enforce repetitive CAPTCHA gates, consider these methods for better performance:
Reuse sessions
Once a remote browser session completes a CAPTCHA on a domain, the verification is saved. Navigate repeatedly or perform additional page steps within the same browser session without re-triggering challenge solving routines.
Multi-tab
Instead separate WebSocket connections (which launch distinct sandboxes with empty cookie pools), execute concurrent tasks by opening multiple tabs or contexts inside your existing session, to reduce connection and verification time across all pages.
Enable selectively
Since solve_captcha is off by default, only enable it (solve_captcha=true) for the specific connections that need it, rather than leaving it on for an entire workflow — this avoids solver initialization latency on pages or sessions that don't face CAPTCHA challenges.
Last updated
Was this helpful?

