API Tutorials

Semaphore Patterns for CAPTCHA Concurrency Control

Sending 100 CAPTCHA tasks simultaneously sounds fast — until you hit rate limits. Semaphores let you cap the number of concurrent API calls to a safe level while keeping throughput high. This guide covers semaphore patterns for controlling CaptchaAI concurrency in Python and Node.js.


Why semaphores

Without semaphore With semaphore
100 simultaneous requests 20 at a time
429 rate limit errors No rate limit errors
Unpredictable timing Steady throughput
Memory spikes Controlled resource usage

A semaphore is a counter that limits how many tasks can run at the same time. When a task acquires the semaphore, the count decreases. When it finishes, the count increases. If the count is zero, new tasks wait.


Python: asyncio.Semaphore

Basic pattern

import asyncio
import aiohttp

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


async def solve_one(session, sem, sitekey, page_url):
    """Solve one CAPTCHA within the semaphore limit."""
    async with sem:
        # Submit
        async with session.post(SUBMIT_URL, data={
            "key": API_KEY,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url,
            "json": "1",
        }) as resp:
            data = await resp.json()

        if data["status"] != 1:
            return {"url": page_url, "error": data["request"]}

        task_id = data["request"]

        # Poll (still within semaphore)
        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()

            if result["status"] == 1:
                return {"url": page_url, "token": result["request"]}
            if result["request"] != "CAPCHA_NOT_READY":
                return {"url": page_url, "error": result["request"]}

        return {"url": page_url, "error": "TIMEOUT"}


async def solve_batch(tasks, max_concurrent=20):
    sem = asyncio.Semaphore(max_concurrent)

    async with aiohttp.ClientSession() as session:
        coros = [
            solve_one(session, sem, t["sitekey"], t["url"])
            for t in tasks
        ]
        results = await asyncio.gather(*coros)

    solved = sum(1 for r in results if "token" in r)
    print(f"Solved {solved}/{len(results)}")
    return results

Split submit and poll semaphores

Submitting is fast (< 1s). Polling takes 15-60s. Using separate semaphores lets you submit faster:

async def solve_split_sems(session, submit_sem, poll_sem, sitekey, page_url):
    # Submit phase — short, limited to 30 concurrent
    async with submit_sem:
        async with session.post(SUBMIT_URL, data={
            "key": API_KEY,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url,
            "json": "1",
        }) as resp:
            data = await resp.json()

    if data["status"] != 1:
        return {"error": data["request"]}

    task_id = data["request"]

    # Poll phase — longer, limited to 50 concurrent
    async with poll_sem:
        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()

            if result["status"] == 1:
                return {"token": result["request"]}
            if result["request"] != "CAPCHA_NOT_READY":
                return {"error": result["request"]}

    return {"error": "TIMEOUT"}


async def main(tasks):
    submit_sem = asyncio.Semaphore(30)  # 30 concurrent submits
    poll_sem = asyncio.Semaphore(50)     # 50 concurrent polls

    async with aiohttp.ClientSession() as session:
        coros = [
            solve_split_sems(session, submit_sem, poll_sem, t["sitekey"], t["url"])
            for t in tasks
        ]
        return await asyncio.gather(*coros)

Node.js: Custom semaphore

Node.js doesn't have a built-in semaphore, but it's simple to build:

class Semaphore {
  constructor(max) {
    this.max = max;
    this.current = 0;
    this.queue = [];
  }

  acquire() {
    return new Promise(resolve => {
      if (this.current < this.max) {
        this.current++;
        resolve();
      } else {
        this.queue.push(resolve);
      }
    });
  }

  release() {
    this.current--;
    if (this.queue.length > 0) {
      this.current++;
      const next = this.queue.shift();
      next();
    }
  }
}

Using the semaphore

const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';
const sem = new Semaphore(20);

async function solveOne(sitekey, pageUrl) {
  await sem.acquire();
  try {
    const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
      params: {
        key: API_KEY,
        method: 'userrecaptcha',
        googlekey: sitekey,
        pageurl: pageUrl,
        json: 1,
      },
    });

    if (submit.data.status !== 1) {
      return { url: pageUrl, error: submit.data.request };
    }

    const taskId = submit.data.request;

    for (let i = 0; i < 24; i++) {
      await new Promise(r => setTimeout(r, 5000));
      const poll = await axios.get('https://ocr.captchaai.com/res.php', {
        params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
      });

      if (poll.data.status === 1) {
        return { url: pageUrl, token: poll.data.request };
      }
      if (poll.data.request !== 'CAPCHA_NOT_READY') {
        return { url: pageUrl, error: poll.data.request };
      }
    }
    return { url: pageUrl, error: 'TIMEOUT' };
  } finally {
    sem.release();
  }
}

// Solve 100 tasks with max 20 concurrent
async function solveBatch(tasks) {
  const results = await Promise.all(
    tasks.map(t => solveOne(t.sitekey, t.url))
  );
  const solved = results.filter(r => r.token).length;
  console.log(`Solved: ${solved}/${results.length}`);
  return results;
}

Adaptive semaphore

Adjust concurrency based on error rates:

class AdaptiveSemaphore:
    def __init__(self, initial=20, min_val=5, max_val=50):
        self.value = initial
        self.min_val = min_val
        self.max_val = max_val
        self.sem = asyncio.Semaphore(initial)
        self.success_count = 0
        self.error_count = 0

    async def acquire(self):
        await self.sem.acquire()

    def release(self, success=True):
        self.sem.release()
        if success:
            self.success_count += 1
        else:
            self.error_count += 1

        total = self.success_count + self.error_count
        if total % 20 == 0:
            self._adjust()

    def _adjust(self):
        error_rate = self.error_count / (self.success_count + self.error_count)

        if error_rate > 0.2 and self.value > self.min_val:
            self.value = max(self.min_val, self.value - 5)
            self.sem = asyncio.Semaphore(self.value)
            print(f"Reduced concurrency to {self.value}")
        elif error_rate < 0.05 and self.value < self.max_val:
            self.value = min(self.max_val, self.value + 5)
            self.sem = asyncio.Semaphore(self.value)
            print(f"Increased concurrency to {self.value}")

        self.success_count = 0
        self.error_count = 0

Troubleshooting

Problem Cause Fix
All tasks blocked Semaphore never released Use try/finally to always release
Still getting 429s Semaphore too high Reduce max concurrent value
Too slow Semaphore too low Increase value or split submit/poll
Memory growing Tasks queued forever Set a timeout on acquire()

FAQ

What concurrency level should I use?

Start with 20 concurrent tasks. If you see no 429 errors, increase to 30-50. If you see errors, reduce to 10-15.

Should I limit submits or polls?

Limit submits more aggressively. Polls are lightweight GET requests and can run at higher concurrency.


Scale your CAPTCHA solving with CaptchaAI

Get your API key at captchaai.com.


Discussions (0)

No comments yet.

Related Posts

Reference CAPTCHA Solving Performance by Region: Latency Analysis
Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimization strategies for global deployments.

Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimizati...

Automation Python All CAPTCHA Types
Apr 05, 2026
Explainers Rate Limiting CAPTCHA Solving Workflows
Sending too many requests too fast triggers blocks, bans, and wasted CAPTCHA solves.

Sending too many requests too fast triggers blocks, bans, and wasted CAPTCHA solves. Smart rate limiting keeps...

Automation Python All CAPTCHA Types
Apr 04, 2026
DevOps & Scaling Horizontal Scaling CAPTCHA Solving Workers: When and How
Scale CAPTCHA solving horizontally — identify bottlenecks, add workers dynamically, auto-scale based on queue depth, and manage costs with Captcha AI.

Scale CAPTCHA solving horizontally — identify bottlenecks, add workers dynamically, auto-scale based on queue...

Automation Python All CAPTCHA Types
Mar 07, 2026
Explainers DNS Resolution Impact on CAPTCHA API Performance
Understand how DNS resolution affects CAPTCHA API call latency and to optimize with DNS caching, pre-resolution, and DNS-over-HTTPS.

Understand how DNS resolution affects CAPTCHA API call latency and learn to optimize with DNS caching, pre-res...

Automation Python All CAPTCHA Types
Apr 03, 2026
Troubleshooting CaptchaAI API Rate Limiting: Handling 429 Responses
Handle Captcha AI API rate limits and 429 responses.

Handle Captcha AI API rate limits and 429 responses. Implement exponential backoff, request throttling, and qu...

Automation Python All CAPTCHA Types
Apr 01, 2026
DevOps & Scaling Auto-Scaling CAPTCHA Solving Workers
Build auto-scaling CAPTCHA solving workers that adjust capacity based on queue depth, balance, and solve rates.

Build auto-scaling CAPTCHA solving workers that adjust capacity based on queue depth, balance, and solve rates...

Automation Python All CAPTCHA Types
Mar 23, 2026
Tutorials CAPTCHA Solving Throughput: How to Process 10,000 Tasks per Hour
Architect a CAPTCHA solving pipeline that processes 10,000 tasks per hour using Captcha AI with async Python, connection pooling, and queue-based distribution.

Architect a CAPTCHA solving pipeline that processes 10,000 tasks per hour using Captcha AI with async Python,...

Automation Python All CAPTCHA Types
Mar 13, 2026
Tutorials Rate-Limited Concurrency: Token Bucket for CAPTCHA API Calls
Implement a token bucket rate limiter for CAPTCHA API calls — control request rates, prevent throttling, and manage Captcha AI API consumption budgets.

Implement a token bucket rate limiter for CAPTCHA API calls — control request rates, prevent throttling, and m...

Automation Python All CAPTCHA Types
Feb 26, 2026
Tutorials Rate Limiting Your Own CAPTCHA Solving Requests
Implement client-side rate limiting for Captcha AI API calls — token bucket, sliding window, and per-key limits to prevent overuse and control costs.

Implement client-side rate limiting for Captcha AI API calls — token bucket, sliding window, and per-key limit...

Automation Python All CAPTCHA Types
Feb 26, 2026
Troubleshooting CAPTCHA Solve Rate Drops: Performance Regression Diagnosis
Diagnose sudden drops in CAPTCHA solve rates — identify whether the issue is your code, proxy, target site changes, or Captcha AI service conditions.

Diagnose sudden drops in CAPTCHA solve rates — identify whether the issue is your code, proxy, target site cha...

Automation Python All CAPTCHA Types
Feb 17, 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
API Tutorials How to Solve reCAPTCHA v2 Enterprise with Python
Solve re CAPTCHA v 2 Enterprise using Python and Captcha AI API.

Solve re CAPTCHA v 2 Enterprise using Python and Captcha AI API. Complete guide with sitekey extraction, task...

Automation Python reCAPTCHA v2
Apr 08, 2026
API Tutorials Solving CAPTCHAs with Kotlin and CaptchaAI API
Complete guide to solving re CAPTCHA, Turnstile, and image CAPTCHAs in Kotlin using Captcha AI's HTTP API with Ok Http, Ktor client, and coroutines.

Complete guide to solving re CAPTCHA, Turnstile, and image CAPTCHAs in Kotlin using Captcha AI's HTTP API with...

Automation reCAPTCHA v2 Cloudflare Turnstile
Mar 06, 2026