¿Tu formulario protegido con CAPTCHA pasa en local pero falla en CI y no encuentras el motivo? Casi siempre el problema está en lo que el navegador envía de verdad, y ahí es donde Chrome DevTools Protocol (CDP) marca la diferencia: te conecta a Chrome a nivel de protocolo para observar cada request, confirmar el sitekey y seguir el token de extremo a extremo. Aquí combinamos CDP y CaptchaAI para diagnosticar integraciones de CAPTCHA en tus propios entornos de QA y staging.
Cuándo tiene sentido este flujo
Este enfoque sirve para diagnóstico sobre aplicaciones que controlas tú:
- staging y sandboxes propios
- pruebas funcionales y de regresión de formularios
- validación de integración de reCAPTCHA v2, Turnstile o GeeTest v3
- diagnóstico de errores de red y tiempos de espera
No está diseñado para compras reales, colas públicas ni plataformas de terceros.
Qué resuelve CDP en tus pruebas
CDP te muestra el porqué, no solo el resultado:
| Necesidad de QA | Cómo ayuda CDP |
|---|---|
| Ver qué request dispara el widget CAPTCHA | Inspección de red y eventos del navegador |
| Validar parámetros enviados al backend | Captura controlada de payloads en staging |
| Diagnosticar timeouts y reintentos | Trazabilidad de tiempos y estados |
| Verificar que el token llega al endpoint correcto | Seguimiento completo del ciclo request/response |
Conectar con CDP e inspeccionar el tráfico
Abre un canal WebSocket contra Chrome en modo de depuración remota. Este cliente localiza la pestaña activa y envía comandos:
const WebSocket = require("ws");
const http = require("http");
class CDPClient {
constructor() {
this.ws = null;
this.id = 0;
this.pending = new Map();
}
async connect(port = 9222) {
const targets = await new Promise((resolve, reject) => {
http.get(`http://127.0.0.1:${port}/json/list`, (res) => {
let body = "";
res.on("data", (c) => (body += c));
res.on("end", () => resolve(JSON.parse(body)));
}).on("error", reject);
});
const page = targets.find((t) => t.type === "page");
if (!page) throw new Error("No page target available");
await new Promise((resolve, reject) => {
this.ws = new WebSocket(page.webSocketDebuggerUrl);
this.ws.on("open", resolve);
this.ws.on("error", reject);
this.ws.on("message", (msg) => {
const parsed = JSON.parse(msg);
if (parsed.id && this.pending.has(parsed.id)) {
this.pending.get(parsed.id)(parsed);
this.pending.delete(parsed.id);
}
});
});
}
send(method, params = {}) {
return new Promise((resolve) => {
const id = ++this.id;
this.pending.set(id, resolve);
this.ws.send(JSON.stringify({ id, method, params }));
});
}
}
Lanza Chrome con --remote-debugging-port=9222 antes de conectar para acceder a los dominios Network, Runtime y Page.
Localizar el sitekey en tu página de staging
Necesitas el sitekey exacto que renderiza tu página. Evalúalo dentro del contexto real del navegador con Runtime.evaluate:
async function detectSitekey(cdp) {
const evalResp = await cdp.send("Runtime.evaluate", {
expression: `
(() => {
const node = document.querySelector('[data-sitekey]');
return node ? node.getAttribute('data-sitekey') : null;
})()
`,
returnByValue: true,
});
return evalResp.result?.value || null;
}
Usa este patrón solo en páginas de prueba que controles tú. Un sitekey null suele indicar que el widget aún no ha cargado o que apuntas a un entorno equivocado.
Enviar los datos a CaptchaAI para validar
Con el sitekey confirmado, el test envía a CaptchaAI los datos públicos del widget y recibe un token válido. Este helper hace el POST:
const https = require("https");
function postForm(url, data) {
return new Promise((resolve, reject) => {
const payload = new URLSearchParams(data).toString();
const req = https.request(
url,
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
},
(res) => {
let body = "";
res.on("data", (d) => (body += d));
res.on("end", () => resolve(JSON.parse(body)));
}
);
req.on("error", reject);
req.write(payload);
req.end();
});
}
Este ejemplo valida la integración en QA, no operaciones reales. Usa los endpoints in.php y res.php.
Un escenario práctico: QA de un alta protegida con Turnstile
Una agencia en Ciudad de México mantiene el portal de registro de un cliente y necesita comprobar, en cada despliegue, que el alta de usuarios sigue funcionando tras poner Cloudflare Turnstile delante del formulario. El equipo levanta ese formulario en staging.example.com, conecta CDP para inspeccionar el request del widget y resuelve el desafío con CaptchaAI para confirmar que el token llega al backend y lo acepta la verificación server-side.
Detecta regresiones antes de producción con un costo predecible en USD, útil para quien factura en monedas locales volátiles. Como CaptchaAI factura por thread concurrente, el plan BASIC ($15/mes, 5 threads) cubre de sobra un pipeline de QA con pocos CAPTCHA por despliegue.
Errores frecuentes y cómo resolverlos
| Problema | Causa común | Acción recomendada |
|---|---|---|
ERROR_WRONG_GOOGLEKEY |
Sitekey de otro entorno | Actualiza la sitekey de staging y repite la prueba |
ERROR_PAGEURL |
URL enviada no coincide | Usa la URL exacta del formulario bajo prueba |
| Timeouts en polling | Intervalo o carga inadecuada | Ajusta el intervalo y registra métricas por corrida |
| Token rechazado por backend | Validación server-side desalineada | Revisa la verificación en backend y logs de integración |
Configuración de navegador reproducible
Un test que pasa en local y falla en CI casi siempre delata una diferencia de configuración del navegador. Usa el mismo viewport, idioma y user-agent en todos los entornos:
from selenium import webdriver
def make_driver(headless: bool = True) -> webdriver.Chrome:
options = webdriver.ChromeOptions()
if headless:
options.add_argument('--headless=new')
options.add_argument('--window-size=1280,800')
options.add_argument('--lang=es-ES')
return webdriver.Chrome(options=options)
Mantener idénticos estos parámetros reduce el ruido y facilita comparar ejecuciones.
El ciclo de integración con CaptchaAI, paso a paso
El patrón es el mismo en cualquier framework de pruebas:
- Tu test detecta el widget de CAPTCHA en tu propia aplicación (formulario de QA, landing de staging).
- Tu test envía a CaptchaAI los datos públicos del widget (
sitekey, URL de la página, tipo de CAPTCHA). - CaptchaAI devuelve un token válido para esa página.
- Tu test inyecta ese token en el campo correspondiente y envía el formulario.
- Tu backend verifica el token con el proveedor de CAPTCHA, igual que con un usuario real.
Se aplica solo a integraciones que controlas tú, no para sortear sitios de terceros.
Qué medir en tu pipeline
Instrumenta los pasos de CAPTCHA para detectar regresiones antes de que lleguen a producción:
- Tiempo de resolución por intento — desde la solicitud a CaptchaAI hasta la entrega del token.
- Tasa de éxito por endpoint propio — verificaciones backend que pasan sobre el total.
- Distribución de errores — agrupados por código (
ERROR_*, timeouts internos, fallos de red). - Latencia extremo a extremo — render de la página, resolución del CAPTCHA y respuesta del backend.
Conserva trazas (logs, capturas, HAR) para reproducir incidentes cuando un test falle de forma intermitente.
Buenas prácticas de QA
- Prueba siempre sobre tu propia aplicación o entornos autorizados.
- Mantén una clave API de CaptchaAI separada para QA, distinta de la de producción.
- Define timeouts y reintentos razonables (
backoffexponencial) para no acumular trabajos pendientes durante caídas. - Versiona tus snapshots de configuración (sitekey, action, umbrales) junto al código de los tests.
- Revisa el changelog de tu proveedor de CAPTCHA para anticipar cambios en tu integración.
Guías relacionadas
- Cuando el navegador falla pero la API responde
- Ventanas de expiración del token en reCAPTCHA
- Probar el endpoint de resolución en formularios web
Preguntas frecuentes
¿Puedo inspeccionar el tráfico del CAPTCHA sin frenar mis tests?
Sí. CDP transmite los eventos de red por WebSocket en tiempo real, así que registras los requests sin frenar el test y revisas la traza (un HAR) después.
¿Qué tipos de CAPTCHA puedo validar con este flujo?
Depende del tipo que use tu formulario. CaptchaAI resuelve reCAPTCHA v2 y v3, Cloudflare Turnstile y Cloudflare Challenge, GeeTest v3, imagen/OCR y grid, además de BLS; CaptchaFox, Friendly Captcha y Lemin están en beta. hCaptcha y FunCaptcha no son compatibles. Consulta la documentación oficial para la lista completa.
¿Sirve esto para automatizar sitios de terceros?
No. Todo el flujo está pensado para tu propia aplicación o para entornos autorizados de QA y staging. Resolver CAPTCHA en sitios que no controlas puede infringir sus términos de servicio.
¿Cómo controlo los timeouts intermitentes en CI?
Aísla el paso de CAPTCHA en una función con reintentos controlados y backoff exponencial, y registra métricas por intento. Así distingues entre fallos de red, tiempos de espera del proveedor y errores de configuración.
Valida tus integraciones CAPTCHA en entornos propios con CaptchaAI.