--- name: detect_captcha kind: function lang: go domain: browser version: "1.0.0" purity: impure signature: "func DetectCaptcha(c *CDPConn) (detected bool, types []string, url string, err error)" description: "Detecta captchas y challenges anti-bot en la pagina actual via CDP: reCAPTCHA, hCaptcha, Cloudflare Turnstile (por iframe/widget) y el JS-challenge de Cloudflare (por texto). Solo detecta — no resuelve ni notifica. Una responsabilidad." tags: [captcha, browser, cdp, antibot, detection, perception] uses_functions: [cdp_evaluate_go_browser] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [encoding/json, fmt] params: - name: c desc: "Conexion CDP activa a una tab de Chrome de tipo 'page'. La evaluacion corre en el top frame." output: "Tupla (detected, types, url, err). detected=true si hay al menos una senal anti-bot. types es el subconjunto de senales detectadas (de: 'recaptcha', 'hcaptcha', 'turnstile', 'challenge'), siempre slice no nulo (vacio si nada). url es la location.href del top frame. err si la conexion es nula, falla el eval CDP, o el JSON resultante es invalido. Una excepcion JS en la pagina se trata como detected=false best-effort, sin error." tested: true tests: ["recaptcha detectado", "hcaptcha detectado", "turnstile detectado", "challenge por texto", "multiples senales", "ninguno", "campo error best-effort no rompe", "types ausente se normaliza a slice vacio", "json invalido devuelve error"] test_file_path: "functions/browser/detect_captcha_test.go" file_path: "functions/browser/detect_captcha.go" --- ## Ejemplo ```go // Conectar a un Chrome con CDP abierto (mismo patron que cdp_get_text) conn, err := CdpConnect(9222) if err != nil { log.Fatal(err) } defer CdpDisconnect(conn) // Tras navegar y esperar la carga, comprobar si la pagina puso un captcha detected, types, url, err := DetectCaptcha(conn) if err != nil { log.Fatal(err) } if detected { fmt.Printf("captcha detectado en %s: %v\n", url, types) // p.ej. -> "captcha detectado en https://x.test/login: [recaptcha]" } else { fmt.Println("sin captcha, seguir clicando") } ``` ## Cuando usarla Tras navegar o esperar la carga de una pagina, para saber si esta puso un captcha o challenge anti-bot antes de seguir clicando o enviando formularios. La usa el `browser_mcp` en sus handlers de navegacion para decidir el handoff humano: si `DetectCaptcha` devuelve `detected=true`, el flujo automatico se detiene y avisa para resolucion manual en vez de chocar contra el muro. ## Gotchas - **Solo top frame**: la evaluacion corre en el frame principal. Un captcha incrustado en un iframe anidado profundo cuyo `src` no matchee los patrones no se detecta. - **Iframes cross-origin**: el contenido de los iframes de reCAPTCHA/hCaptcha/Turnstile NO se lee (politica same-origin), pero SI se detectan por su `src` y por las clases del widget host (`.g-recaptcha`, `.h-captcha`, `.cf-turnstile`), que viven en el top document. - **Falsos positivos posibles**: la senal `challenge` viene de regex sobre `innerText` (p.ej. "verify you are human", "unusual traffic"). Una pagina con ese texto en otro contexto (un articulo, una FAQ sobre bots) puede dar `detected=true` sin haber captcha real. - **No detecta captchas custom**: solo cubre los proveedores listados (reCAPTCHA, hCaptcha, Turnstile) + el JS-challenge de Cloudflare. Captchas propios o de otros vendors no se reconocen. - **Depende de innerText**: la pagina debe haber pintado el body. En una tab aun cargando (`document.body` nulo o vacio) la senal `challenge` puede no dispararse — esperar con `cdp_wait_load` antes de detectar si el contenido es dinamico. - **Impura**: hace un round-trip CDP (I/O de red). Requiere conexion activa a una tab de tipo `page`.