Cloudflare Turnstile viene con tres modos de widget que controlan cómo se presentan los challenges: Managed (Cloudflare decide), Non-Interactive (solo prueba de trabajo, nunca muestra UI) e Invisible (sin contenedor de widget, se ejecuta en silencio). El modo determina lo que ve el usuario, cuánto tarda el challenge y si el widget llega a ser visible. Para la automatización, los tres modos producen el mismo resultado (un token cf-turnstile-response), pero detectarlos y resolverlos requiere entender las diferencias.
Comparación de modos
| Característica | Managed | Non-Interactive | Invisible |
|---|---|---|---|
| ¿Widget visible? | A veces | Nunca (solo spinner) | Nunca |
| ¿Se requiere elemento contenedor? | Sí | Sí | Sí (oculto) |
| ¿Se necesita interacción del usuario? | A veces (casilla de verificación) | No | No |
| ¿Challenge de prueba de trabajo? | Sí (puede intensificarse) | Sí (siempre) | Sí (siempre) |
| ¿Casilla de verificación alternativa? | Sí | No (falla en su lugar) | No (falla en su lugar) |
| Salida de token | cf-turnstile-response |
cf-turnstile-response |
cf-turnstile-response |
| Método CaptchaAI | turnstile |
turnstile |
turnstile |
| Recomendado para | Login, registro | Formularios de baja fricción | Verificación en segundo plano |
Managed mode (predeterminado)
El Managed mode permite a Cloudflare decidir el nivel de challenge por visitante. La mayoría de los usuarios pasan de forma invisible. El tráfico sospechoso ve una casilla de verificación. El tráfico muy sospechoso puede enfrentarse a un challenge más complejo.
Implementación
<!-- Managed mode (default) -->
<div class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-theme="light">
</div>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
Lo que ve la automatización
El modo administrado se adapta según las señales del solicitante:
| Reputación | El widget se representa como |
|---|---|
| Alta confianza | Pase invisible (sin interfaz de usuario visible) |
| Confianza media | Widget de casilla de verificación (haga clic para verificar) |
| Baja confianza | Desafío o bloque interactivo |
Para la automatización, el Managed mode es el más frecuente y el más variable. El widget puede estar visible o no dependiendo de las señales del navegador.
Detección en HTML
def is_managed_mode(html):
"""Check if Turnstile is using managed mode (default)."""
# Managed mode is the default — no explicit mode attribute
has_turnstile = "cf-turnstile" in html
has_explicit_mode = 'data-appearance="interaction-only"' in html or \
'data-appearance="always"' in html or \
'appearance: "interaction-only"' in html
return has_turnstile and not has_explicit_mode
Non-Interactive mode
El Non-Interactive mode nunca muestra una casilla de verificación ni ningún elemento interactivo. Ejecuta un challenge de prueba de trabajo en segundo plano y muestra solo un spinner. Si el challenge no puede completarse de forma no interactiva, falla en lugar de escalar.
Implementación
<!-- Non-interactive mode -->
<div class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-appearance="interaction-only">
</div>
O mediante la API de JavaScript:
turnstile.render('#turnstile-container', {
sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
appearance: 'interaction-only',
callback: function(token) {
document.getElementById('cf-turnstile-response').value = token;
},
});
Comportamiento
Page loads → Widget initializes
↓
Background proof-of-work runs
↓
Success → Token generated (no visible UI)
OR
Failure → Widget reports error (no fallback to checkbox)
Casos de uso del Non-Interactive mode
- Formularios de comentarios y widgets de resumen
- Suscripciones a newsletters
- Acciones de bajo valor donde la fricción debe ser mínima
- Endpoints de API con protección del lado del navegador
Invisible mode
El Invisible mode es verdaderamente invisible: no aparece ningún elemento contenedor en el viewport. El widget se ejecuta al cargar la página (o al activarse de forma programática) y produce un token sin ninguna indicación visual.
Implementación
<!-- Invisible mode — container is hidden -->
<div id="turnstile-invisible"
class="cf-turnstile"
data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg"
data-size="invisible">
</div>
O completamente a través de JavaScript:
// Programmatic invisible Turnstile
turnstile.render('#hidden-container', {
sitekey: '0x4AAAAAAAC3DHQhMMQ_Rxrg',
size: 'invisible',
callback: function(token) {
// Token ready — submit form automatically
submitForm(token);
},
'error-callback': function() {
// Challenge failed
console.error('Invisible Turnstile failed');
},
});
Dificultad de detección
El Invisible mode es más difícil de detectar porque el contenedor no tiene dimensiones visibles:
import re
def detect_invisible_turnstile(html):
"""Detect invisible Turnstile on a page."""
indicators = {
"script_loaded": "challenges.cloudflare.com/turnstile" in html,
"size_invisible": 'data-size="invisible"' in html or
"size: 'invisible'" in html or
'size: "invisible"' in html,
"api_render_call": "turnstile.render" in html,
"response_field": "cf-turnstile-response" in html,
}
if indicators["script_loaded"] and indicators["size_invisible"]:
return {"mode": "invisible", "confidence": "high"}
elif indicators["script_loaded"] and indicators["api_render_call"]:
return {"mode": "invisible_or_programmatic", "confidence": "medium"}
elif indicators["response_field"]:
return {"mode": "turnstile_present", "confidence": "low"}
return {"mode": "none", "confidence": "high"}
Extracción de sitekey en todos los modos
Independientemente del modo, se requiere la clave del sitio para resolver. Extraerlo de cualquier modo:
import re
def extract_turnstile_sitekey(html):
"""Extract Turnstile sitekey from page HTML (works for all modes)."""
# Pattern 1: data-sitekey attribute in HTML
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', html)
if match:
return match.group(1)
# Pattern 2: JavaScript render call
match = re.search(r"sitekey:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
if match:
return match.group(1)
# Pattern 3: Turnstile config object
match = re.search(r"siteKey['\"]?\s*[:=]\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", html)
if match:
return match.group(1)
return None
Resolviendo los tres modos con CaptchaAI
Los tres modos Turnstile se resuelven de forma idéntica con CaptchaAI. El modo no afecta la llamada a la API:
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_turnstile(sitekey, page_url):
"""Solve any Turnstile mode — managed, non-interactive, or invisible."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": sitekey,
"pageurl": page_url,
"json": 1,
})
task_id = submit.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Turnstile solve timed out")
# Use with any mode
token = solve_turnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
print(f"Token: {token[:50]}...")
Node.js
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveTurnstile(sitekey, pageUrl) {
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method: "turnstile",
sitekey,
pageurl: pageUrl,
json: 1,
},
});
const taskId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId, json: 1 },
});
if (result.data.status === 1) {
return result.data.request;
}
}
throw new Error("Turnstile solve timed out");
}
// Same function works for all Turnstile modes
solveTurnstile("0x4AAAAAAAC3DHQhMMQ_Rxrg", "https://staging.example.com/qa-login")
.then((token) => console.log("Token:", token.substring(0, 50)));
Solución de problemas
| Síntoma | Causa | Solución |
|---|---|---|
| Token válido pero el formulario lo rechaza | Sitekey incorrecto (diferente del widget visible) | Verificar si hay un sitekey renderizado en JavaScript |
| Widget no encontrado en HTML | Invisible mode cargado tras el renderizado inicial | Esperar a que se cargue la página completa, verificar respuestas XHR |
| Múltiples widgets Turnstile en la página | Diferentes sitekeys para diferentes formularios | Hacer coincidir el sitekey con el formulario específico |
data-size="compact" confunde la detección |
Compact es una variante de tamaño, no un modo | Compact usa Managed mode por defecto |
Atributo data-action presente |
Etiqueta de acción para análisis, no es un modo | Incluir la acción al resolver si se valida del lado del servidor |
| El token caduca antes del envío | Los tokens de Turnstile caducan en 300 s | Resolver justo antes del envío |
Preguntas frecuentes
¿El modo Turnstile afecta la resolución de CaptchaAI?
No. CaptchaAI utiliza el mismo método turnstile para los tres modos. La clave del sitio y la URL de la página son los únicos parámetros obligatorios. El modo no cambia el formato del token ni el flujo de validación.
¿Cómo sé qué modo utiliza un sitio?
Verifique el HTML para los atributos data-appearance o data-size. Si data-size="invisible" está presente, es modo invisible. Si data-appearance="interaction-only" está presente, no es interactivo. Si no se establece ninguno de los dos, es el modo administrado (el predeterminado).
¿Puede un sitio cambiar de modo dinámicamente?
Sí. Algunos sitios utilizan el modo administrado de forma predeterminada y cambian al modo no interactivo para páginas o segmentos de usuarios específicos. La clave del sitio suele permanecer igual. Vuelva a detectar siempre el modo de navegación.
¿Cuál es la diferencia en la tasa de éxito entre los modos?
CaptchaAI logra una tasa de éxito del 100% en todos los modos Turnstile. El modo solo afecta el comportamiento de cara al usuario; el desafío a nivel de API es idéntico.
Resumen
Los tres modos de widget de Cloudflare Turnstile (Managed, Non-Interactive e Invisible) controlan la experiencia del usuario pero producen el mismo token cf-turnstile-response. Para la automatización, todos los modos se resuelven de forma idéntica usando el Solucionador de Turnstile de CaptchaAI con una tasa de éxito del 100%. La diferencia clave para los desarrolladores está en la detección: el Managed mode muestra HTML visible, mientras que el Invisible mode requiere un análisis más profundo de la página para encontrar el sitekey.
Artículos relacionados
- Cloudflare Challenge vs Turnstile: cómo detectar
- Cloudflare Turnstile 403 después del token: solución
- Cloudflare Turnstile: errores y solución de problemas