Si la API devuelve un token válido y aun así el formulario responde "verificación fallida", el problema no está en la resolución: está en cómo enviaste la tarea. El fallo número uno es tratar un widget Enterprise como si fuera un v2 estándar. Sin enterprise=1, CaptchaAI lo resuelve como v2 normal y el backend — que verifica contra la API de Enterprise — descarta el token sin explicación.
El catálogo es corto: aquí van síntoma por síntoma, con el código que los corrige. Si dudas de la variante, empieza por cómo identificar una implementación de reCAPTCHA Enterprise.
Antes de depurar: confirma si es Enterprise o v2 estándar
Depurar la variante equivocada cuesta horas. Las diferencias:
| Característica | v2 estándar | v2 Enterprise |
|---|---|---|
| URL del script | google.com/recaptcha/api.js |
google.com/recaptcha/enterprise.js |
| Objeto JS | grecaptcha |
grecaptcha.enterprise |
| Endpoint de verificación | recaptcha/api/siteverify |
recaptchaenterprise.googleapis.com |
| Parámetro CaptchaAI | method=userrecaptcha |
method=userrecaptcha + enterprise=1 |
Parámetro data-s |
Nunca | A veces presente (token extra) |
Dos comprobaciones en la consola zanjan la duda:
typeof grecaptcha.enterprisedevuelve"object"en Enterprise,"undefined"en el estándar.- El método de envío no cambia: sigue siendo
userrecaptcha.
Fallo 1: el sitio rechaza un token que la API entregó correctamente
Síntoma: in.php responde con estado 1, res.php devuelve el token y el formulario lo rechaza.
Causa: enviaste la tarea sin enterprise=1. El token es legítimo, pero de la familia equivocada.
Solución: añade el flag:
import requests
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6LcR_RsTAAAAAFJR-JhNbC6CC42wKCbR9Hq_kVCd",
"pageurl": "https://staging.example.com/qa-login",
"enterprise": 1,
"json": 1
})
data = response.json()
task_id = data["request"]
El equivalente en Node.js:
const params = new URLSearchParams({
key: "YOUR_API_KEY",
method: "userrecaptcha",
googlekey: "6LcR_RsTAAAAAFJR-JhNbC6CC42wKCbR9Hq_kVCd",
pageurl: "https://staging.example.com/qa-login",
enterprise: 1,
json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const data = await res.json();
const taskId = data.request;
Fallo 2: falta el parámetro data-s
Síntoma: ERROR_BAD_PARAMETERS, o el token sigue rechazado pese a llevar enterprise=1.
Causa: algunas implementaciones Enterprise añaden al div un atributo data-s, un token de sesión del desafío. Si la página lo publica y no lo reenvías, la verificación falla.
Solución: inspecciona el div g-recaptcha y propaga el valor:
# Look for: <div class="g-recaptcha" data-sitekey="..." data-s="..."></div>
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"enterprise": 1,
"data-s": data_s_value, # Include if present on the page
"json": 1
})
Léelo del DOM en cada ejecución: cambia entre cargas de página.
Fallo 3: identificaste mal el script
Síntoma: el token funciona de forma intermitente.
Causa: el sitio migró, dejó ambos scripts en el HTML y clasificaste el widget al revés.
Solución: comprueba qué script y qué objeto JS renderizan el widget:
// Enterprise uses enterprise.js
// <script src="https://www.google.com/recaptcha/enterprise.js?render=SITEKEY"></script>
// Standard uses api.js
// <script src="https://www.google.com/recaptcha/api.js"></script>
// Also check the JS object:
// Enterprise: grecaptcha.enterprise.render(...)
// Standard: grecaptcha.render(...)
Errores generales que comparte con el v2 estándar
Descartado lo anterior, quedan los códigos habituales:
| Código de error | Causa | Solución |
|---|---|---|
ERROR_WRONG_USER_KEY |
Formato de clave no válido | Verifícala en captchaai.com/api.php |
ERROR_KEY_DOES_NOT_EXIST |
Clave no encontrada | Busca espacios perdidos al copiarla |
ERROR_ZERO_BALANCE |
Sin saldo | Recarga tu cuenta |
ERROR_PAGEURL |
Falta pageurl |
Envía la URL completa |
ERROR_GOOGLEKEY |
Sitekey mal formado | Extráelo otra vez de data-sitekey |
ERROR_BAD_TOKEN_OR_PAGEURL |
Sitekey y URL no coinciden | Revisa el contexto del iframe |
CAPCHA_NOT_READY |
Todavía en proceso | Espera 5 segundos y vuelve a sondear |
ERROR_CAPTCHA_UNSOLVABLE |
No se pudo resolver | Envía una tarea nueva |
Un caso habitual: portales de cita previa y trámites públicos
En portales administrativos hispanohablantes — cita previa, trámites tipo SAT, centros de visados BLS — el patrón se repite: el equipo prueba en staging contra un widget v2 estándar, todo funciona, y al pasar al portal real los tokens rebotan. La diferencia era una línea: el portal servía enterprise.js.
Detecta la variante en tiempo de ejecución, no por entorno, y respeta los términos de servicio y la normativa de protección de datos aplicable. CaptchaAI factura por threads concurrentes: BASIC ($15/mes, 5 threads) cubre el QA de un equipo pequeño y ADVANCE ($90/mes, 50 threads), pipelines en paralelo.
Flujo completo de resolución con manejo de errores
Móntalo una vez: envía, sondea y distingue "aún no está listo" de "falló de verdad".
import requests
import time
def solve_recaptcha_v2_enterprise(api_key, sitekey, page_url, data_s=None):
params = {
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"enterprise": 1,
"json": 1
}
if data_s:
params["data-s"] = data_s
response = requests.get("https://ocr.captchaai.com/in.php", params=params)
data = response.json()
if data.get("status") != 1:
raise RuntimeError(f"Submit failed: {data.get('request')}")
task_id = data["request"]
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "CAPCHA_NOT_READY":
continue
raise RuntimeError(f"Solve failed: {result.get('request')}")
raise TimeoutError("Solve timed out after 200 seconds")
token = solve_recaptcha_v2_enterprise("YOUR_API_KEY", "SITEKEY", "https://staging.example.com/qa-login")
Lo mismo en Node.js:
async function solveRecaptchaV2Enterprise(apiKey, sitekey, pageUrl, dataS) {
const params = new URLSearchParams({
key: apiKey, method: "userrecaptcha", googlekey: sitekey,
pageurl: pageUrl, enterprise: 1, json: 1,
});
if (dataS) params.set("data-s", dataS);
const submitRes = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const submitData = await submitRes.json();
if (submitData.status !== 1) throw new Error(`Submit failed: ${submitData.request}`);
const taskId = submitData.request;
for (let i = 0; i < 40; i++) {
await new Promise(r => setTimeout(r, 5000));
const res = await fetch(`https://ocr.captchaai.com/res.php?${new URLSearchParams({
key: apiKey, action: "get", id: taskId, json: 1,
})}`);
const data = await res.json();
if (data.status === 1) return data.request;
if (data.request === "CAPCHA_NOT_READY") continue;
throw new Error(`Solve failed: ${data.request}`);
}
throw new Error("Timed out after 200s");
}
El techo son 200 segundos (40 intentos por 5). Si rozas ese límite, revisa sitekey y pageurl antes que el timeout.
Preguntas frecuentes
Lo que más se pregunta sobre Enterprise:
¿Cuánto dura un token de reCAPTCHA v2 Enterprise antes de caducar?
Unos dos minutos, igual que en el v2 estándar. Envía el formulario justo después de recibirlo.
¿Puedo reutilizar un token Enterprise en varias solicitudes?
No. Es de un solo uso y va ligado al par sitekey + pageurl de esa carga.
Si los pones en cola, caducan esperando turno.
¿Cambia el precio por resolver Enterprise en lugar del v2 estándar?
No. CaptchaAI factura por threads concurrentes, con resoluciones ilimitadas dentro del plan y sin recargos por tipo de CAPTCHA.
¿Qué hago si data-s no aparece en el HTML?
Esa implementación no lo usa: omítelo. Enviarlo vacío provoca ERROR_BAD_PARAMETERS.
Vuelve a mirar tras renderizar el JS: a veces se inyecta después.
¿Sirve el mismo código para v2 estándar y Enterprise?
Sí. Cambia solo el flag; método, parámetros y sondeo son idénticos.
Lista de verificación antes de abrir un ticket
Casi todos los tickets Enterprise se cierran en uno de estos puntos.
- Confirma la variante buscando
enterprise.jsen las etiquetas<script>. - Añade
enterprise=1si el widget es Enterprise. - Comprueba
data-sen el divg-recaptcha. - Envía el token antes de los ~2 minutos.
- Verifica sitekey y
pageurl, sobre todo dentro de un iframe.
Guías relacionadas
- Distinguir una implementación Enterprise en el HTML
- Resolver reCAPTCHA v2 con la API
- reCAPTCHA v2 estándar frente a Enterprise
- Códigos de error de la API de CaptchaAI
Obtén tu clave API en captchaai.com/api.php y valida un token Enterprise contra tu staging antes de tocar producción.