Getting Started

Callback vs Polling: CaptchaAI Result Delivery

CaptchaAI offers two ways to receive solved CAPTCHA results: polling (you ask repeatedly) and callback (we tell you). Both work with all CAPTCHA types. Here's when to use each.

Polling (Default)

Poll the res.php endpoint every 5 seconds until the result is ready:

import requests
import time

API_KEY = "YOUR_API_KEY"

# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com"
})
task_id = resp.text.split("|")[1]

# Poll
while True:
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "get",
        "id": task_id
    })
    if result.text == "CAPCHA_NOT_READY":
        continue
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

Polling Pros

  • Simple to implement
  • No server infrastructure needed
  • Works in any environment (scripts, serverless, CLI)
  • No firewall or networking concerns

Polling Cons

  • Wastes requests while waiting (one every 5 seconds)
  • Adds latency — you check after the solve completes, not instantly
  • Higher API call volume

Callback (Webhook)

Provide a pingback URL when submitting. CaptchaAI posts the result to your URL when solving completes:

# Submit with callback URL
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "pingback": "https://your-server.com/captcha-callback"
})
task_id = resp.text.split("|")[1]
# No polling needed — result arrives at your callback URL

CaptchaAI sends a GET request to your callback URL:

GET https://your-server.com/captcha-callback?id=TASK_ID&code=TOKEN

Callback Server (Python Flask)

from flask import Flask, request

app = Flask(__name__)
results = {}

@app.route("/captcha-callback")
def callback():
    task_id = request.args.get("id")
    token = request.args.get("code")
    results[task_id] = token
    return "OK", 200

@app.route("/get-result/<task_id>")
def get_result(task_id):
    token = results.get(task_id)
    if token:
        return {"status": "solved", "token": token}
    return {"status": "pending"}, 202

if __name__ == "__main__":
    app.run(port=8080)

Callback Server (Node.js Express)

const express = require("express");
const app = express();

const results = new Map();

app.get("/captcha-callback", (req, res) => {
  const { id, code } = req.query;
  results.set(id, code);
  res.send("OK");
});

app.get("/get-result/:taskId", (req, res) => {
  const token = results.get(req.params.taskId);
  if (token) {
    res.json({ status: "solved", token });
  } else {
    res.status(202).json({ status: "pending" });
  }
});

app.listen(8080);

Callback Pros

  • Instant notification when solve completes
  • No wasted polling requests
  • More efficient for high-volume usage
  • Better for async architectures

Callback Cons

  • Requires a publicly accessible server
  • Need to handle webhook reliability (retries, timeouts)
  • More complex infrastructure
  • Firewall/networking setup required

Comparison

Factor Polling Callback
Infrastructure needed None Web server with public URL
Implementation complexity Simple Medium
Latency after solve 0-5 seconds Near-instant
API calls per solve ~3-12 (polling requests) 1 (submit only)
Best for Scripts, small projects High-volume, server apps
Works behind firewall ❌ (needs public URL)
Works in serverless ⚠️ (requires webhook endpoint)

When to Use Each

Use Polling When:

  • Running local scripts or CLI tools
  • Building prototypes or testing
  • Behind a firewall without a public server
  • Processing fewer than 100 CAPTCHAs per hour
  • Using serverless functions (Lambda, Cloud Functions)

Use Callbacks When:

  • Processing 100+ CAPTCHAs per hour
  • Running a web application with a server already available
  • Building real-time systems where latency matters
  • You want to minimize API call volume
  • Building a CAPTCHA solving microservice

Hybrid Approach

Use callbacks with a polling fallback:

import requests
import time

API_KEY = "YOUR_API_KEY"
CALLBACK_URL = "https://your-server.com/captcha-callback"

def solve_with_fallback(site_key, page_url):
    # Try callback first
    resp = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "pingback": CALLBACK_URL
    })
    task_id = resp.text.split("|")[1]

    # Wait for callback result (check your callback store)
    for _ in range(12):  # 60 seconds
        time.sleep(5)
        result = check_callback_store(task_id)
        if result:
            return result

    # Fallback to polling
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        return result.text.split("|")[1]

    raise TimeoutError()

FAQ

Does the callback URL need HTTPS?

HTTPS is recommended for security, but HTTP also works. If your callback handles sensitive data (tokens), use HTTPS.

What if my callback server is down when the result arrives?

CaptchaAI may retry the callback. As a safety net, you can always fall back to polling the result endpoint.

Can I use the same callback URL for multiple tasks?

Yes. Each callback includes the id parameter so you can match results to their tasks.

Discussions (0)

No comments yet.