Cómo solucionar el error "Enable JavaScript and cookies to continue"
Este mensaje aparece cuando Cloudflare (u otro proxy de seguridad similar) bloquea la solicitud porque detecta que el navegador no cumple con los requisitos mínimos de seguridad: JavaScript deshabilitado o cookies bloqueadas. No es un error de tu código frontend, sino un bloqueo de capa de red/proxy.
🔍 Raíz técnica
Cloudflare ejecuta un JavaScript challenge (desafío de validación) antes de permitir el tráfico al servidor. Si el navegador no puede ejecutar JS o no acepta cookies (necesarias para mantener el estado del desafío), muestra este mensaje. Ocurre comúnmente en:
- Pruebas automatizadas (Selenium, Playwright, Puppeteer) sin configuración adecuada.
- Navegadores headless con JS deshabilitado por defecto.
- Extensiones que bloquean JS o cookies (uBlock Origin, Privacy Badger, etc.).
- Configuraciones de seguridad estrictas en navegadores corporativos.
✅ Pasos para solucionarlo
1. En desarrollo local (navegador humano)
- Asegúrate de que JavaScript esté habilitado.
- Desactiva temporalmente extensiones de privacidad (uBlock, Ghostery, etc.).
- Verifica que las cookies estén permitidas para el dominio (ajustes → privacidad → cookies y datos de sitios).
- Prueba en modo incógnito (sin extensiones ni cache).
2. En pruebas automatizadas (Puppeteer/Playwright/Selenium)
📌 Solución definitiva para Puppeteer (Node.js)
import { chromium } from 'playwright'; // o 'puppeteer'
const browser = await chromium.launch({
headless: true,
args: ['--disable-features=IsolateOrigins,site-per-process']
});
const context = await browser.newContext({
javaScriptEnabled: true,
permissions: ['geolocation', 'notifications'], // opcional
httpCredentials: { username: '', password: '' } // si aplica
});
const page = await context.newPage();
// Opcional: forzar cookies y localStorage
await context.addCookies([{
name: 'cf_clearance',
value: 'dummy-value', // solo para evitar rechazo inicial (no recomendado en producción)
domain: '.tudominio.com',
path: '/',
expires: Math.floor(Date.now() / 1000) + 3600
}]);
await page.goto('https://tudominio.com', { waitUntil: 'networkidle' });
📌 Solución para Playwright con bypass de Cloudflare (recomendado)
import { chromium } from 'playwright';
const browser = await chromium.launch({
headless: false, // Cloudflare detecta mejor headless=true
args: ['--disable-blink-features=AutomationControlled']
});
const context = await browser.newContext({
viewport: { width: 1280, height: 720 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
javaScriptEnabled: true,
permissions: ['geolocation', 'notifications']
});
const page = await context.newPage();
// Evitar detección de automation
await page.addInitScript(() => {
delete navigator.__proto__.webdriver;
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3] });
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
});
await page.goto('https://tudominio.com', { waitUntil: 'domcontentloaded' });
// Esperar a que Cloudflare resuelva el challenge (si no se resuelve automáticamente)
await page.waitForSelector('#challenge-form', { state: 'detached', timeout: 15000 });
⚠️ Nota crítica: Si el sitio usa Cloudflare Under Attack Mode o Managed Challenge, no hay solución 100% automatizada estable. Cloudflare usa fingerprinting avanzado (canvas, WebGL, WebRTC, etc.). En casos extremos, usa un proxy con navegador real (Selenium + ChromeDriver + headless=false + delay人工).
3. En producción (backend)
-
Si tú controlas el servidor detrás de Cloudflare:
- Añade el IP del cliente a la lista de Exclusions en Cloudflare (panel → Firewall → Tools → Add IP to Exclusions).
- O desactiva el Challenge para rutas específicas (ej.
/api/*) en Firewall Rules:
(http.request.uri.path contains "/api") and ip.src ne 192.168.0.0/16→ Esto deshabilita el desafío para esas rutas.
🧠 Pro-tip
-
Nunca confíes en
cf_clearancemanual: Cloudflare lo invalida tras ~15 minutos y usa session binding (vincula el token a tu fingerprint). Intentar reutilizarlo genera403 Forbidden. -
Usa
waitUntil: 'domcontentloaded'en lugar de'networkidle'en headless: Cloudflare inyecta JS dinámicamente ynetworkidlepuede disparar antes de que termine el challenge. -
Si usas Puppeteer, evita
headless: 'new'(Chrome 112+): tiene más detección de automation. Usaheadless: truecon--disable-blink-features=AutomationControlled.
✅ Verificación final: Abre DevTools → Network tab → filtra por js. Si ves una solicitud a /cdn-cgi/challenge-platform/... y termina con 200 OK, el challenge se resolvió. Si el HTML contiene <div id="challenge-error-text">, el bloqueo persiste.
Top comments (0)