Skip to main content

CAPTCHA Solving

CAPTCHAs blocking your automation? We handle them for you. Surfsky comes with built-in solving that works with all major CAPTCHA types.

We use a combination of third-party services and our own internal CAPTCHA solvers to provide the best success rates. You can choose to use all available solvers or limit to internal ones only based on your needs.

Better yet - our fingerprinting often prevents CAPTCHAs from appearing at all. But when they do show up, you've got options.

Two Ways to Win

Prevention First: Good fingerprinting = fewer CAPTCHAs
Smart Solving: When they appear, we solve them fast

Getting too many? Check troubleshooting below or contact support.

Supported CAPTCHAs

  • Google reCAPTCHA (v2, v3, Enterprise)
  • hCaptcha
  • Cloudflare Turnstile
  • DataDome
  • PerimeterX
  • GeeTest
  • Amazon WAF
  • Tencent
  • FaucetPay
  • Imperva
  • Prosopo
  • Temu
  • Yidun
  • MTCaptcha
  • BLS
  • Click CAPTCHA
  • Image CAPTCHA
  • Text CAPTCHA

Need something else? Let us know - we add new types regularly.

Two Solving Modes

Manual Mode

You control when to solve:

  1. Your code detects a CAPTCHA
  2. You call Captcha.solve()
  3. We solve it and return the result
  4. Perfect for known CAPTCHA locations

Auto Mode

We handle everything:

  1. Call Captcha.autoSolve() once
  2. Browser monitors for CAPTCHAs
  3. Solves them automatically
  4. Fires events to keep you informed
  5. Great for unpredictable CAPTCHAs
Beta Status

Working well but still improving. Test with your specific sites.

Quick Start

Setup

  1. Enable anti_captcha in your browser profile settings
  2. Choose manual or auto mode based on your needs
  3. Run your automation

Code Examples

Manual Solving

import asyncio
from playwright.async_api import async_playwright

async def solve_captcha_manually():
async with async_playwright() as p:
# Connect to your Surfsky browser
browser = await p.chromium.connect_over_cdp("ws://your-browser-url")
page = await browser.new_page()

# Create CDP session for captcha commands
client = await page.context.new_cdp_session(page)

# Navigate to page with CAPTCHA
await page.goto("https://example.com/login")

# Wait for CAPTCHA to appear (adjust selector as needed)
await page.wait_for_selector(".g-recaptcha", timeout=5000)

print("CAPTCHA detected, solving...")

# Solve with specific type
response = await client.send("Captcha.solve", {"type": "recaptcha"})

# Or let us auto-detect the type
# response = await client.send("Captcha.solve")

if response.get("status") == "success":
print("✓ CAPTCHA solved!")
# Continue with your automation
await page.click("#submit-button")
else:
print("✗ Failed to solve CAPTCHA")

# Run it
asyncio.run(solve_captcha_manually())

Auto Solving

import asyncio
from playwright.async_api import async_playwright

async def solve_captcha_auto():
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp("ws://your-browser-url")
page = await browser.new_page()
client = await page.context.new_cdp_session(page)

# Start auto-solving for all CAPTCHA types
await client.send("Captcha.autoSolve")

# Or target specific type only
# await client.send("Captcha.autoSolve", {"type": "turnstile"})

print("Auto-solve activated, navigating...")

# Navigate - CAPTCHAs will be solved automatically
await page.goto("https://example.com/protected-page")

# Your automation continues normally
# Browser handles any CAPTCHAs in the background

asyncio.run(solve_captcha_auto())

With Event Listeners

import asyncio
from contextlib import suppress
from playwright.async_api import async_playwright

async def solve_with_events():
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp("ws://your-browser-url")
page = await browser.new_page()
client = await page.context.new_cdp_session(page)

# Event to track solving completion
captcha_done = asyncio.Event()
results = {}

# Handle CAPTCHA events
async def handle_captcha_event(data):
event_type = data['type']
detail = data.get('detail', {})

print(f"[{event_type}] {detail}")

if event_type == "Captcha.solveStarted":
print(f"🔄 Solving {detail.get('type')} CAPTCHA...")
elif event_type == "Captcha.solveCompleted":
print(f"✓ CAPTCHA solved successfully!")
results['success'] = True
captcha_done.set()
elif event_type == "Captcha.solveFailed":
print(f"✗ Failed to solve: {detail.get('error')}")
results['success'] = False
captcha_done.set()

# Register event handler
await page.expose_function("captchaEventHandler", handle_captcha_event)

# Listen for CAPTCHA events
await page.evaluate("""
['solveStarted', 'solveCompleted', 'solveFailed'].forEach(eventName => {
window.addEventListener('Captcha.' + eventName, async (event) => {
await window.captchaEventHandler({
type: 'Captcha.' + eventName,
detail: event.detail || {}
});
});
});
""")

# Navigate to page
await page.goto("https://2captcha.com/demo/recaptcha-v2")

# Trigger manual solve
print("Triggering CAPTCHA solve...")
client.send("Captcha.solve", {"type": "recaptcha"})

# Wait for completion (with timeout)
with suppress(asyncio.TimeoutError):
await asyncio.wait_for(captcha_done.wait(), timeout=60)

if results.get('success'):
print("Proceeding with automation...")
# Continue your flow
else:
print("CAPTCHA solving failed, retrying...")

asyncio.run(solve_with_events())

Best Practices

Choose the Right Mode

Use Manual Mode when:

  • You know exactly where CAPTCHAs appear
  • You need precise control over timing
  • Testing specific CAPTCHA types

Use Auto Mode when:

  • CAPTCHAs appear unpredictably
  • Multiple CAPTCHAs on same page
  • You want "set and forget" solving

Handle Timeouts Properly

# Good: Realistic timeouts with retry
try:
response = await client.send("Captcha.solve", {"type": "recaptcha"})
if response.get("status") != "success":
# Retry once
response = await client.send("Captcha.solve", {"type": "recaptcha"})
except TimeoutError:
print("CAPTCHA solving timed out")

Monitor Events

Always listen for events in production:

  • Captcha.solveStarted - Solving began
  • Captcha.solveCompleted - Success!
  • Captcha.solveFailed - Something went wrong

Troubleshooting

Too Many CAPTCHAs?

Quick Fixes:

  1. Better Proxies - Residential > Datacenter
  2. Slow Down - Add N second delays between actions
  3. Act Human - Use Human Emulation for natural behavior
  4. Reuse Profiles - Persistent profiles that passed CAPTCHAs have trusted cookies & higher limits

Use Human Emulation to Prevent CAPTCHAs:

Instead of robotic Playwright/Puppeteer actions, use our Human Emulation CDP commands for natural behavior:

# ❌ Robotic - triggers CAPTCHAs
await page.click("#login")
await page.type("#username", "[email protected]")

# ✅ Human-like - avoids detection
client = await page.context.new_cdp_session(page)
await client.send("Human.click", {"selector": "#login"})
await client.send("Human.type", {"text": "[email protected]"})

Natural mouse movements, realistic typing speeds, and smooth scrolling make sites treat you like a real user. See Human Emulation docs for full API.

Common Issues

"Captcha solver not enabled"

  • Enable anti_captcha in profile settings
  • Start browser after enabling

"No captcha detected"

  • Check if page fully loaded
  • Try manual mode with specific type
  • Verify CAPTCHA is visible (not hidden)

Solving takes forever

  • Normal for complex CAPTCHAs (up to 60s)
  • Check your API credits
  • Try different proxy

Third-party solvers failing?

  • Use internal solvers only by setting disable_external_providers: true:
{
"anti_captcha": {
"enabled": true,
"disable_external_providers": true
}
}

This disables third-party services and uses only our internal solving methods, which may provide better results for certain CAPTCHA implementations.

API Reference

CDP Commands

Captcha.solve

Manually solve a CAPTCHA on the current page.

Parameters:

  • type (optional) - CAPTCHA type. Supported values:
    • recaptcha - Google reCAPTCHA (v2, v3, Enterprise)
    • hcaptcha - hCaptcha
    • turnstile - Cloudflare Turnstile
    • datadome - DataDome
    • perimeterx - PerimeterX
    • geetest - GeeTest
    • bls - BLS CAPTCHA
    • funcaptcha - FunCaptcha
    • click - Click-based CAPTCHAs
    • image - Image CAPTCHAs
  • options (optional) - Solving options object:
    • selector - CSS selector or [x, y] coordinates for click CAPTCHAs
    • proxy - Proxy URL for captcha solving
  • timeout (optional) - Max time to wait in milliseconds

Returns:

  • status - success, failed, or timeout
  • type - Detected CAPTCHA type
  • solution (for image CAPTCHAs) - Text solution

Captcha.autoSolve

Enable automatic CAPTCHA detection and solving.

Parameters:

  • type (optional) - Only solve specific CAPTCHA type (same values as Captcha.solve)
  • options (optional) - Solving options object:
    • selector - CSS selector or [x, y] coordinates for click CAPTCHAs
    • proxy - Proxy URL for captcha solving

Returns:

  • status - started

Events

All events are dispatched on the window object:

  • Captcha.detectionStarted - Looking for CAPTCHAs
  • Captcha.detectionCompleted - Found (or not found) CAPTCHA
  • Captcha.solveStarted - Solving started
  • Captcha.solveCompleted - Successfully solved
  • Captcha.solveFailed - Solving failed

Need Help?

Questions? Issues? Contact us: