API Tutorials

How to Solve reCAPTCHA v2 Using API: Step-by-Step Guide

reCAPTCHA v2 is still one of the most common checkpoint challenges in login, signup, checkout, and form-submission flows. If your automation workflow hits a reCAPTCHA v2 checkbox or image challenge, you can solve it through an API in four steps: extract the sitekey and pageurl from the page, send them to the CaptchaAI reCAPTCHA v2 solver, poll for the result, and inject the returned token into the protected flow.

This guide walks through every step with working Python and Node.js code. It is written for developers who need a working integration, not a theory overview.

Not sure which reCAPTCHA version you're dealing with? Read How to Identify reCAPTCHA Version first.


What you need before you start

Requirement Details
CaptchaAI API key Get yours from captchaai.com/api.php. It is a 32-character string.
Target page URL The full URL where the reCAPTCHA v2 widget loads.
reCAPTCHA v2 sitekey The public key tied to the widget instance on the page.
Runtime environment Python 3.7+ with requests, or Node.js 18+ with built-in fetch.
Token submission path A browser automation tool (Selenium, Puppeteer, Playwright) or an HTTP request flow that can submit the solved token.

How to extract the sitekey and pageurl

The two required inputs are the sitekey and the pageurl. Getting either one wrong is the most common reason a solve request fails.

Finding the sitekey

The sitekey is a public key Google assigns to the reCAPTCHA widget on a given page. You can find it in three places:

Option 1 — the data-sitekey attribute on the widget container:

<div class="g-recaptcha" data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"></div>

Option 2 — the anchor URL loaded inside the reCAPTCHA iframe:

https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-&...

The value of the k parameter is the sitekey.

Option 3 — a grecaptcha.render() call in the page's JavaScript:

grecaptcha.render('captcha-container', {
  sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
  callback: onSuccess
});

Setting the pageurl

Use the full URL of the page where the widget loads — including the protocol. For example:

https://example.com/login

If the reCAPTCHA widget loads inside an iframe hosted on a different subdomain, use the iframe's source URL as the pageurl, not the parent page.

Important: If the sitekey and pageurl pair is invalid, the CaptchaAI API returns ERROR_BAD_TOKEN_OR_PAGEURL. Double-check both values before debugging anything else.


How the solving flow works

Page → extract sitekey + pageurl
                ↓
    POST to in.php (method=userrecaptcha)
                ↓
        receive captcha ID
                ↓
    wait 15–20 seconds
                ↓
    GET res.php (action=get, id=…)
        ↓                   ↓
  CAPCHA_NOT_READY     status=1 → token
   (wait 5s, retry)         ↓
                    inject into g-recaptcha-response
                            ↓
                      submit form / callback
  1. SubmitPOST to https://ocr.captchaai.com/in.php with method=userrecaptcha, your API key, the googlekey (sitekey), and the pageurl. The API returns a captcha ID.
  2. Wait — Pause 15–20 seconds. reCAPTCHA v2 solves typically complete in under 60 seconds with a 99.5%+ success rate.
  3. PollGET https://ocr.captchaai.com/res.php with action=get and the captcha ID. If the result is CAPCHA_NOT_READY, wait 5 seconds and retry.
  4. Receive — When solved, the API returns the reCAPTCHA response token (a long encoded string).
  5. Inject — Place the token into the g-recaptcha-response textarea on the page, or pass it to the page's callback function.
  6. Submit — Trigger the form submission or the action the target page expects after a successful reCAPTCHA solve.

Python implementation

import time
import requests

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://example.com/login"

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


def solve_recaptcha_v2(api_key, sitekey, pageurl):
    """Submit a reCAPTCHA v2 challenge and return the solved token."""

    # Step 1: Submit the captcha
    submit_resp = requests.post(
        SUBMIT_URL,
        data={
            "key": api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "json": 1,
        },
        timeout=30,
    )
    submit_resp.raise_for_status()
    submit_data = submit_resp.json()

    if submit_data.get("status") != 1:
        raise RuntimeError(f"Submit failed: {submit_data}")

    captcha_id = submit_data["request"]
    print(f"Task created — captcha ID: {captcha_id}")

    # Step 2: Wait before first poll
    time.sleep(15)

    # Step 3: Poll for result
    for _ in range(60):  # max ~5 minutes of polling
        result_resp = requests.get(
            RESULT_URL,
            params={
                "key": api_key,
                "action": "get",
                "id": captcha_id,
                "json": 1,
            },
            timeout=30,
        )
        result_resp.raise_for_status()
        result_data = result_resp.json()

        if result_data.get("request") == "CAPCHA_NOT_READY":
            time.sleep(5)
            continue

        if result_data.get("status") == 1:
            return result_data["request"]

        raise RuntimeError(f"Polling error: {result_data}")

    raise TimeoutError("reCAPTCHA v2 solve timed out")


# Usage
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

What this does:

  • Sends the sitekey and pageurl to in.php with method=userrecaptcha.
  • Waits 15 seconds, then polls res.php every 5 seconds.
  • Returns the solved token as a string, ready for injection.
  • Includes a safety limit of 60 poll attempts to prevent infinite loops.

Node.js implementation

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://example.com/login";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
  // Step 1: Submit the captcha
  const submitResp = await fetch(SUBMIT_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      key: apiKey,
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: pageurl,
      json: "1",
    }),
  });

  const submitData = await submitResp.json();

  if (submitData.status !== 1) {
    throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
  }

  const captchaId = submitData.request;
  console.log(`Task created — captcha ID: ${captchaId}`);

  // Step 2: Wait before first poll
  await sleep(15_000);

  // Step 3: Poll for result
  for (let i = 0; i < 60; i++) {
    const resultResp = await fetch(
      `${RESULT_URL}?${new URLSearchParams({
        key: apiKey,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );

    const resultData = await resultResp.json();

    if (resultData.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (resultData.status === 1) {
      return resultData.request;
    }

    throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
  }

  throw new Error("reCAPTCHA v2 solve timed out");
}

// Usage
solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL)
  .then((token) => console.log(`Solved token: ${token.slice(0, 80)}...`))
  .catch(console.error);

PHP implementation (optional)

<?php
$apiKey  = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://example.com/login";

// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
    "key"       => $apiKey,
    "method"    => "userrecaptcha",
    "googlekey" => $sitekey,
    "pageurl"   => $pageurl,
    "json"      => 1,
]));

$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
    die("Submit failed: " . $submit);
}

$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";

// Step 2: Wait and poll
sleep(15);

for ($i = 0; $i < 60; $i++) {
    $result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
        "key"    => $apiKey,
        "action" => "get",
        "id"     => $captchaId,
        "json"   => 1,
    ]));

    $resultData = json_decode($result, true);

    if ($resultData["request"] === "CAPCHA_NOT_READY") {
        sleep(5);
        continue;
    }

    if ($resultData["status"] === 1) {
        echo "Solved token: " . substr($resultData["request"], 0, 80) . "...\n";
        exit(0);
    }

    die("Polling error: " . $result);
}

die("Solve timed out");

How to inject the solved token

Getting a token is not the final step. The token must reach the target page in the way it expects.

Method 1: Direct field injection (most common)

Set the value of the hidden g-recaptcha-response textarea. In Selenium (Python):

driver.execute_script(
    'document.getElementById("g-recaptcha-response").innerHTML = arguments[0];',
    token
)
driver.find_element("css selector", "form#login-form").submit()

In Puppeteer (Node.js):

await page.evaluate((token) => {
  document.getElementById("g-recaptcha-response").innerHTML = token;
}, token);
await page.click("#submit-button");

Method 2: Callback function

Some pages define a data-callback on the widget or pass a callback to grecaptcha.render(). In that case, call the callback with the token:

// Find the callback name in the widget's data-callback attribute
// or in grecaptcha.render({ callback: myCallback })
await page.evaluate((token) => {
  // Direct call if you know the function name
  myCallbackFunction(token);

  // Or via the internal config
  // ___grecaptcha_cfg.clients[0].aa.l.callback(token);
}, token);

Method 3: Request-based injection

If you are not using a browser, include the token in the POST body that normally follows the reCAPTCHA solve:

response = requests.post("https://example.com/login", data={
    "username": "user@example.com",
    "password": "secure_password",
    "g-recaptcha-response": token,
})

Common mistakes

# Mistake What happens Fix
1 Wrong sitekey API returns ERROR_BAD_TOKEN_OR_PAGEURL or token is rejected by the page Re-extract the sitekey from data-sitekey or the anchor URL k parameter
2 Wrong pageurl Same as above — the sitekey/pageurl pair does not match Use the exact URL where the widget loads, including protocol
3 Mixing reCAPTCHA versions Submitting a v3 or enterprise challenge as v2 Check the widget type first — see How to Identify reCAPTCHA Version
4 Polling too aggressively Unnecessary API load, possible rate limiting Wait 15–20 seconds before the first poll, then 5 seconds between attempts
5 Token injected into wrong field Form submits but the page rejects the response Verify whether the page uses g-recaptcha-response, a callback, or a custom field
6 Invisible reCAPTCHA sent without invisible=1 Solve may fail silently Add invisible=1 to the request if the widget is invisible — see Common reCAPTCHA Invisible Errors

Troubleshooting

ERROR_WRONG_USER_KEY or ERROR_KEY_DOES_NOT_EXIST

Your API key is malformed or inactive. Verify the 32-character key from captchaai.com/api.php.

ERROR_ZERO_BALANCE

No free threads available. Either wait for threads to free up or upgrade your plan.

ERROR_PAGEURL

The pageurl parameter is missing. Add the full page URL to your request.

ERROR_BAD_TOKEN_OR_PAGEURL

The sitekey/pageurl pair is invalid. The most common cause: the reCAPTCHA widget loads inside an iframe on a different subdomain — use that iframe's URL, not the parent page URL.

CAPCHA_NOT_READY

Normal. The solve is still in progress. Wait 5 seconds and poll again.

ERROR_CAPTCHA_UNSOLVABLE

The challenge could not be solved. Retry with a fresh request.

Token returned but page still rejects it

This is almost always a token injection problem, not an API problem:

  1. Wrong field — Confirm the page uses g-recaptcha-response and not a callback.
  2. Wrong page context — If the widget is in an iframe, the target form may be in a different frame.
  3. Token expired — reCAPTCHA tokens expire after about 2 minutes. Use the token immediately.
  4. Post-token flow wrong — The form submission, AJAX call, or callback execution after injection may be incorrect. Inspect network traffic from a manual solve to compare.

For the complete error reference, see Common reCAPTCHA v2 Solving Errors.


Why CaptchaAI works for this

Factor Detail
Success rate 99.5%+ for reCAPTCHA v2
Solve speed Under 60 seconds
Integration Standard HTTP API — works with any language or framework
Pricing Thread-based plans starting at $15/month for unlimited solves
Same pattern The submit → poll → result flow is identical for reCAPTCHA v3, Turnstile, GeeTest, and other types

The biggest practical advantage: the exact same code pattern (submit to in.php, poll res.php) works across every captcha type CaptchaAI supports. Learn it once, and you can extend it to Cloudflare Turnstile, GeeTest v3, and more.


FAQ

What is the sitekey in reCAPTCHA v2?

The sitekey is the public key Google assigns to a specific reCAPTCHA widget instance. You need it together with the page URL to create a solve request. Find it in the data-sitekey attribute, the anchor iframe URL (k parameter), or in a grecaptcha.render() call.

How long does reCAPTCHA v2 solving take?

CaptchaAI solves reCAPTCHA v2 in under 60 seconds with a 99.5%+ success rate. Wait 15–20 seconds before your first poll, then check every 5 seconds.

Can I use the solved token in Selenium or Puppeteer?

Yes. Inject the token into the g-recaptcha-response field using JavaScript execution, then submit the form. If the page uses a callback, call that callback with the token instead.

How do I know the site uses reCAPTCHA v2 and not v3 or Enterprise?

Look for the "I'm not a robot" checkbox, a data-sitekey attribute on a widget container, or the absence of the render=sitekey pattern in api.js loading (which indicates v3). For the full detection method, read How to Identify reCAPTCHA Version.

What if the reCAPTCHA is invisible?

Add invisible=1 to your API request. The submit and poll flow is otherwise the same. Read How reCAPTCHA Invisible Works for details.

Does CaptchaAI support proxies for reCAPTCHA v2?

Yes. Add proxy (format: login:password@IP:PORT) and proxytype (HTTP, HTTPS, SOCKS4, or SOCKS5) to your request. Proxies are optional but recommended when IP matching matters.


Start solving reCAPTCHA v2

The fastest path from here:

  1. Get your API keycaptchaai.com/api.php
  2. Copy the Python or Node.js code above — replace the placeholders with your key, sitekey, and pageurl
  3. Run it — you will have a solved token in under 60 seconds
  4. Inject the token — use direct field injection, callback, or request-body inclusion
  5. Explore the API docsdocs.captchaai.com for the full parameter reference

If you run into issues, start with the Troubleshooting section above or read the full reCAPTCHA v2 Errors and Fixes guide.


Iteration log

Iteration Focus Changes
Draft 1 Structure and content Initial draft from brief — workflow, Python/Node.js code, FAQ, CTA
Draft 2 Technical accuracy Verified all API endpoints, parameters, and error codes against captchaai.com/api-docs. Added PHP example. Added proxy parameter note.
Draft 3 Token injection depth Added 3 injection methods (field, callback, request-body) with Selenium/Puppeteer code. Added error code table with official fix actions.
Draft 4 SEO and internal linking Added structured FAQ answers, internal links to 5 cluster articles, meta title/description, common mistakes table, technical stats table.
Draft 5 Final QA polish Verified code examples run cleanly. Added poll safety limit. Tightened intro. Added invisible reCAPTCHA boundary note. Confirmed all error codes match official docs.

Visual asset brief

Hero image

  • Alt text: Developer workflow for solving reCAPTCHA v2 via API — sitekey extraction, API request, token injection
  • Must show: A clean technical flow from page → API → token → form submission
  • File name: recaptcha-v2-api-solver-workflow-hero.png

In-article visual 1

  • Placement: After "How the solving flow works"
  • Type: Flowchart
  • Alt text: Flowchart showing reCAPTCHA v2 API solving sequence — submit, poll, receive token, inject
  • File name: recaptcha-v2-submit-poll-result-flow.png

In-article visual 2

  • Placement: Before "Troubleshooting"
  • Type: Decision tree
  • Alt text: Decision tree for diagnosing reCAPTCHA v2 integration failures
  • File name: recaptcha-v2-troubleshooting-decision-tree.png

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
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
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
Tutorials Securing CaptchaAI Credentials in Environment Variables
Store Captcha AI API keys securely using environment variables, .env files, Docker secrets, and cloud secret managers instead of hardcoding.

Store Captcha AI API keys securely using environment variables, .env files, Docker secrets, and cloud secret m...

Automation Python reCAPTCHA v2
Feb 12, 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 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
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
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
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
API Tutorials Solve Image CAPTCHA with Python OCR and CaptchaAI
Solve distorted text image CAPTCHAs using Captcha AI's OCR API from Python.

Solve distorted text image CAPTCHAs using Captcha AI's OCR API from Python. Covers file upload, base 64 submis...

Automation Python Image OCR