Most reCAPTCHA v2 failures fall into three buckets: request-stage mistakes (wrong parameters sent to the API), result-stage issues (polling problems or unsolvable tasks), and target-page rejections (the API returns a valid token but the page ignores it). The biggest culprits are almost always the same: wrong googlekey, incorrect pageurl, missing callback execution, or expired tokens.
This guide walks through every common failure pattern with the exact fix for each one. If you are new to reCAPTCHA v2 solving, read How to Solve reCAPTCHA v2 Using API first.
The four biggest reCAPTCHA v2 failure points
Before digging into individual error codes, check these first — they cover 80% of failures.
1. Wrong or missing googlekey
The googlekey (sitekey) comes from the data-sitekey attribute on the reCAPTCHA widget or the k parameter in the anchor URL. If this value is wrong, blank, or copied from a different page, the API rejects the task immediately with ERROR_GOOGLEKEY or ERROR_WRONG_GOOGLEKEY.
How to find the correct sitekey:
# Look for data-sitekey in the page HTML
# <div class="g-recaptcha" data-sitekey="6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-"></div>
# Or find it in the anchor URL
# https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-
2. Wrong pageurl
The pageurl must be the exact URL where the reCAPTCHA widget loads. If the widget is inside an iframe hosted on a different domain, you need the iframe URL — not the parent page URL. Sending the wrong URL causes ERROR_PAGEURL or ERROR_BAD_TOKEN_OR_PAGEURL.
3. Callback not executed
Some pages use a JavaScript callback function instead of the hidden g-recaptcha-response field. If you inject the token into the hidden field but the page expects a callback, the form never submits. Check for data-callback on the widget or a callback property in grecaptcha.render().
4. Token expired or reused
reCAPTCHA tokens are valid for one use only and expire after about 2 minutes. If your automation takes too long between receiving the token and submitting the form, or if it reuses a token, the target page rejects it silently.
Request-stage errors (in.php)
These errors happen when you submit the CAPTCHA task to https://ocr.captchaai.com/in.php.
| Error Code | Cause | Fix |
|---|---|---|
ERROR_WRONG_USER_KEY |
API key format is invalid (not 32 characters) | Check your API key at captchaai.com/api.php |
ERROR_KEY_DOES_NOT_EXIST |
API key does not exist in the system | Verify you copied the full key without extra spaces |
ERROR_ZERO_BALANCE |
Account balance is zero | Top up your account or check active thread count |
ERROR_PAGEURL |
pageurl parameter is missing |
Add the full URL where the reCAPTCHA widget appears |
ERROR_GOOGLEKEY |
googlekey is malformed or empty |
Extract the correct sitekey from the page |
ERROR_WRONG_GOOGLEKEY |
googlekey parameter is missing entirely |
Add googlekey to your API request |
ERROR_BAD_TOKEN_OR_PAGEURL |
The googlekey + pageurl pair is invalid |
Check if the widget is in an iframe; use the iframe URL |
ERROR_BAD_PARAMETERS |
Required parameters are missing or malformed | Review the API docs for required fields |
Example: Correct request with error handling
import requests
def submit_recaptcha_v2(api_key, sitekey, page_url):
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1
})
data = response.json()
if data.get("status") == 1:
return data["request"] # task ID
error = data.get("request", "UNKNOWN_ERROR")
if error == "ERROR_WRONG_USER_KEY":
raise ValueError("API key format is invalid. Must be 32 characters.")
elif error == "ERROR_ZERO_BALANCE":
raise RuntimeError("Account balance is zero. Top up at captchaai.com")
elif error == "ERROR_PAGEURL":
raise ValueError("pageurl parameter is missing from request")
elif error in ("ERROR_GOOGLEKEY", "ERROR_WRONG_GOOGLEKEY"):
raise ValueError(f"Invalid sitekey. Verify the data-sitekey value on the page.")
elif error == "ERROR_BAD_TOKEN_OR_PAGEURL":
raise ValueError("Sitekey/pageurl mismatch. Check if widget is in an iframe.")
else:
raise RuntimeError(f"API error: {error}")
# Usage
task_id = submit_recaptcha_v2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://example.com/login")
print(f"Task submitted: {task_id}")
async function submitRecaptchaV2(apiKey, sitekey, pageUrl) {
const params = new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const data = await res.json();
if (data.status === 1) return data.request;
const error = data.request || "UNKNOWN_ERROR";
const fixes = {
ERROR_WRONG_USER_KEY: "API key format is invalid. Must be 32 characters.",
ERROR_ZERO_BALANCE: "Account balance is zero. Top up at captchaai.com",
ERROR_PAGEURL: "pageurl parameter is missing from request",
ERROR_GOOGLEKEY: "Invalid sitekey. Check the data-sitekey attribute.",
ERROR_BAD_TOKEN_OR_PAGEURL: "Sitekey/pageurl mismatch. Check iframe context.",
};
throw new Error(fixes[error] || `API error: ${error}`);
}
// Usage
const taskId = await submitRecaptchaV2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://example.com/login");
console.log(`Task submitted: ${taskId}`);
Result-stage errors (res.php)
These errors happen when polling https://ocr.captchaai.com/res.php for the result.
| Error Code | Cause | Fix |
|---|---|---|
CAPCHA_NOT_READY |
Solve is still in progress | Wait 5 seconds and poll again. This is normal. |
ERROR_CAPTCHA_UNSOLVABLE |
The CAPTCHA could not be solved | Submit a new task with fresh parameters |
ERROR_WRONG_ID_FORMAT |
Task ID format is invalid | Verify the ID returned from in.php |
ERROR_WRONG_CAPTCHA_ID |
Task ID does not exist | Check that you saved the correct task ID |
ERROR_EMPTY_ACTION |
action=get parameter is missing |
Add action=get to your polling request |
Example: Polling with proper error handling
import time
import requests
def poll_result(api_key, task_id, timeout=120):
start = time.time()
while time.time() - start < timeout:
time.sleep(5)
response = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = response.json()
if data.get("status") == 1:
return data["request"] # solved token
error = data.get("request", "")
if error == "CAPCHA_NOT_READY":
continue # normal — keep waiting
elif error == "ERROR_CAPTCHA_UNSOLVABLE":
raise RuntimeError("CAPTCHA unsolvable. Submit a new task with fresh params.")
elif error in ("ERROR_WRONG_ID_FORMAT", "ERROR_WRONG_CAPTCHA_ID"):
raise ValueError(f"Invalid task ID: {task_id}")
else:
raise RuntimeError(f"Polling error: {error}")
raise TimeoutError(f"Solve timed out after {timeout}s")
# Usage
token = poll_result("YOUR_API_KEY", task_id)
print(f"Token: {token[:50]}...")
async function pollResult(apiKey, taskId, timeout = 120000) {
const start = Date.now();
while (Date.now() - start < timeout) {
await new Promise((r) => setTimeout(r, 5000));
const params = new URLSearchParams({
key: apiKey,
action: "get",
id: taskId,
json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/res.php?${params}`);
const data = await res.json();
if (data.status === 1) return data.request;
if (data.request === "CAPCHA_NOT_READY") continue;
if (data.request === "ERROR_CAPTCHA_UNSOLVABLE")
throw new Error("Unsolvable. Submit a new task.");
throw new Error(`Polling error: ${data.request}`);
}
throw new Error(`Solve timed out after ${timeout / 1000}s`);
}
Target-page rejections
The API returned a valid token but the target site still rejects it. These are the hardest failures to debug because the API thinks everything worked.
Token injected into the wrong field
Some pages look for the token in the g-recaptcha-response textarea. Others use grecaptcha.getResponse(). Others expect a callback. If you pick the wrong injection method, the form submission fails silently.
Fix: Inspect the page to determine the expected path:
# Method 1: Hidden field injection
driver.execute_script(
'document.getElementById("g-recaptcha-response").innerHTML = arguments[0];',
token
)
# Method 2: Callback execution (check data-callback attribute)
driver.execute_script(f'onCaptchaSuccess("{token}");')
# Method 3: Direct form field + submit
driver.execute_script(
'document.querySelector("[name=g-recaptcha-response]").value = arguments[0];',
token
)
driver.find_element("css selector", "form").submit()
Callback not triggered
If the widget has data-callback="onSuccess" or uses grecaptcha.render() with a callback property, filling the hidden field alone does nothing. You must call the callback function directly.
Fix: Find and call the callback:
// In browser console or Puppeteer/Playwright
// Check for data-callback
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
window[callbackName](token);
}
Token expired
If more than ~2 minutes pass between receiving the token and submitting the form, Google rejects it. This is common in slow automation pipelines.
Fix: Submit the form immediately after receiving the token. If your pipeline is slow, request the solve closer to the submission step rather than at the start.
Widget is in an iframe
If the reCAPTCHA loads inside an iframe from a different domain, you must use the iframe source URL as pageurl, not the parent page URL. The ERROR_BAD_TOKEN_OR_PAGEURL error usually signals this problem.
Fix: Inspect the page, find the iframe containing the reCAPTCHA, and use that iframe's src URL as your pageurl.
Quick diagnosis checklist
| Symptom | First thing to check |
|---|---|
ERROR_GOOGLEKEY or ERROR_WRONG_GOOGLEKEY |
Is the sitekey copied correctly from data-sitekey? |
ERROR_PAGEURL |
Did you include the full page URL? |
ERROR_BAD_TOKEN_OR_PAGEURL |
Is the widget inside an iframe? Use the iframe URL. |
CAPCHA_NOT_READY for over 3 minutes |
Normal for hard challenges. Increase timeout to 180s. |
ERROR_CAPTCHA_UNSOLVABLE |
Submit a new task. If repeated, verify sitekey + pageurl. |
| Token works but page does nothing | Check for data-callback. Call the callback function. |
| Token returns but form still fails | Token may be expired (>2 min). Submit faster. |
| Intermittent failures | Add retry logic with fresh task IDs. |
FAQ
Why does reCAPTCHA v2 fail even when the request looks correct?
The three most common causes are: (1) the pageurl does not match the actual widget context — especially when the widget is inside an iframe, (2) the page expects a callback function but you only filled the hidden field, or (3) the token expired before you submitted the form.
What is the most common reCAPTCHA v2 solving mistake?
Using the wrong googlekey or wrong pageurl. This is especially common when the reCAPTCHA widget loads in an iframe on a different domain or subdomain — the sitekey and URL must match the iframe context, not the parent page.
What does CAPCHA_NOT_READY mean?
It means the CAPTCHA is still being solved. This is not an error. Wait 5 seconds and poll res.php again. Typical reCAPTCHA v2 solve times are 15–60 seconds.
What should I do if the API returns a token but the page still rejects it?
Check three things in order: (1) Does the page use a callback? Look for data-callback on the widget. (2) Is your pageurl correct — especially if the widget is in an iframe? (3) Did more than 2 minutes pass between receiving and using the token?
How do I handle ERROR_CAPTCHA_UNSOLVABLE?
Submit a new task with fresh parameters. Do not retry the same task ID. If this error happens repeatedly, verify your sitekey and pageurl match the actual page and that the CAPTCHA type is standard reCAPTCHA v2 (not Enterprise — which requires different parameters).
Fix your reCAPTCHA v2 workflow
- Verify your inputs — extract
googlekeyfromdata-sitekeyand use the exact page URL (check for iframes) - Check the injection method — determine whether the page expects hidden field, callback, or both
- Submit immediately — use the token within 2 minutes of receiving it
- Add error handling — use the code examples above to catch and handle every error type
Start solving reCAPTCHA v2 with the CaptchaAI solver. Get your API key from captchaai.com/api.php.
Related guides
- How to Solve reCAPTCHA v2 Using API — full step-by-step tutorial
- How to Solve reCAPTCHA v2 Callback Using API — callback-specific guide
- reCAPTCHA Grid Challenge Explained — how grid challenges work
- CaptchaAI Error Codes Reference — complete error code list
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.