AntiDetect
Funciones Tecnología Precios Para quién
Docs Blog FAQ
Idioma
EnglishItalianoDeutschEspañolРусский
Descargar

Chrome headless es un callejón sin salida

El nuevo headless cerró la brecha que abrió el viejo. No cerró la que hay debajo. Si sigues eligiendo entre headless y headful, estás optimizando la variable equivocada — y hay una tercera opción que no cuesta casi nada.

Dos modos headless, una sola reputación

Hasta Chrome 112, --headless significaba el headless viejo: una ruta binaria aparte que no era realmente Chrome. Tenía su propio user agent con la cadena HeadlessChrome, sin soporte de extensiones, sin chrome.runtime, sin lista de plugins y con una ruta de renderizado que se saltaba buena parte de la cadena real. Detectarlo era una sola línea.

Chrome 112 trajo el nuevo headless (--headless=new, y desde Chrome 132 simplemente --headless). Es el navegador de verdad, solo que sin dibujar la ventana. Las extensiones funcionan, la lista de plugins está poblada, chrome.runtime existe y el user agent ya no se anuncia. Cerró casi todas las señales que filtraba el modo antiguo.

La reputación se quedó igualmente, y en buena parte con razón. El nuevo headless quitó las pistas fáciles. Lo que no quitó es la capa que hay debajo.

Lo que todavía lo delata

SwiftShader, el que acaba la sesión

La señal más fiable de todas, y con la que tropieza casi todo el mundo. Sin GPU — que es el estado normal de un servidor —, Chrome recurre a la rasterización por software, y WebGL informa:

UNMASKED_VENDOR_WEBGL   → "Google Inc. (Google)"
UNMASKED_RENDERER_WEBGL → "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device ...))"

Ese par existe en cero dispositivos de consumo. No «rara vez»: cero. Nadie navega por Instagram con renderizado por software. No es una señal probabilística que sube una puntuación; es categórica y termina la sesión.

Es también el motivo de que --disable-gpu sea tan mal consejo en este caso de uso. El flag se copia sin parar de hilos de resolución de problemas en Docker donde arregla un fallo, y fuerza exactamente el recurso anterior.

La ventana que no está

Headless igualmente tiene que inventarse una ventana, y el invento se nota. outerWidth y outerHeight suelen coincidir con innerWidth y innerHeight, porque no hay cromo que descontar — un Chrome de escritorio real tiene unos 16 píxeles de diferencia horizontal y de 85 a 90 de vertical. screenX y screenY se quedan a cero. screen.availHeight es igual a screen.height, lo que significa que en esa máquina no existe ninguna barra de tareas ni dock.

Nunca se mueve nada

Sin movimiento de ratón, sin inercia al desplazar, sin focus ni blur al cambiar de ventana, sin visibilitychange cuando una pestaña pasa a segundo plano. Cloudflare Turnstile y sus pares vigilan esto de forma continua, no como una comprobación única. Una sesión con fingerprint limpio y cero eventos de entrada es una sesión que ha pasado todas las pruebas estáticas y ha fallado la única dinámica.

La pila de debajo

Headless no cambia los fingerprints de TLS ni de HTTP/2 — y eso es una buena noticia de verdad, porque una build real de Chromium te da handshakes de Chrome reales en cualquier caso. Tampoco cambia la superficie de CDP, que es donde de verdad se pilla la automatización. Cambiar de modo no mueve ninguna de las dos.

Cuatro capas. Headless arregla una y rompe otra; a las dos de debajo no las toca.

Por qué dejaron de funcionar los plugins stealth

puppeteer-extra-plugin-stealth y sus descendientes aplican una tanda de parches JavaScript al inicio del documento: ocultar webdriver, poblar navigator.plugins, falsear chrome.runtime, etcétera. En 2019 con eso solía bastar.

Ahora no, y por una razón estructural más que de mantenimiento. Cada parche es un override de JavaScript, y los overrides de JavaScript tienen una forma. Los getters nativos se convierten en cadena como [native code]; los sustitutos no. Las propiedades del prototipo no aparecen como propiedades propias; los sustitutos sí. Y ningún script a nivel de página llega al ámbito de un Web Worker, así que cualquier valor parcheado en el hilo principal se contradice con la copia del worker.

Los benchmarks de detección publicados en 2026 informan de una identificación casi total de las sesiones con plugins stealth: un proveedor sitúa Playwright puro en el 98,2 % y las sesiones comerciales browserless en modo stealth en el 100 %, con tasas de falsos positivos por debajo del 1 %. Esas cifras vienen de una empresa que vende detección y deben leerse con eso en mente, pero la dirección no está en discusión.

Los plugins no están mal escritos. Están trabajando en una capa que no puede expresar la respuesta.

La opción que no está en el menú

El planteamiento «headless o headful» esconde la elección que de verdad funciona: Chrome headful sobre una pantalla virtual.

En Linux, ejecuta Xvfb — un servidor X real que renderiza en memoria en vez de en un monitor. Chrome arranca sin ningún flag --headless. Es un navegador completo, dibujando una ventana completa, con renderizado GPU real si el anfitrión tiene GPU. No hay modo headless que detectar porque no hay modo headless.

Xvfb :99 -screen 0 1920x1080x24 &
DISPLAY=:99 google-chrome --window-size=1920,1080

Qué arregla esto: la señal de SwiftShader (con GPU presente), las señales de geometría de la ventana, la cromo que falta, availHeight y toda la clase de pistas del tipo «aquí no hay pantalla». Qué no arregla: las fugas de CDP y el comportamiento. Eso requiere trabajo aparte.

El coste son unas pocas decenas de megabytes de RAM por instancia y una línea en tu script de aprovisionamiento. Comparado con mantener un conjunto de parches stealth contra un blanco móvil, es casi gratis.

Cuándo headless sigue siendo lo correcto

Nada de esto hace inútil a headless. Lo convierte en la herramienta equivocada para una tarea concreta.

Headless va bien para: pruebas internas, generación de capturas y PDF, rastrear tus propias webs, hacer scraping de sitios sin defensa antibots, pipelines de CI, comprobación de enlaces, monitorización de disponibilidad. Allí donde nadie intenta identificarte, headless es más rápido y más ligero y deberías usarlo.

Headless es la herramienta equivocada para: cualquier cosa detrás de Cloudflare, Akamai, DataDome o PerimeterX; cualquier cosa que implique una cuenta con sesión iniciada en una plataforma a la que le importa; cualquier cosa donde que te clasifiquen como automatización tenga un coste.

La distinción no es de sofisticación técnica. Es si hay un adversario.

Un diagnóstico corto

Si quieres saber dónde está tu configuración actual, cuatro comprobaciones ordenadas por cuánto te dicen:

  1. Renderizador WebGL. Lee UNMASKED_RENDERER_WEBGL. Si menciona SwiftShader, para y arregla eso antes que nada; lo demás no importa.
  2. Geometría de la ventana. outerHeight - innerHeight debería rondar los 85 a 90 en Chrome de escritorio, y screen.availHeight debería ser menor que screen.height.
  3. CreepJS. Cárgalo y lee las secciones de headless y de detección de mentiras. Es directo con lo que encuentra.
  4. Un objetivo real. Carga un sitio que de verdad te importe y mira si te salta un desafío. Toda prueba sintética es un sucedáneo de esta.

Pasa las mismas cuatro con un navegador que manejes a mano en la misma máquina. Las diferencias entre ambas listas son tu lista de tareas.

Headful, siempre

Los perfiles de P8 se ejecutan como ventanas reales con renderizado GPU real. La automatización los conduce como lo haría una persona, sin ningún modo headless que ocultar.

Empieza gratis
Todos los artículos Siguiente: a WebRTC le da igual tu proxy