"¿Qué MCP de navegador sirve para saltarse Cloudflare?" es una pregunta viva en r/ClaudeAI, y la respuesta honesta durante la mayor parte de 2026 fue: ninguno de forma fiable, el nuestro incluido. Un benchmark de detección de bots que ejecutamos contra la v6.6.2 a mediados de septiembre recomendaba enrutar el tráfico por proxies residenciales. Lo configuramos. No hizo nada. Averiguar por qué se convirtió en seis versiones en once días, y este post es el registro de lo que cambiaron, para cualquiera que necesite hacer scraping de sitios protegidos por Cloudflare desde un MCP server sin fingir ser algo que no es.
CrawlForge MCP v6.7.0 a v6.12.0 giran en torno a una sola página: la que vuelve como un muro de desafío. La petición simple sigue ejecutándose primero y sigue costando 2 credits. Lo que cambió es todo lo que ocurre después de que la rechacen.
Tabla de contenidos
- Qué se publicó, versión a versión
- Por qué una petición simple falla en un sitio protegido por Cloudflare
- Una llamada, tres intentos: la escalera de escalado
- Un desafío resuelto sigue resuelto
- El agente reintenta por sí mismo las páginas bloqueadas
- Trae tus propios proxies, y ahora sí enrutan
- Medido contra un benchmark, no afirmado
- Lo que CrawlForge no va a hacer
- Ejecutarlo para clientes: la configuración de agencia
- Cómo actualizar
Qué se publicó, versión a versión
| Versión | Fecha | La versión en una línea |
|---|---|---|
| v6.7.0 | 2026-09-16 | proxyRotation enruta el tráfico de verdad; Camoufox deja de anunciarse como Chrome |
| v6.8.0 | 2026-09-22 | El benchmark de stealth pasa a ser npm run bench:stealth; fugas de huella digital cerradas; el motor "auto" usa Camoufox por defecto |
| v6.9.0 | 2026-09-22 | agent reintenta una página bloqueada en el navegador stealth, 8 credits + 5 por cada reintento que consigue la página |
| v6.10.0 | 2026-09-25 | Tarro de clearances: las cookies cf_clearance, __cf_bm y datadome se reproducen en el siguiente contexto stealth |
| v6.11.0 | 2026-09-26 | Un intento TLS de Chrome (impit) antes de lanzar cualquier navegador; clic en la casilla de Turnstile en Chromium; filas de auditoría de escalado |
| v6.12.0 | 2026-09-27 | Los fallbacks de error de aplicación se detectan como bloqueos suaves; CRAWLFORGE_IMPIT=off por despliegue |
No se añadió ni renombró ninguna herramienta, y ningún precio cambió salvo el techo de agent, que ahora depende de lo que haya pasado. Cada línea de arriba sale del changelog del servidor.
Por qué una petición simple falla en un sitio protegido por Cloudflare
Cloudflare puntúa una petición antes de servir la página, y un cliente HTTP de Node falla esa puntuación en tres sitios a la vez: la IP pertenece a un rango de datacenter conocido, el handshake TLS no parece el de un navegador y el interstitial necesita un JavaScript que el cliente nunca va a ejecutar. El resultado es un 403, o un 200 que no trae más que la carcasa de un desafío. La guía de stealth mode cubre las capas de detección en detalle; este post trata de lo que hace ahora el servidor cuando se topa con una.
Desde la v5.6.11, scrape informa de ese muro como success: false con blocked.vendor nombrando a Cloudflare, DataDome, PerimeterX, Akamai, Amazon o Vercel, sea cual sea el código HTTP, y no cobra nada por ello. Desde la v5.9.0, escalate: true permite que la misma llamada renderice la página una vez en el navegador stealth en lugar de devolver el bloqueo. Las seis versiones de abajo son en lo que se ha convertido esa etapa de escalado.
Una llamada, tres intentos: la escalera de escalado
Con escalate: true y el motor por defecto "auto", una sola llamada a scrape sube ahora una escalera y se detiene en el primer peldaño que devuelve la página:
- La petición simple, con el User-Agent
CrawlForge/<version>. 2 credits. Si el host bloqueó con un muro una petición en las últimas 24 horas, el MCP server se salta este peldaño en vez de repetir una petición condenada. - Un handshake TLS de Chrome a través de
impit, nuevo en la v6.11.0. Presenta la huella TLS de Chrome y sigue llevando el User-Agent honesto de CrawlForge. No arranca ningún navegador. Desde una IP residencial en la que Cloudflare bloquea la petición simple, indeed.com volvió en alrededor de un segundo. - El navegador stealth, Camoufox primero y Chromium con un aviso cuando el binario de Camoufox no está (v6.8.0). Aquí se aplica el tarro de clearances de la v6.10.0, y en Chromium un muro que sigue en pie tras la espera habitual, con un frame de
challenges.cloudflare.comen la página, recibe un clic en la casilla de Turnstile (v6.11.0).
El precio es 2 + 5 sea cual sea de los dos últimos peldaños el que consiguió la página, y una llamada que la petición simple sirvió sigue pagando 2. Una página que se topa con el muro en todos los peldaños vuelve como un bloqueo con escalated: true y no se cobra nada.
// npm install crawlforge-sdk
import { CrawlForge } from 'crawlforge-sdk';
const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });
// One call. The plain fetch runs first; only a wall triggers the rest.
const result = await client.scrape({
url: 'https://www.indeed.com/cmp/Burger-King/reviews',
formats: ['markdown', 'metadata'],
escalate: true
});
const data = result.data as {
escalated?: boolean;
stealth?: { engine: string };
content: { markdown: string };
};
// "impit" means the TLS rung got it and no browser ever launched.
console.log(data.escalated, data.stealth?.engine, data.content.markdown.length);Dos guardas viven dentro del peldaño impit. Cada salto de redirección pasa la comprobación SSRF con su propia resolución DNS, porque impit resuelve los nombres por su cuenta. Y una página con menos de 200 caracteres de texto visible sigue hacia el navegador en lugar de devolverse: quora.com responde a un handshake de Chrome con el fallback "Something went wrong" de su aplicación cliente bajo un título perfectamente normal, y la v6.12.0 trata ahora ese fallback como un bloqueo suave en todas las rutas, no solo en esta.
Una diferencia deliberada: el escalado de scrape en la API REST alojada sigue siendo solo de navegador. Medido desde la IP de datacenter de la instancia alojada, el paso impit no superó ninguno de los muros del benchmark, así que el servicio alojado funciona con CRAWLFORGE_IMPIT=off mientras que una instalación por npm lo mantiene activado.
Un desafío resuelto sigue resuelto
Antes de la v6.10.0, cada render stealth empezaba en frío. Si el interstitial de Cloudflare dejaba pasar al navegador, esa clearance moría con el contexto del navegador, y la siguiente llamada al mismo host la resolvía otra vez.
El tarro de clearances conserva exactamente tres cookies de un render que superó un muro: cf_clearance, __cf_bm y datadome. Se reproducen en el siguiente contexto stealth con el mismo motor, User-Agent y proxy, que es la identidad a la que se emitió la clearance. Eso cubre la etapa de escalado de scrape, stealth_mode, el reintento stealth del agente, browser_session y scrape_with_actions.
Medido en stackoverflow.com desde una IP residencial: la primera llamada stealth atravesó el interstitial de Cloudflare en 4,1 segundos, con las peticiones de desafío orchestrate y fo visibles en la traza. La segunda fue directa al 200 sin ninguna de las dos, en 1,6 segundos. Un segundo proceso reutilizó una clearance desde disco y cargó indeed.com con cero peticiones a la plataforma de desafíos.
Los límites importan tanto como la función:
- Nunca se conserva ninguna otra cookie. Una cookie de sesión del login de un cliente no puede llegar al contexto de otro, porque el tarro no la guarda.
- Un render que vuelve a toparse con el muro descarta las clearances de ese host, así que una clearance caducada no puede entrar en bucle.
- La caducidad es la propia de la cookie, con un tope de 24 horas. El tarro guarda como máximo 32 identidades con 200 cookies cada una.
- Persiste en
~/.crawlforge/stealth-clearance.json, modo 0600, con las claves hasheadas.CRAWLFORGE_CLEARANCE_JAR=offlo desactiva.
Se consideró un pool de perfiles persistentes de Chromium para la misma fase y se decidió deliberadamente no construirlo. Un perfil compartido conserva logins y almacenamiento de sitios, y en una instancia alojada eso se filtraría entre clientes.
El agente reintenta por sí mismo las páginas bloqueadas
Antes de la v6.9.0, la etapa de actuación de la herramienta agent ejecutaba solo la petición simple. Una página semilla con desafío se descartaba y la respuesta se montaba a partir de fragmentos de búsqueda. En nuestra propia revisión eso produjo la frase "3.3 stars, based on 3.3 reviews" para una página de Burger King en Indeed, que es lo que pasa cuando una valoración se cuela en el campo de recuento de un fragmento.
Ahora una página que se topa con un desafío, un 403 o 429, una carcasa vacía o un timeout se reintenta a través de la misma etapa de escalado que usa scrape, con la misma puerta de cumplimiento, el mismo resolutor de motor y los mismos proxies. Las URLs que nombró el llamante se reintentan primero. Una URL descubierta solo se reintenta cuando no tiene ningún fragmento de búsqueda relevante. Los rechazos, los 404 y los errores 5xx nunca se reintentan, una ejecución hace como máximo dos reintentos, y ninguno empieza con menos de 20 segundos de reloj restantes.
Con el motor Chromium, la misma prueba de Indeed leyó la propia página semilla y respondió 3.3 estrellas de 58.942 reseñas, con la evidencia marcada via: "stealth".
El precio sigue a lo que haya pasado:
| Ejecución | Credits |
|---|---|
| Sin reintento necesario, o todos los reintentos se toparon con el muro | 8 |
| Un reintento que consiguió su página | 13 |
| Dos reintentos que consiguieron sus páginas (el techo) | 18 |
El resultado informa de stealth_retries (intentos) y stealth_retries_charged (facturados). Un reintento que vuelve a toparse con el muro, o que lanza un error, es gratis. La API REST cobra lo mismo: 8 + 5 por cada reintento cobrado.
Trae tus propios proxies, y ahora sí enrutan
CrawlForge no suministra proxies. Lo que arregló la v6.7.0 es que los que tú suministras se usen de verdad. stealthConfig.proxyRotation había sido un no-op de tres maneras distintas: el proxy iba al flag --proxy-server de Chromium, que no puede llevar el user:pass con el que se emite todo proxy residencial, así que los proxies con autenticación respondían 407; la ruta de lanzamiento de Camoufox retornaba antes de construir la lista de argumentos, así que el motor Firefox corría sin proxy pidieras lo que pidieras; y la lista se leía una sola vez al arrancar, así que rotationInterval nunca podía cumplirse.
Los tres están arreglados. Los proxies son URLs corrientes (http, https, socks4, socks5, credenciales codificadas en porcentaje), se aplican por contexto de navegador para que ambos motores se autentiquen, y una entrada mal formada es un error y no una petición sin proxy en silencio. Camoufox corre ahora con sus propias funciones geoip, block_webrtc y humanize activadas, así que detrás de un proxy deriva la configuración regional, la zona horaria y la ubicación de la IP de salida y coincide con la dirección que ve el sitio.
La v6.8.0 añadió la forma a nivel de servidor, CRAWLFORGE_STEALTH_PROXIES: una lista separada por comas que usan la etapa de escalado, stealth_mode, browser_session, scrape_with_actions y el reintento del agente cuando una llamada no pasa ninguno. Un proxy en la llamada siempre gana.
La misma versión arregló un problema de identidad de Camoufox anterior a todo esto. Alrededor de dos tercios de los contextos de Camoufox habían presentado un User-Agent de Chrome sobre un motor Gecko y enviado client hints sec-ch-ua que Firefox nunca ha implementado. Un detector podía actuar sobre eso solo con las cabeceras de la petición, antes de que se ejecutara una sola línea de script. Camoufox presenta ahora su propia identidad de Firefox, sin nada con forma de Chromium inyectado encima.
Medido contra un benchmark, no afirmado
Cada número de este post sale de npm run bench:stealth, que la v6.8.0 convirtió de una tabla hecha a mano en un comando. Lanza el navegador stealth y la petición simple contra doce muros anti-bot y cinco páginas detectoras, y encabeza su matriz con el sistema operativo del host, la clase de IP de salida, el motor y las versiones de navegador, porque un resultado de Cloudflare desde una conexión residencial y uno desde un datacenter son mediciones distintas.
Medido contra él, las fugas de huella digital quedaron cerradas: navigator.webdriver devuelve false en lugar de estar borrado, nada es propiedad propia de navigator, userAgentData pierde su marca HeadlessChrome, la versión mayor de Chrome sale del binario instalado y un Web Worker responde lo mismo que el documento. Las autocomprobaciones de los detectores pasaron de una lista conocida de fallos a 19 aprobadas, 0 fallidas, 1 omitida en ambos motores. npm run bench:stealth:ci ejecuta diez de esas sondas sin ningún sitio de terceros y falla solo ante una regresión, con un control negativo que fuerza navigator.webdriver a true y debe ser detectado.
Dos hallazgos del benchmark merece la pena llevarse:
- Qué motor pasa depende de la IP de salida. Desde una conexión residencial Camoufox superó indeed.com donde Chromium falló. Desde la dirección de datacenter de la instancia alojada, dos ejecuciones encontraron exactamente lo contrario. Por eso existe
CRAWLFORGE_STEALTH_ENGINEpara fijar un despliegue, por eso el servicio alojado fija Chromium y por eso el valor por defecto de npm sigue prefiriendo Camoufox. - Una sola celda de DataDome no es un resultado. leboncoin en Chromium pasó en una ejecución y fue bloqueado una hora después desde la misma IP sin que cambiara nada entre medias.
Lo que no está cerrado se dice en el changelog en vez de disimularse. Chromium sigue filtrando HeadlessChrome desde un SharedWorker, un target al que Playwright no adjunta nada. Y el clic en Turnstile se verificó contra la sitekey de prueba de interacción forzada de Cloudflare, lo que demuestra solo el mecanismo; que un sitio real acepte el clic sigue dependiendo de la IP y la huella que puntúa.
Lo que CrawlForge no va a hacer
La palabra del que busca es "bypass". La nuestra es más estrecha, y estas versiones mantuvieron la línea:
- Nada de resolver CAPTCHAs ni de falsificar tokens de desafío. El clic en Turnstile es un único clic en una casilla que Cloudflare puso en la página, solo en Chromium. No se llama a ninguna API de tokens.
- El User-Agent es honesto en todos los peldaños. El handshake de
impitpresenta la huella TLS de Chrome y sigue identificándose comoCrawlForge/<version>. En indeed.com, el User-Agent honesto pasó 3 ejecuciones de 4 donde un User-Agent de Chrome pasó 0, así que la cabecera honesta no era lo que nos costaba la página. - Las cookies de clearance nunca se mueven entre identidades. Reproducir una cookie
cf_clearancea través deimpitse descartó, porque la cookie está ligada al User-Agent con el que se obtuvo, y reproducirla significaría enviar un User-Agent de navegador en lugar del nuestro. - robots.txt se comprueba antes de que corra ningún peldaño, contra el mismo product token
CrawlForgeque usa la petición simple. Una anulación conrespect_robots: falsese escribe en el registro de auditoría de cumplimiento. - Cada escalado se audita. Desde la v6.11.0,
scrapeconescalate, el reintento stealth del agente ystealth_modeescriben cada uno una filastealth_escalationenlogs/compliance-audit.log, después de la puerta de cumplimiento y antes de que el navegador navegue, con la URL, la herramienta, el motor resuelto y un hash truncado de la API key. Una petición rechazada no escribe ninguna.
Esa lista es la diferencia entre un scraper al que una agencia puede poner su nombre al lado y uno al que no.
Ejecutarlo para clientes: la configuración de agencia
Si ejecutas CrawlForge para varios clientes, las piezas de arriba se componen en un solo despliegue:
# Your residential or ISP proxies. CrawlForge supplies none.
CRAWLFORGE_STEALTH_PROXIES=http://user:pass@proxy-a:8000,socks5://user:pass@proxy-b:1080
# Pin the engine once you have measured which one passes from your exit IP.
CRAWLFORGE_STEALTH_ENGINE=chromium
# Leave the Chrome TLS rung on unless your exit IP is a datacenter range.
# CRAWLFORGE_IMPIT=off
# Clearances persist per engine, User-Agent and proxy; off if you would rather start cold.
# CRAWLFORGE_CLEARANCE_JAR=offDespués mide antes de prometer nada: npm run bench:stealth desde la máquina que va a hacer el trabajo, para que la matriz lleve tu clase de IP de salida y no la nuestra. El registro de auditoría te da un historial por clave de cada escalado stealth para entregárselo a un cliente que pregunte qué se descargó en su nombre, y la regla de tres cookies del tarro de clearances significa que el login de un cliente nunca queda en un contexto que reutilice el trabajo de otro.
Para la API alojada, la descripción honesta es esta: el tráfico stealth sale desde una IP de datacenter, el escalado es solo de navegador, y qué muros supera es una propiedad de esa IP. Cuando los objetivos del cliente están detrás de comprobaciones de reputación de IP, el MCP server autoalojado con tu propia lista de proxies es la configuración que mide bien.
Cómo actualizar
npm install -g crawlforge-mcp-server@latest
crawlforge --version # 6.12.0Un cliente MCP que arranca el servidor con npx coge la v6.12.0 en el siguiente reinicio. impit es una dependencia opcional con binarios precompilados; cuando no está, el escalado se comporta exactamente como en la v6.10.0. Camoufox también es opcional, necesita Node 22 por sus dependencias transitivas, y "auto" recurre a Chromium con un aviso que lo dice. Ninguna herramienta cambió de esquema ni de forma de salida.
¿Quieres ver qué supera la escalera desde tu IP? Empieza gratis con 1.scrape con escalate: true contra la página que te ha estado bloqueando y lee la referencia de la API de scrape para conocer cada parámetro que acepta la etapa de escalado.