Cuando la resolución de un reCAPTCHA v2 falla, casi nunca es culpa del servicio de resolución: es un parámetro mal copiado. En la práctica, cuatro problemas concentran la enorme mayoría de los fallos: un googlekey incorrecto, un pageurl que no coincide con el widget real, un callback que la página espera pero que tu automatización nunca ejecuta, y un token que ya caducó antes de enviar el formulario. Identifica cuál de los cuatro te está afectando y el resto es cuestión de un ajuste puntual.
Esta guía separa los fallos por etapa —envío de la tarea, sondeo del resultado y aceptación en la página de destino— y te da la corrección exacta para cada código de error, con ejemplos en Python y JavaScript. Si todavía no has integrado el flujo básico, empieza por Cómo resolver reCAPTCHA v2 usando la API y vuelve aquí cuando algo falle.
Tabla de diagnóstico rápido: empieza por aquí
Antes de leer el detalle, localiza tu síntoma en esta tabla. En la mayoría de los casos apunta directamente a la causa.
| Síntoma | Lo primero que hay que comprobar |
|---|---|
ERROR_GOOGLEKEY o ERROR_WRONG_GOOGLEKEY |
¿Copiaste bien la sitekey desde data-sitekey? |
ERROR_PAGEURL |
¿Incluiste la URL completa de la página? |
ERROR_BAD_TOKEN_OR_PAGEURL |
¿El widget está dentro de un iframe? Usa la URL del iframe. |
CAPCHA_NOT_READY durante más de 3 minutos |
Normal en desafíos difíciles. Sube el timeout a 180 s. |
ERROR_CAPTCHA_UNSOLVABLE |
Envía una tarea nueva. Si se repite, revisa sitekey + pageurl. |
| El token llega pero la página no reacciona | Busca data-callback y llama a la función callback. |
| El token vuelve pero el formulario aún falla | El token puede estar caducado (>2 min). Envía más rápido. |
| Fallos intermitentes | Añade lógica de reintento con IDs de tarea nuevos. |
Los cuatro fallos que causan el 80% de los errores
Antes de bajar a los códigos de error concretos, descarta estos cuatro puntos, en orden.
1. googlekey incorrecto o ausente
El googlekey (la sitekey) sale del atributo data-sitekey del widget o del parámetro k de la URL de anclaje (anchor).
- Cómo se manifiesta:
ERROR_GOOGLEKEY(formato inválido o vacío) oERROR_WRONG_GOOGLEKEY(falta el parámetro). - Cómo lo corriges: vuelve a extraer la sitekey de
data-sitekey(o del parámetrokdel anchor) en la página real, sin recortes ni espacios:
# 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. pageurl que no coincide
- Cómo se manifiesta:
ERROR_PAGEURL(falta la URL) oERROR_BAD_TOKEN_OR_PAGEURL(enviaste la URL de la página en lugar de la del iframe). - Cómo lo corriges: usa la URL exacta donde carga el widget: la de la página real o, si vive en un iframe de otro dominio, la de su atributo
src.
3. Callback sin ejecutar
- Cómo se manifiesta: la página usa una función callback de JavaScript en lugar del campo oculto
g-recaptcha-response; inyectas el token pero el formulario no reacciona ni muestra error. - Cómo lo corriges: busca
data-callbacken el widget o una propiedadcallbackdentro degrecaptcha.render()y llama a esa función con el token.
4. Token caducado o reutilizado
- Cómo se manifiesta: los tokens sirven para un único uso y caducan tras unos 2 minutos; si tardas demasiado o reutilizas uno ya consumido, la página lo rechaza en silencio, sin código de la API.
- Cómo lo corriges: pide la resolución justo antes de enviar el formulario y nunca reutilices un token ya gastado.
Errores en la etapa de envío (in.php)
Estos errores aparecen cuando envías la tarea CAPTCHA a https://ocr.captchaai.com/in.php.
| Código de error | Causa | Solución |
|---|---|---|
ERROR_WRONG_USER_KEY |
El formato de la clave API no es válido (no tiene 32 caracteres) | Verifica tu clave API en captchaai.com/api.php |
ERROR_KEY_DOES_NOT_EXIST |
La clave API no existe en el sistema. | Comprueba que copiaste la clave completa, sin espacios de más |
ERROR_ZERO_BALANCE |
El saldo de la cuenta es cero. | Recarga tu cuenta o revisa el número de threads activos |
ERROR_PAGEURL |
Falta el parámetro pageurl |
Añade la URL completa donde aparece el widget reCAPTCHA |
ERROR_GOOGLEKEY |
googlekey tiene un formato incorrecto o está vacío |
Extrae la sitekey correcta de la página |
ERROR_WRONG_GOOGLEKEY |
Falta por completo el parámetro googlekey |
Añade googlekey a tu solicitud a la API |
ERROR_BAD_TOKEN_OR_PAGEURL |
El par googlekey + pageurl no es válido |
Comprueba si el widget está en un iframe; usa la URL del iframe |
ERROR_BAD_PARAMETERS |
Faltan parámetros obligatorios o están mal formados | Revisa la documentación de la API para ver los campos requeridos |
Ejemplo: solicitud correcta con manejo de errores
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://staging.example.com/qa-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://staging.example.com/qa-login");
console.log(`Task submitted: ${taskId}`);
Errores en la etapa de sondeo (res.php)
Estos errores aparecen al sondear https://ocr.captchaai.com/res.php para recuperar el resultado.
| Código de error | Causa | Solución |
|---|---|---|
CAPCHA_NOT_READY |
La resolución sigue en curso. | Espera 5 segundos y vuelve a sondear. Es normal. |
ERROR_CAPTCHA_UNSOLVABLE |
El CAPTCHA no se pudo resolver | Envía una tarea nueva con parámetros frescos |
ERROR_WRONG_ID_FORMAT |
El formato del ID de tarea no es válido | Verifica el ID que devolvió in.php |
ERROR_WRONG_CAPTCHA_ID |
El ID de tarea no existe | Comprueba que guardaste el ID de tarea correcto |
ERROR_EMPTY_ACTION |
Falta el parámetro action=get |
Añade action=get a tu solicitud de sondeo |
Ejemplo: sondeo con manejo de errores
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`);
}
Cuando el token es válido pero la página lo rechaza
El token entra en el campo equivocado
No todas las páginas leen el token del mismo sitio, y si eliges el método de inyección equivocado el formulario se envía sin efecto y sin mostrar ningún error. Inspecciona la página para ver cuál de estas tres vías espera:
- El textarea oculto
g-recaptcha-response. - Una llamada a
grecaptcha.getResponse(). - Una función callback registrada en el widget.
# 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()
El callback nunca se dispara
- Cuándo ocurre: el widget trae
data-callback="onSuccess"o usagrecaptcha.render()con una propiedadcallback; rellenar el campo oculto por sí solo no hace nada. - Cómo lo corriges: localiza el nombre del callback e invócalo directamente pasándole el token, como en el ejemplo:
// 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);
}
El token caducó
- Cuándo ocurre: pasan más de ~2 minutos entre recibir el token y enviar el formulario —habitual en pipelines lentos o con muchos pasos intermedios— y Google lo rechaza.
- Cómo lo corriges: envía el formulario justo después de recibir el token; si tu proceso es lento, pide la resolución lo más cerca posible del paso de envío, no al inicio del flujo.
El widget está dentro de un iframe
Si el reCAPTCHA carga en un iframe de otro dominio, tienes que usar la URL de origen del iframe como pageurl, no la de la página principal. El error ERROR_BAD_TOKEN_OR_PAGEURL suele delatar precisamente este caso.
Solución, paso a paso:
- Abre las herramientas de desarrollador y localiza el
<iframe>que contiene el reCAPTCHA. - Copia el valor de su atributo
src. - Usa esa URL como tu
pageurlal enviar la tarea, en lugar de la URL de la barra de direcciones.
Escenario habitual: reCAPTCHA anidado en un portal público
Este patrón del iframe es el que más consultas de soporte genera entre equipos de habla hispana que hacen QA o monitoreo de trámites en portales públicos: centros de visados BLS, portales de cita previa o sedes de trámites gubernamentales. El síntoma es siempre el mismo: la sitekey parece correcta, la tarea se envía y la API devuelve un token, pero el portal lo ignora con ERROR_BAD_TOKEN_OR_PAGEURL porque enviaste el pageurl de la página contenedora, no el del iframe real. Recuerda además respetar los términos de servicio de cada portal y la normativa de protección de datos aplicable: automatiza solo flujos que tengas autorización para usar.
Preguntas frecuentes
¿Por qué el token de reCAPTCHA v2 llega pero el formulario no se envía?
Porque la página espera el token por una vía distinta a la que usaste. Muchos formularios exigen ejecutar una función data-callback en lugar de simplemente rellenar el campo oculto g-recaptcha-response. Comprueba en el widget si hay un data-callback y, si lo hay, llámalo con el token en cuanto lo recibas.
¿Cómo saco el pageurl correcto cuando el reCAPTCHA está en un iframe?
Inspecciona el DOM, localiza el <iframe> que contiene el widget y usa la URL de su atributo src, no la URL de la página principal. Si la sitekey es buena pero recibes ERROR_BAD_TOKEN_OR_PAGEURL, este desajuste entre página e iframe es casi siempre el motivo.
¿CAPCHA_NOT_READY es un error que deba corregir?
No. Solo indica que la resolución sigue en curso. Espera 5 segundos y vuelve a sondear res.php. Un reCAPTCHA v2 suele resolverse en unos 15 a 60 segundos; solo si el estado persiste más de 3 minutos conviene subir el timeout a 180 s.
¿Qué hago cuando aparece ERROR_CAPTCHA_UNSOLVABLE de forma repetida?
Envía una tarea nueva con parámetros frescos; nunca reintentes el mismo ID. Si el error persiste, revisa en este orden:
- Que la sitekey y el
pageurlcorrespondan a la página real, no a una copia en caché. - Que sea un reCAPTCHA v2 estándar y no reCAPTCHA v2 Enterprise, que requiere parámetros distintos.
¿Cuánto tiempo tengo para usar un token antes de que caduque?
Alrededor de 2 minutos, y es de un solo uso. Si tu pipeline es lento, solicita la resolución justo antes del paso de envío en lugar de al principio, para que el token llegue fresco al momento de mandar el formulario.
Ajusta tu flujo de reCAPTCHA v2 en cuatro pasos
- Verifica las entradas: extrae
googlekeydesdedata-sitekeyy usa la URL exacta de la página (revisa si hay iframes de por medio). - Confirma el método de inyección: decide si la página espera el campo oculto, un callback o ambos.
- Envía sin demora: usa el token dentro de los 2 minutos siguientes a recibirlo.
- Añade manejo de errores: apóyate en los ejemplos anteriores para capturar y tratar cada tipo de error.
Empieza a resolver reCAPTCHA v2 con el solver de CaptchaAI. Consigue tu clave API en captchaai.com/api.php.
Guías relacionadas
- Cómo resolver reCAPTCHA v2 usando la API — tutorial completo paso a paso
- Cómo resolver el callback de reCAPTCHA v2 usando la API — guía centrada en callbacks
- Errores comunes de reCAPTCHA v2 Enterprise — incidencias propias de Enterprise
- Referencia de códigos de error de CaptchaAI — listado completo de códigos