Tutorials

Handling Multiple CAPTCHAs on a Single Page

Some pages render two or more CAPTCHAs — a login form with reCAPTCHA and a newsletter signup with a second reCAPTCHA, or a multi-step form where each step triggers its own challenge. Each CAPTCHA has a unique sitekey and target element, so you need to detect all of them, solve them in parallel, and inject each token into the correct callback.


Detecting multiple CAPTCHAs

Python with Selenium

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com/multi-captcha-page")

# Find all reCAPTCHA iframes
captcha_iframes = driver.find_elements(
    By.CSS_SELECTOR, 'iframe[src*="recaptcha/api2/anchor"]'
)

# Extract sitekeys from each iframe's src
import re
captchas = []
for i, iframe in enumerate(captcha_iframes):
    src = iframe.get_attribute("src")
    match = re.search(r"k=([A-Za-z0-9_-]+)", src)
    if match:
        captchas.append({
            "index": i,
            "sitekey": match.group(1),
            "iframe": iframe
        })

print(f"Found {len(captchas)} CAPTCHAs on page")
for c in captchas:
    print(f"  [{c['index']}] sitekey: {c['sitekey']}")

Expected output:

Found 2 CAPTCHAs on page
  [0] sitekey: 6LcXyzABCDEF-login
  [1] sitekey: 6LcAbcDEFGHI-signup

JavaScript with Puppeteer

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto('https://example.com/multi-captcha-page', {
    waitUntil: 'networkidle2'
  });

  // Extract all reCAPTCHA widgets from the page
  const captchas = await page.evaluate(() => {
    const widgets = document.querySelectorAll('.g-recaptcha');
    return Array.from(widgets).map((el, i) => ({
      index: i,
      sitekey: el.getAttribute('data-sitekey'),
      elementId: el.id || `captcha-${i}`,
      callbackName: el.getAttribute('data-callback') || null
    }));
  });

  console.log(`Found ${captchas.length} CAPTCHAs`);
  captchas.forEach(c => console.log(`  [${c.index}] ${c.sitekey}`));
})();

Solving all CAPTCHAs in parallel

Submit all CAPTCHAs to CaptchaAI at once, then poll until each resolves.

Python

import requests
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

API_KEY = "YOUR_API_KEY"
PAGE_URL = "https://example.com/multi-captcha-page"

def submit_captcha(sitekey):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": PAGE_URL,
        "json": "1"
    })
    result = resp.json()
    if result["status"] != 1:
        raise Exception(f"Submit error: {result['request']}")
    return result["request"]

def poll_result(task_id, timeout=120):
    deadline = time.time() + timeout
    while time.time() < deadline:
        time.sleep(5)
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": "1"
        })
        result = resp.json()
        if result["status"] == 1:
            return result["request"]
        if result["request"] != "CAPCHA_NOT_READY":
            raise Exception(f"Poll error: {result['request']}")
    raise TimeoutError(f"Task {task_id} timed out")

def solve_all(captchas):
    # Submit all in parallel
    task_ids = {}
    with ThreadPoolExecutor(max_workers=len(captchas)) as pool:
        futures = {
            pool.submit(submit_captcha, c["sitekey"]): c["index"]
            for c in captchas
        }
        for future in as_completed(futures):
            idx = futures[future]
            task_ids[idx] = future.result()
            print(f"[captcha-{idx}] Submitted → task {task_ids[idx]}")

    # Poll all in parallel
    tokens = {}
    with ThreadPoolExecutor(max_workers=len(task_ids)) as pool:
        futures = {
            pool.submit(poll_result, tid): idx
            for idx, tid in task_ids.items()
        }
        for future in as_completed(futures):
            idx = futures[future]
            tokens[idx] = future.result()
            print(f"[captcha-{idx}] Solved")

    return tokens

# Example usage
captchas = [
    {"index": 0, "sitekey": "6LcXyzABCDEF-login"},
    {"index": 1, "sitekey": "6LcAbcDEFGHI-signup"}
]

tokens = solve_all(captchas)

Expected output:

[captcha-0] Submitted → task 71823456
[captcha-1] Submitted → task 71823457
[captcha-1] Solved
[captcha-0] Solved

Injecting tokens into the correct widget

Each reCAPTCHA widget has its own g-recaptcha-response textarea. When multiple widgets exist, each textarea is nested inside its widget container.

Python (Selenium)

def inject_tokens(driver, captchas, tokens):
    for c in captchas:
        idx = c["index"]
        token = tokens[idx]

        # Find the textarea within the widget's container
        container = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")[idx]
        textarea = container.find_element(
            By.CSS_SELECTOR, 'textarea[name="g-recaptcha-response"]'
        )
        driver.execute_script(
            "arguments[0].value = arguments[1];", textarea, token
        )

        # Trigger the callback if defined
        callback = c.get("callback")
        if callback:
            driver.execute_script(f"{callback}('{token}');")

        print(f"[captcha-{idx}] Token injected")

inject_tokens(driver, captchas, tokens)

JavaScript (Puppeteer)

async function injectTokens(page, captchas, tokens) {
  for (const captcha of captchas) {
    const token = tokens[captcha.index];

    await page.evaluate((idx, tkn, callbackName) => {
      const widgets = document.querySelectorAll('.g-recaptcha');
      const textarea = widgets[idx].querySelector(
        'textarea[name="g-recaptcha-response"]'
      );
      textarea.value = tkn;

      if (callbackName && typeof window[callbackName] === 'function') {
        window[callbackName](tkn);
      }
    }, captcha.index, token, captcha.callbackName);

    console.log(`[captcha-${captcha.index}] Token injected`);
  }
}

await injectTokens(page, captchas, tokens);

Mixed CAPTCHA types

When a page has different CAPTCHA types (e.g., reCAPTCHA + Turnstile), detect each type separately:

def detect_all_captchas(driver):
    detected = []

    # reCAPTCHA
    recaptchas = driver.find_elements(By.CSS_SELECTOR, ".g-recaptcha")
    for i, el in enumerate(recaptchas):
        detected.append({
            "type": "userrecaptcha",
            "sitekey": el.get_attribute("data-sitekey"),
            "label": f"recaptcha-{i}"
        })

    # Turnstile
    turnstiles = driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile")
    for i, el in enumerate(turnstiles):
        detected.append({
            "type": "turnstile",
            "sitekey": el.get_attribute("data-sitekey"),
            "label": f"turnstile-{i}"
        })

    return detected

Submit each with its matching method parameter — userrecaptcha for reCAPTCHA, turnstile for Turnstile.


Troubleshooting

Problem Cause Fix
Token injected but form still blocked Callback not triggered Check data-callback and call it with the token
Only first CAPTCHA detected Second CAPTCHA loads lazily Wait for all iframes/widgets to appear before scanning
Wrong token in wrong widget Index mismatch Map tokens to sitekeys, not positional index
ERROR_WRONG_GOOGLEKEY Sitekey extracted incorrectly Verify sitekey from iframe src or data-sitekey attribute

FAQ

Can a page have different sitekeys for each CAPTCHA?

Yes. Each widget can use a separate sitekey. Always extract the sitekey per widget rather than assuming they share one.

Should I solve them sequentially or in parallel?

In parallel. Each solve takes 15-30 seconds. Solving two CAPTCHAs in parallel takes the same time as solving one.

What if the second CAPTCHA only appears after submitting the first form?

Re-scan the page after each form submission to detect newly rendered CAPTCHAs. Use WebDriverWait (Selenium) or page.waitForSelector (Puppeteer) to wait for the new widget.


Solve any number of CAPTCHAs per page with CaptchaAI

Get your API key at captchaai.com.


Discussions (0)

No comments yet.

Related Posts

Use Cases Multi-Step Workflow Automation with CaptchaAI
Manage workflows across multiple accounts on CAPTCHA-protected platforms — , action, and data collection at scale.

Manage workflows across multiple accounts on CAPTCHA-protected platforms — , action, and data collection at sc...

Automation Python reCAPTCHA v2
Apr 06, 2026
Use Cases Academic Research Web Scraping with CAPTCHA Solving
How researchers can collect data from academic databases, journals, and citation sources protected by CAPTCHAs using Captcha AI.

How researchers can collect data from academic databases, journals, and citation sources protected by CAPTCHAs...

Python reCAPTCHA v2 Cloudflare Turnstile
Apr 06, 2026
Explainers Mobile Proxies for CAPTCHA Solving: Higher Success Rates Explained
Why mobile proxies produce the lowest CAPTCHA trigger rates and how to use them with Captcha AI for maximum success.

Why mobile proxies produce the lowest CAPTCHA trigger rates and how to use them with Captcha AI for maximum su...

Python reCAPTCHA v2 Cloudflare Turnstile
Apr 03, 2026
Troubleshooting CAPTCHA Appears After Login: Mid-Session CAPTCHA Handling
Handle CAPTCHAs that appear mid-session after — triggered by suspicious activity, rate limits, or session age.

Handle CAPTCHAs that appear mid-session after — triggered by suspicious activity, rate limits, or session age....

Python reCAPTCHA v2 Cloudflare Turnstile
Apr 01, 2026
Troubleshooting ERROR_PROXY_NOT_AUTHORIZED: Proxy Authentication Fixes
Fix ERROR_PROXY_NOT_AUTHORIZED when using Captcha AI with proxies.

Fix ERROR_PROXY_NOT_AUTHORIZED when using Captcha AI with proxies. Diagnose proxy format, authentication, whit...

Python reCAPTCHA v2 Cloudflare Turnstile
Mar 30, 2026
Integrations Selenium Wire + CaptchaAI: Request Interception for CAPTCHA Solving
Complete guide to using Selenium Wire for request interception, proxy routing, and automated CAPTCHA solving with Captcha AI in Python.

Complete guide to using Selenium Wire for request interception, proxy routing, and automated CAPTCHA solving w...

Python reCAPTCHA v2 Cloudflare Turnstile
Mar 13, 2026
Explainers Rotating Residential Proxies: Best Practices for CAPTCHA Solving
Best practices for using rotating residential proxies with Captcha AI to reduce CAPTCHA frequency and maintain high solve rates.

Best practices for using rotating residential proxies with Captcha AI to reduce CAPTCHA frequency and maintain...

Python reCAPTCHA v2 Cloudflare Turnstile
Mar 01, 2026
Use Cases Job Board Scraping with CAPTCHA Handling Using CaptchaAI
Scrape job listings from Indeed, Linked In, Glassdoor, and other job boards that use CAPTCHAs with Captcha AI integration.

Scrape job listings from Indeed, Linked In, Glassdoor, and other job boards that use CAPTCHAs with Captcha AI...

Python reCAPTCHA v2 Cloudflare Turnstile
Feb 28, 2026
Integrations Smartproxy + CaptchaAI: Residential Proxy Setup for CAPTCHA Solving
Set up Smartproxy residential proxies with Captcha AI for reliable CAPTCHA solving with clean residential IPs.

Set up Smartproxy residential proxies with Captcha AI for reliable CAPTCHA solving with clean residential IPs.

Python reCAPTCHA v2 Cloudflare Turnstile
Feb 26, 2026
Tutorials Extracting reCAPTCHA Parameters from Page Source
Extract re CAPTCHA parameters from any web page — sitekey, action, data-s, enterprise flag, and version — using regex, DOM queries, and network interception.

Extract all re CAPTCHA parameters from any web page — sitekey, action, data-s, enterprise flag, and version —...

Python reCAPTCHA v2 Web Scraping
Apr 07, 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