API Tutorials

Python asyncio + CaptchaAI: Concurrent Solving at Scale

Sequential CAPTCHA solving caps throughput at one solve per cycle — around 20–30 seconds each. With Python asyncio and aiohttp, you can solve dozens of CAPTCHAs concurrently while keeping resource usage flat.


Prerequisites

pip install aiohttp

Basic async solver

import asyncio
import aiohttp

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
API_KEY = "YOUR_API_KEY"


async def solve_captcha(session, method, params):
    """Submit a CAPTCHA task and poll for the result."""
    data = {
        "key": API_KEY,
        "method": method,
        "json": 1,
        **params
    }

    # Submit
    async with session.post(SUBMIT_URL, data=data) as resp:
        result = await resp.json(content_type=None)

    if result.get("status") != 1:
        raise Exception(f"Submit error: {result.get('error_text', result.get('request'))}")

    task_id = result["request"]

    # Poll
    for _ in range(24):  # 24 * 5s = 120s max
        await asyncio.sleep(5)
        async with session.get(RESULT_URL, params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1
        }) as resp:
            result = await resp.json(content_type=None)

        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise Exception(f"Poll error: {result.get('error_text', result.get('request'))}")

    raise Exception(f"Timeout: task {task_id}")


async def main():
    async with aiohttp.ClientSession() as session:
        token = await solve_captcha(session, "userrecaptcha", {
            "googlekey": "6Le-SITEKEY",
            "pageurl": "https://example.com"
        })
        print(f"Token: {token[:50]}...")


asyncio.run(main())

Expected output:

Token: 03AGdBq26ZfPxL...

Concurrent solving with semaphore

Use asyncio.Semaphore to limit concurrency and prevent rate limit errors:

import asyncio
import aiohttp

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
API_KEY = "YOUR_API_KEY"

MAX_CONCURRENT = 10


async def solve_captcha(session, semaphore, method, params, label=""):
    async with semaphore:
        data = {
            "key": API_KEY,
            "method": method,
            "json": 1,
            **params
        }

        async with session.post(SUBMIT_URL, data=data) as resp:
            result = await resp.json(content_type=None)

        if result.get("status") != 1:
            error = result.get("error_text", result.get("request"))
            print(f"[{label}] Submit failed: {error}")
            return None

        task_id = result["request"]
        print(f"[{label}] Submitted: {task_id}")

        for _ in range(24):
            await asyncio.sleep(5)
            async with session.get(RESULT_URL, params={
                "key": API_KEY,
                "action": "get",
                "id": task_id,
                "json": 1
            }) as resp:
                result = await resp.json(content_type=None)

            if result.get("status") == 1:
                print(f"[{label}] Solved: {result['request'][:40]}...")
                return result["request"]
            if result.get("request") != "CAPCHA_NOT_READY":
                print(f"[{label}] Error: {result.get('error_text', result.get('request'))}")
                return None

        print(f"[{label}] Timeout")
        return None


async def main():
    semaphore = asyncio.Semaphore(MAX_CONCURRENT)

    # 20 tasks — only 10 run concurrently
    tasks_params = [
        {"googlekey": f"6Le-SITEKEY-{i}", "pageurl": f"https://example.com/page/{i}"}
        for i in range(20)
    ]

    async with aiohttp.ClientSession() as session:
        tasks = [
            solve_captcha(session, semaphore, "userrecaptcha", params, label=f"task-{i}")
            for i, params in enumerate(tasks_params)
        ]

        results = await asyncio.gather(*tasks, return_exceptions=True)

    solved = [r for r in results if r and not isinstance(r, Exception)]
    failed = len(results) - len(solved)
    print(f"\nResults: {len(solved)} solved, {failed} failed")


asyncio.run(main())

Expected output:

[task-0] Submitted: 72345678901
[task-1] Submitted: 72345678902
...
[task-0] Solved: 03AGdBq26ZfPxL...
[task-1] Solved: 03AGdBq27AbCdE...
...
Results: 18 solved, 2 failed

Mixed CAPTCHA types

Solve different CAPTCHA types in the same batch:

async def solve_mixed_batch(session, semaphore):
    tasks = [
        solve_captcha(session, semaphore, "userrecaptcha", {
            "googlekey": "6Le-SITEKEY-A",
            "pageurl": "https://site-a.com"
        }, label="recaptcha-1"),

        solve_captcha(session, semaphore, "turnstile", {
            "sitekey": "0x4AAAA-SITEKEY-B",
            "pageurl": "https://site-b.com"
        }, label="turnstile-1"),

        solve_captcha(session, semaphore, "userrecaptcha", {
            "googlekey": "6Le-SITEKEY-C",
            "pageurl": "https://site-c.com"
        }, label="recaptcha-2"),
    ]

    return await asyncio.gather(*tasks, return_exceptions=True)

Error handling patterns

Retry with backoff

async def solve_with_retry(session, semaphore, method, params, max_retries=2):
    for attempt in range(max_retries + 1):
        try:
            return await solve_captcha(session, semaphore, method, params,
                                        label=f"attempt-{attempt}")
        except Exception as e:
            if "ERROR_ZERO_BALANCE" in str(e):
                raise  # Don't retry permanent errors
            if attempt < max_retries:
                wait = 2 ** attempt
                print(f"Retry in {wait}s: {e}")
                await asyncio.sleep(wait)
            else:
                raise

Collect results with error tracking

async def solve_batch_with_tracking(session, semaphore, task_list):
    results = {"solved": [], "failed": [], "errors": []}

    async def tracked_solve(task_params, index):
        try:
            token = await solve_captcha(session, semaphore,
                                         task_params["method"],
                                         task_params["params"],
                                         label=f"task-{index}")
            if token:
                results["solved"].append({"index": index, "token": token})
            else:
                results["failed"].append(index)
        except Exception as e:
            results["errors"].append({"index": index, "error": str(e)})

    tasks = [tracked_solve(t, i) for i, t in enumerate(task_list)]
    await asyncio.gather(*tasks)

    return results

Performance tuning

Parameter Default Recommended Notes
MAX_CONCURRENT 10 5–20 Start low, increase based on error rate
Poll interval 5s 5s Don't go below 3s
Max poll attempts 24 24 (120s) Increase for complex types
Connection pool aiohttp default 100 aiohttp.TCPConnector(limit=100)
Timeout per request None 15s aiohttp.ClientTimeout(total=15)

Optimized connector

connector = aiohttp.TCPConnector(limit=100, keepalive_timeout=30)
timeout = aiohttp.ClientTimeout(total=15)

async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
    # Use session for all solves
    pass

Troubleshooting

Problem Cause Fix
ERROR_NO_SLOT_AVAILABLE Too many concurrent submits Lower MAX_CONCURRENT
ClientConnectorError DNS or network issue Check connectivity, add retry
All tasks timeout API under load Increase poll timeout to 180s
RuntimeError: Event loop closed Wrong asyncio usage on Windows Use asyncio.run() or WindowsSelectorEventLoopPolicy

FAQ

How many concurrent tasks should I run?

Start with 10. Monitor for ERROR_NO_SLOT_AVAILABLE and adjust. Most accounts support 20+ concurrent tasks.

Does asyncio use multiple CPU cores?

No. asyncio is single-threaded — it handles I/O concurrency, not CPU parallelism. For CAPTCHA solving, the bottleneck is network I/O, so asyncio is ideal.

Can I cancel in-progress tasks?

Yes. Use task.cancel() on any asyncio task. The pending API requests will be abandoned, but CaptchaAI will still process them (you'll be charged).


Start solving CAPTCHAs concurrently with CaptchaAI

Get your API key at captchaai.com.


Discussions (0)

No comments yet.

Related Posts

Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
Tutorials Pytest Fixtures for CaptchaAI API Testing
Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI.

Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI. Covers mocking, live integra...

Automation Python reCAPTCHA v2
Apr 08, 2026
Reference Browser Session Persistence for CAPTCHA Workflows
Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and maintain authenticated state.

Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and main...

Automation Python reCAPTCHA v2
Feb 24, 2026
Integrations Browser Profile Isolation + CaptchaAI Integration
Browser profile isolation tools create distinct browser environments with unique fingerprints per session.

Browser profile isolation tools create distinct browser environments with unique fingerprints per session. Com...

Automation Python reCAPTCHA v2
Feb 21, 2026
Comparisons WebDriver vs Chrome DevTools Protocol for CAPTCHA Automation
Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabilities, and when to use each with Captcha AI.

Compare Web Driver and Chrome Dev Tools Protocol (CDP) for CAPTCHA automation — detection, performance, capabi...

Automation Python reCAPTCHA v2
Mar 27, 2026
Use Cases CAPTCHA Solving in Ticket Purchase Automation
How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automated purchasing workflows.

How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automate...

Automation Python reCAPTCHA v2
Feb 25, 2026
Use Cases Event Ticket Monitoring with CAPTCHA Handling
Build an event ticket availability monitor that handles CAPTCHAs using Captcha AI.

Build an event ticket availability monitor that handles CAPTCHAs using Captcha AI. Python workflow for checkin...

Automation Python reCAPTCHA v2
Jan 17, 2026
Tutorials Caching CAPTCHA Tokens for Reuse
Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs.

Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs. Covers token lifetimes, cache st...

Automation Python reCAPTCHA v2
Feb 15, 2026
Tutorials CAPTCHA Retry Queue with Exponential Backoff
Implement a retry queue with exponential backoff for Captcha AI API calls.

Implement a retry queue with exponential backoff for Captcha AI API calls. Handles transient failures, rate li...

Automation Python reCAPTCHA v2
Feb 15, 2026
API Tutorials How to Solve reCAPTCHA v2 Callback Using API
how to solve re CAPTCHA v 2 callback implementations using Captcha AI API.

Learn how to solve re CAPTCHA v 2 callback implementations using Captcha AI API. Detect the callback function,...

Automation reCAPTCHA v2 Webhooks
Mar 01, 2026
API Tutorials Solve GeeTest v3 CAPTCHA with Python and CaptchaAI
Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API.

Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API. Includes...

Automation Python Testing
Mar 23, 2026
API Tutorials Case-Sensitive CAPTCHA API Parameter Guide
How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI.

How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI. Covers when to use, comm...

Python Web Scraping Image OCR
Apr 09, 2026