Comparativas

Cloudflare Browser Integrity Check vs Challenge CAPTCHA

¿Recibes un 403 en un sitio con Cloudflare y no sabes si es cosa de tus encabezados o de un CAPTCHA? El código HTTP te lo dice: un 403 viene del Browser Integrity Check (BIC) y se corrige ajustando los encabezados; un 503 es un Challenge CAPTCHA que hay que resolver. Son dos capas independientes, y confundirlas hace perder horas.


Diferencias entre BIC y Challenge CAPTCHA

Esta tabla resume por qué cada bloqueo necesita una estrategia distinta:

Característica Browser Integrity Check Challenge CAPTCHA
Qué comprueba Solo cabeceras HTTP Comportamiento del navegador + entorno
¿Se requiere JavaScript? No (nivel de cabecera)
El usuario ve Nada (pasa) o 403 (falla) Widget de challenge o página JS
Estado HTTP en error 403 503
¿Tiene solución? No: corrige las cabeceras o se bloquea Sí, resuelve CAPTCHA
Cookie emitida No qa_validation_cookie
¿Se necesita CaptchaAI? No: corregir cabeceras de solicitud
Habilitado por defecto Sí (todos los planes de Cloudflare) No (configurado por regla)
Aplica a Cada solicitud Solo reglas WAF coincidentes

El código HTTP te orienta al instante:

  • 403 con encabezados mínimos y 200 con los de navegador: solo BIC.
  • 503: un Challenge lanzado por una regla WAF.
  • 403 con cualquier combinación: bloqueo de IP.

El BIC actúa en todas las solicitudes; el Challenge, solo cuando coincide una regla WAF. Por eso un script estable puede fallar de golpe sin que hayas tocado nada.


Browser Integrity Check (BIC): la primera capa

El BIC revisa los encabezados de cada solicitud para descartar tráfico que no parece de un navegador. Corre antes que cualquier reto de JavaScript, así que es lo primero que debes superar.

Qué señales revisa el BIC

Comprobación Qué busca Fallos habituales
Validación del User-Agent UA ausente, vacío o defectuoso python-requests/2.31, curl, wget
Orden de los encabezados Encabezados en orden inusual Bibliotecas HTTP sin navegador
Encabezados de navegador ausentes Faltan Accept, Accept-Language, Accept-Encoding Clientes HTTP mínimos
Firmas de bots conocidos UA de spammers o de escáneres Googlebot desde IP que no son de Google
IP en listas de abuso IP maliciosas conocidas IP de centros de datos en listas de bloqueo

Cómo decide el BIC

Request hits Cloudflare edge
    ↓
BIC evaluates HTTP headers:
  ├─ User-Agent present and valid?
  ├─ Required headers (Accept, Accept-Language) present?
  ├─ Header order consistent with browser?
  └─ IP not on abuse list?
    ↓
Pass → Request forwarded to origin
    OR
Fail → 403 Forbidden (no challenge offered)

Pasar el BIC con los encabezados correctos

El BIC se supera con encabezados coherentes con los de un navegador real; no interviene ningún CAPTCHA:

import requests

# ❌ FAILS BIC — minimal headers
response = requests.get("https://cloudflare-protected.com")
# User-Agent: python-requests/2.31.0
# Result: 403 Forbidden

# ✅ PASSES BIC — browser-like headers
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
              "image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
}

response = requests.get("https://cloudflare-protected.com", headers=headers)
# Result: 200 OK (passed BIC)

El mismo enfoque en Node.js

const axios = require("axios");

// Browser-like headers to pass BIC
const headers = {
  "User-Agent":
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
  Accept:
    "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,*/*;q=0.8",
  "Accept-Language": "en-US,en;q=0.9",
  "Accept-Encoding": "gzip, deflate, br",
  Connection: "keep-alive",
  "Upgrade-Insecure-Requests": "1",
  "Sec-Fetch-Dest": "document",
  "Sec-Fetch-Mode": "navigate",
  "Sec-Fetch-Site": "none",
  "Sec-Fetch-User": "?1",
};

async function fetchWithBIC(url) {
  const response = await axios.get(url, { headers });
  console.log(`Status: ${response.status}`);
  return response.data;
}

Los Challenge CAPTCHA de Cloudflare

Los Challenge se activan una vez superado el BIC. A diferencia de este, exigen ejecutar JavaScript y presentan un reto con solución.

Tipos de Challenge de Cloudflare

Tipo de desafío Cuándo se activa ¿Visible para el usuario? Método CaptchaAI
Widget de Turnstile Incrustado en la página por el desarrollador Widget en el formulario turnstile
Managed Challenge Coincidencia de reglas WAF Adaptativo (invisible/checkbox) turnstile
JavaScript Challenge Regla IUAM o WAF Página "Comprobando tu navegador" cloudflare_challenge
Interactive Challenge Alta sospecha Desafío a página completa cloudflare_challenge

Cómo fluye un Challenge

Request passes BIC check
    ↓
WAF rules evaluate bot score, IP, path
    ↓
Rule triggers CAPTCHA challenge (HTTP 503)
    ↓
Browser executes JavaScript challenge
    ↓
Challenge solved → qa_validation_cookie cookie issued
    ↓
Subsequent requests pass with cookie

Cómo saber si un bloqueo es BIC o Challenge

Para saber qué te bloquea, lanza dos solicitudes y compara los códigos:

  1. Una con encabezados mínimos, para provocar el BIC.
  2. Otra con encabezados de navegador, para superarlo.
import requests

def diagnose_cloudflare_block(url):
    """Determine if block is BIC or CAPTCHA."""
    # Intentionally use minimal headers to trigger BIC
    minimal_response = requests.get(url, timeout=15, allow_redirects=False)

    # Use browser-like headers to satisfy BIC checks
    browser_headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0",
        "Accept": "text/html,application/xhtml+xml,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
    }
    browser_response = requests.get(
        url, headers=browser_headers, timeout=15, allow_redirects=False
    )

    result = {
        "minimal_headers_status": minimal_response.status_code,
        "browser_headers_status": browser_response.status_code,
    }

    if minimal_response.status_code == 403 and browser_response.status_code == 200:
        result["diagnosis"] = "BIC only — fix headers to pass"
        result["fix"] = "Add browser-like headers"

    elif minimal_response.status_code == 403 and browser_response.status_code == 403:
        result["diagnosis"] = "IP or WAF block — not just BIC"
        result["fix"] = "Change IP or check WAF rules"

    elif browser_response.status_code == 503:
        html = browser_response.text
        if "jschl" in html:
            result["diagnosis"] = "IUAM JavaScript challenge"
            result["fix"] = "Use CaptchaAI cloudflare_challenge method"
        elif "cf-turnstile" in html or "challenge-platform" in html:
            result["diagnosis"] = "Managed/Turnstile challenge"
            result["fix"] = "Use CaptchaAI turnstile method"
        else:
            result["diagnosis"] = "Unknown Cloudflare challenge"
            result["fix"] = "Inspect page source for challenge type"

    elif browser_response.status_code == 200:
        html = browser_response.text
        if "cf-turnstile" in html:
            result["diagnosis"] = "Page loads but has Turnstile widget"
            result["fix"] = "Use CaptchaAI turnstile method for form submission"
        else:
            result["diagnosis"] = "No challenge — page accessible"
            result["fix"] = "None needed"

    return result


# Usage
diagnosis = diagnose_cloudflare_block("https://example-cf-site.com")
print(f"Diagnosis: {diagnosis['diagnosis']}")
print(f"Fix: {diagnosis['fix']}")

Diagnóstico rápido de errores

Antes de los casos completos, esta tabla cubre los síntomas frecuentes:

Síntoma Causa Solución
403 con encabezados mínimos, 200 con encabezados de navegador Solo BIC Usa encabezados similares a los de un navegador
403 con cualquier combinación de encabezados IP bloqueada o regla WAF Prueba con otra IP o salida de red autorizada
503 con página de desafío Challenge CAPTCHA (no BIC) Usa CaptchaAI
403 de forma intermitente Límite de solicitudes o basado en sesión Baja la frecuencia y mantén la sesión
Encabezados correctos pero sigue el 403 Comprobación de huella TLS (JA3) Usa curl_cffi o un navegador real

Cuatro situaciones típicas

Cuatro patrones habituales y qué hacer en cada uno.

Caso 1 — solo bloqueo BIC. Basta con encabezados de navegador:

Request with python-requests UA → 403
Request with Chrome UA → 200 ✓

Fix: Add proper browser headers. No CaptchaAI needed.

Caso 2 — BIC superado y luego CAPTCHA. Encabezados correctos, pero salta el reto:

Request with Chrome UA → 503 (challenge page)

Fix: Headers are fine. Usa CaptchaAI para solve the challenge.

Caso 3 — BIC y CAPTCHA a la vez. Las dos cosas, en orden:

Request with python-requests UA → 403 (BIC block)
Request with Chrome UA → 503 (CAPTCHA challenge)

Fix: First fix headers, then solve CAPTCHA con CaptchaAI.

Caso 4 — bloqueo de IP. No hay reto que resolver:

Request with python-requests UA → 403
Request with Chrome UA → 403

Fix: Neither BIC nor solvable challenge. IP is blocked.
Try different IP/proxy.

Un ejemplo cercano: una agencia que monitorea precios en un marketplace regional protegido por Cloudflare (tipo MercadoLibre o Amazon.es). Al principio recibe 403 en todo — es puro BIC — y lo resuelve con encabezados de navegador. Semanas después aparecen 503 en algunas rutas: se activó un Challenge por reglas WAF, y ahí entra CaptchaAI. Respeta siempre los términos de servicio y la normativa de protección de datos aplicable (GDPR/LOPDGDD, LFPDPPP).


Encabezados recomendados para el BIC

Estos encabezados dejan tu solicitud coherente con un navegador real:

CLOUDFLARE_SAFE_HEADERS = {
    # Mandatory
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",

    # Strongly recommended
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",

    # Sec-Fetch headers (modern Chrome)
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",

    # Recommended for consistency
    "Sec-Ch-Ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"Windows"',
}

Y estos disparan el bloqueo:

Encabezado Por qué falla
User-Agent: python-requests/2.31.0 Identificador de biblioteca HTTP conocido
User-Agent: curl/7.81.0 Identificador de herramienta de línea de comandos
Falta el encabezado Accept Ningún navegador omite Accept
Falta Accept-Language Todos los navegadores lo envían
User-Agent: "" (vacío) No válido: automatización evidente
User-Agent: Googlebot/2.1 desde una IP que no es de Google Identidad de bot falsa

Preguntas frecuentes

Dudas habituales sobre ambas capas:

¿Qué diferencia hay entre el 403 del BIC y el 503 de un Challenge?

El código lo dice todo. Un 403 significa que el BIC rechazó tus encabezados y no hay nada que resolver: corrige el User-Agent y las cabeceras Accept. Un 503 es un Challenge que exige ejecutar JavaScript y obtener un token.

¿Cómo distingo un bloqueo de BIC de uno por IP?

Repite la solicitud con encabezados de navegador. Si pasa a 200, era BIC. Si sigue en 403 con encabezados correctos, el problema es la IP o una regla WAF.

Si supero el BIC, ¿aún puede aparecer un CAPTCHA?

Sí. Son capas independientes: pasar el BIC solo significa que tus encabezados parecen legítimos. Aún puedes disparar un CAPTCHA por reglas WAF, puntuación de bot o modo IUAM.

¿CaptchaAI sirve para pasar el BIC?

No. El BIC no presenta un reto resoluble, así que se corrige ajustando los encabezados HTTP. CaptchaAI actúa en la otra capa: resuelve los Challenge de Cloudflare (Turnstile, JavaScript Challenge y Managed Challenge).

¿Cada cuánto conviene actualizar el User-Agent?

Mantenlo alineado con una versión reciente y real de Chrome. Un UA que apunta a una versión retirada es una señal poco natural; refréscalo al cambiar la rama estable que imitas.


Resumen

El BIC bloquea con 403 las solicitudes cuyos encabezados no parecen de un navegador; los Challenge CAPTCHA presentan tareas resolubles con 503. El BIC se arregla enviando encabezados de navegador reales, sin CaptchaAI de por medio; los Challenge sí requieren el método turnstile o el solver de Cloudflare Challenge de CaptchaAI. La regla de oro: diagnostica el bloqueo por su código HTTP, corrige encabezados para el BIC, usa CaptchaAI para los CAPTCHA y cambia de IP en los bloqueos duros.

Artículos relacionados

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