Tutoriales de API

Cómo resolver reCAPTCHA v2 Enterprise con Node.js

Añade enterprise=1 a tu solicitud v2 de CaptchaAI: el resto del flujo en Node.js no cambia. Ese es todo el ajuste, y el que más horas cuesta descubrir. El widget es idéntico a la casilla "No soy un robot" de siempre, pero por detrás Google valida contra su backend Enterprise, más estricto y con puntuación de riesgo. Manda ese sitekey como un v2 normal y tendrás un token de buena pinta que el sitio rechazará sin explicación.

Vamos al grano, en cuatro pasos:

  1. Reconocer que estás ante Enterprise v2 y no ante un v2 corriente.
  2. Enviar la tarea desde Node.js con fetch.
  3. Sondear el resultado sin saturar la API.
  4. Inyectar el token para que el servidor lo acepte a la primera.

Antes de escribir código: qué necesitas a mano

  • Clave API de CaptchaAI, que obtienes en captchaai.com.
  • Node.js 14+, con fetch nativo o con node-fetch.
  • La URL completa de la página donde aparece el CAPTCHA.
  • El sitekey y, si existe, el action: los saca el paso 1 de una pasada.

Paso 1: confirma que es Enterprise v2 y no v2 estándar

Abre las DevTools, filtra por recaptcha en la pestaña Red y busca la solicitud de anclaje:

https://www.google.com/recaptcha/enterprise/anchor?ar=1&k=6LdxxXXxAAAAAAcX...&sa=LOGIN&...

Compara lo que ves con esta tabla antes de seguir:

Señal Enterprise v2 v2 estándar
Ruta del script /recaptcha/enterprise.js /recaptcha/api.js
URL de anclaje /enterprise/anchor /api2/anchor
Parámetro sa= Suele aparecer, es la action Ausente
enterprise=1 en tu solicitud Obligatorio No lo mandes

El k= es el sitekey en ambos casos. Mandar enterprise=1 en un v2 normal produce un token que el sitio descartará: esta comprobación de diez segundos evita el error más común del flujo.


Paso 2: envía la tarea a CaptchaAI

La solicitud va a in.php con el método userrecaptcha, el flag enterprise y el action si existe. La respuesta con status: 1 trae en request el ID de tarea del paso siguiente:

const API_KEY = "YOUR_API_KEY";

async function submitTask(sitekey, pageurl, action) {
  const params = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: sitekey,
    pageurl: pageurl,
    enterprise: "1",
    json: "1",
  });

  if (action) {
    params.set("action", action);
  }

  const response = await fetch(
    `https://ocr.captchaai.com/in.php?${params}`
  );
  const data = await response.json();

  if (data.status !== 1) {
    throw new Error(`Submit failed: ${data.request}`);
  }

  console.log(`Task submitted. ID: ${data.request}`);
  return data.request;
}

Paso 3: consulta el resultado sin machacar la API

La primera consulta va a los 20 segundos y a partir de ahí cada 5; antes solo obtendrás CAPCHA_NOT_READY. La función devuelve también el user_agent, el dato que separa una integración estable de una intermitente y que usarás en el paso 4.

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

async function pollResult(taskId) {
  await delay(20000);

  for (let attempt = 0; attempt < 30; attempt++) {
    const params = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

    const response = await fetch(
      `https://ocr.captchaai.com/res.php?${params}`
    );
    const data = await response.json();

    if (data.status === 1) {
      console.log(`Solved. Token: ${data.request.substring(0, 60)}...`);
      return {
        token: data.request,
        userAgent: data.user_agent || "",
      };
    }

    if (data.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve failed: ${data.request}`);
    }

    console.log(`Attempt ${attempt + 1}: not ready, waiting 5s...`);
    await delay(5000);
  }

  throw new Error("Solve timed out");
}

Paso 4: inyecta el token en tu formulario

El token viaja en el campo g-recaptcha-response. Si la respuesta de CaptchaAI incluyó un user_agent, mándalo en las cabeceras de la misma solicitud:

async function submitForm(token, userAgent) {
  const headers = { "Content-Type": "application/x-www-form-urlencoded" };

  if (userAgent) {
    headers["User-Agent"] = userAgent;
  }

  const response = await fetch("https://example.com/api/login", {
    method: "POST",
    headers,
    body: new URLSearchParams({
      username: "user",
      password: "pass",
      "g-recaptcha-response": token,
    }),
  });

  console.log(`Response status: ${response.status}`);
  return response;
}

Con un navegador headless en vez del POST directo, escribe el token en el textarea oculto y dispara el envío. En Puppeteer o Playwright el patrón es idéntico: extraes el sitekey, resuelves por API y devuelves el token al DOM.


Script completo, listo para pegar

Envío, sondeo y devolución del token con su User-Agent, en un solo archivo:

const API_KEY = "YOUR_API_KEY";
const SITE_KEY = "6LdxxXXxAAAAAAcXxxXxxX91xxxxxxxx8xxOx7A";
const PAGE_URL = "https://staging.example.com/qa-login";
const ACTION = "LOGIN"; // optional — omit if not in anchor URL

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

async function solveRecaptchaV2Enterprise() {
  // Submit task
  const submitParams = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: SITE_KEY,
    pageurl: PAGE_URL,
    enterprise: "1",
    action: ACTION,
    json: "1",
  });

  const submitRes = await fetch(
    `https://ocr.captchaai.com/in.php?${submitParams}`
  );
  const submitData = await submitRes.json();

  if (submitData.status !== 1) {
    throw new Error(`Submit error: ${submitData.request}`);
  }

  const taskId = submitData.request;
  console.log(`Task ID: ${taskId}`);

  // Poll for result
  await delay(20000);

  for (let i = 0; i < 30; i++) {
    const pollParams = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

    const pollRes = await fetch(
      `https://ocr.captchaai.com/res.php?${pollParams}`
    );
    const pollData = await pollRes.json();

    if (pollData.status === 1) {
      return {
        token: pollData.request,
        userAgent: pollData.user_agent || "",
      };
    }

    if (pollData.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve error: ${pollData.request}`);
    }

    await delay(5000);
  }

  throw new Error("Solve timed out");
}

(async () => {
  const { token, userAgent } = await solveRecaptchaV2Enterprise();
  console.log(`Token: ${token.substring(0, 60)}...`);
  if (userAgent) console.log(`User-Agent: ${userAgent}`);
})();

Salida esperada:

Task ID: 73849562810
Token: 03AGdBq24PBCqLmOx2V4pGHJjkR2xZ1r...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...

Errores frecuentes y cómo salir de ellos

Error Causa Solución
ERROR_WRONG_USER_KEY Formato de clave API inválido Comprueba que la clave de tu panel de control tenga 32 caracteres
ERROR_KEY_DOES_NOT_EXIST La clave no existe Verifica la clave en captchaai.com
ERROR_ZERO_BALANCE Saldo agotado Recarga tu cuenta
ERROR_BAD_TOKEN_OR_PAGEURL sitekey o URL incorrectos Extrae el valor k= de la URL de anclaje Enterprise, no del HTML renderizado
ERROR_CAPTCHA_UNSOLVABLE No se pudo resolver Confirma que el sitekey sea de Enterprise v2 y reintenta
El sitio rechaza el token User-Agent distinto Usa el user_agent que devuelve la respuesta de resolución

El reintento que ahorra incidencias

Envuelve ERROR_CAPTCHA_UNSOLVABLE en un reintento con retroceso exponencial (2 s, 4 s, 8 s), máximo tres intentos. Los fallos aislados se recuperan solos; si caen los tres, el problema es de configuración, no de carga.


Qué te va a costar esto al mes

La siguiente duda es el presupuesto. CaptchaAI cobra por threads concurrentes, no por resolución:

  • BASIC — $15/mes, 5 threads.
  • STANDARD — $30/mes, 15 threads.
  • ADVANCE — $90/mes, 50 threads.

Dentro de esos hilos las resoluciones no se cuentan una a una, y el precio no cambia según el tipo de CAPTCHA. Para quien factura en moneda local eso importa: un importe fijo en USD es presupuestable; el pago por resolución, no.


Un caso concreto: vigilar un portal de cita previa

Piensa en una gestoría que comprueba cada mañana si su acceso a un portal público sigue vivo tras un despliegue: cita previa en España, trámites del SAT en México o un panel de proveedores con reCAPTCHA Enterprise. No busca adelantarse a nadie, solo enterarse antes que sus clientes.

Ahí el script es un job programado que, en cada pasada:

  • resuelve el CAPTCHA con el flujo de los pasos 1 a 4;
  • envía credenciales de prueba y guarda el código de estado;
  • avisa al equipo solo si ese código cambia.

Los 5 threads de BASIC cubren de sobra una verificación por minuto en varios entornos. Y deja por escrito la advertencia de rigor: respeta los términos de servicio del sitio y la normativa de protección de datos aplicable —GDPR y LOPDGDD en España, LFPDPPP en México—.


Preguntas frecuentes

¿Necesito una clave API distinta para Enterprise?

No. Es la misma clave que usas para el v2 estándar; lo único que cambia es el parámetro enterprise=1.

¿Qué pasa si mando enterprise=1 en un reCAPTCHA v2 normal?

Recibirás un token, pero el sitio lo rechazará al validarlo. El flag debe coincidir con la implementación real: revisa la URL de anclaje antes de enviar la tarea.

¿Puedo reutilizar el mismo token en varias solicitudes?

No. Cada token es de un solo uso y caduca en pocos minutos: resuelve un CAPTCHA por envío de formulario y descártalo al recibir la respuesta.

¿Cuántos threads necesito para 500 formularios al día?

Muy pocos, y el cálculo es rápido:

  • 500 formularios repartidos en el día son unos 35 por hora punta.
  • A 15–30 segundos por resolución, cada thread despacha más de 100 por hora.

Los 5 threads de BASIC ($15/mes) sobran. Cambia de plan cuando sea tu pico de concurrencia, no el total diario, el que roce el límite.

¿Sirve este mismo código para otros tipos de CAPTCHA?

La estructura sí: enviar a in.php, sondear res.php, inyectar el token; cambian el method y los parámetros. Lo que puedes resolver hoy:

  • reCAPTCHA v2 y v3, incluidas sus variantes Enterprise.
  • Cloudflare Turnstile y Cloudflare Challenge.
  • GeeTest v3, imagen/OCR y texto.
  • CaptchaFox, Friendly Captcha y Lemin, en beta.

hCaptcha y FunCaptcha no son compatibles, y GeeTest v4 está anunciado como próximamente.


Empieza a resolver Enterprise v2 hoy

Consigue tu clave API en captchaai.com, añade enterprise=1 a tus solicitudes v2 y lleva el script a tu proyecto Node.js.


Guías relacionadas

Los comentarios están deshabilitados para este artículo.