Comparisons

Desafio gerenciado da Cloudflare versus desafio interativo

Se um endpoint que sempre respondia com HTTP 403 e um CAPTCHA visível começa, do nada, a devolver 503 sem nenhum widget na tela, é bem provável que o site tenha trocado o Desafio Interativo pelo Desafio Gerenciado da Cloudflare. São as duas ações de desafio que qualquer regra de WAF da Cloudflare pode disparar — e a diferença entre elas decide se a sua automação recebe um turnstile para resolver ou passa direto sem fazer nada.

O Desafio Gerenciado é a opção adaptativa: a Cloudflare avalia cada visitante e decide, caso a caso, entre deixar passar, mostrar um Turnstile leve ou exigir um desafio JavaScript completo. O Desafio Interativo é a opção legada — sempre mostra um CAPTCHA, para todo mundo, sem exceção. Este guia mostra como reconhecer cada um pelo código HTTP e pelo HTML da página, e qual método da CaptchaAI usar em cada caso.


Gerenciado x Interativo: a diferença em uma tabela

Aspecto Desafio Gerenciado Desafio Interativo
Chegou em 2021 Legado (anterior a 2021)
É adaptativo? Sim — a Cloudflare decide por visitante Não — sempre interativo
Passagem invisível? Sim (~90% dos visitantes passam sem ver nada) Não (CAPTCHA sempre visível)
Desafios que pode usar Invisível → Cloudflare Turnstile → desafio JS CAPTCHA sempre visível
Recomendado pela Cloudflare? Sim (padrão para regras novas) Não (mantido por compatibilidade)
Fricção para o usuário Baixa (a maioria nem percebe) Alta (interação obrigatória)
Código HTTP 503 403
Método na CaptchaAI turnstile ou turnstile_staging turnstile

Como funciona o Desafio Gerenciado

O Desafio Gerenciado é a ação recomendada pela própria Cloudflare. Ele usa um mecanismo de decisão para aplicar o desafio menos invasivo possível a cada visitante:

Fluxo de decisão

WAF rule triggers Managed Challenge
    ↓
Cloudflare evaluates visitor signals:
  ├─ Browser sinal de navegador quality
  ├─ IP reputation score
  ├─ TLS sinal de navegador (JA3/JA4)
  ├─ Request history
  ├─ Behavioral signals
  └─ Device capabilities
    ↓
Risk assessment → Challenge level selected:
  ├─ LOW risk → Invisible pass (no visible UI)
  ├─ MEDIUM risk → Non-interactive Turnstile (background PoW)
  ├─ HIGH risk → Interactive Turnstile (checkbox/widget)
  └─ VERY HIGH risk → JavaScript challenge page (5s wait)
    ↓
Challenge completed
    ↓
cookie_qa_validacao cookie issued

O que o visitante vê

O que aparece na tela depende só do risco calculado para aquele visitante:

  • Navegador comum, IP com boa reputação — nada acontece, passagem invisível (~90% dos casos).
  • Navegador novo, IP neutro — um spinner rápido aparece e some (~5%).
  • Sinais suspeitos — checkbox do Turnstile precisa ser marcado (~4%).
  • Sinais de alto risco — página "Verificando seu navegador..." com espera de alguns segundos (~1%).

Saída em HTML

As páginas de Desafio Gerenciado usam a plataforma de desafio da Cloudflare:

<!-- Managed Challenge page (when visible) -->
<body>
    <div id="challenge-stage">
        <div id="challenge-body-text">
            Verifying you are human. This may take a few seconds.
        </div>

        <!-- Turnstile widget (when rendered) -->
        <div class="cf-turnstile"
             data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg">
        </div>
    </div>

    <!-- Challenge platform script -->
    <script src="/cdn-cgi/challenge-platform/h/g/orchestrate/managed/v1?ray=...">
    </script>
</body>

Como funciona o Desafio Interativo (o modelo legado)

O Desafio Interativo sempre mostra um CAPTCHA visível que o visitante precisa resolver manualmente. Não existe passagem invisível: todo visitante vê e precisa concluir o desafio.

Como funciona

WAF rule triggers Interactive Challenge
    ↓
Full-page CAPTCHA served (HTTP 403)
    ↓
Visitor must interact with CAPTCHA widget
    ↓
CAPTCHA solved
    ↓
cookie_qa_validacao cookie issued

O que o visitante vê

Todo visitante recebe uma página inteira de desafio com um widget parecido com o Turnstile:

<!-- Interactive Challenge page -->
<body>
    <div id="challenge-running">
        <div class="main-wrapper">
            <h2>Please verify you are human</h2>

            <!-- Always-visible challenge widget -->
            <div class="challenge-widget">
                <!-- Checkbox + verification -->
            </div>
        </div>
    </div>
</body>

Por que a Cloudflare desaconselha o uso

O próprio fornecedor lista o Desafio Interativo como opção de última instância, pelos motivos abaixo:

  • Sempre visível — 100% dos visitantes veem o desafio, sem exceção.
  • Mais fricção — todo mundo precisa interagir, mesmo quem já é conhecido do site.
  • Mais abandono — parte dos visitantes sai em vez de completar o CAPTCHA.
  • Sem adaptação a risco — visitantes de baixo risco são desafiados do mesmo jeito que os suspeitos.
  • Questões de acessibilidade — a interação manual é obrigatória para todo mundo, sem alternativa.

Detecção: qual desafio essa página está usando?

Antes de decidir qual método da CaptchaAI chamar, o código precisa identificar o tipo de desafio pelo código HTTP e pelo HTML retornado:

import requests
import re

def identify_challenge_type(url):
    """Determine if a URL uses Managed or Interactive Challenge."""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0",
        "Accept": "text/html,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    }

    response = requests.get(url, headers=headers, timeout=15, allow_redirects=False)
    html = response.text
    status = response.status_code

    result = {
        "url": url,
        "status": status,
        "challenge_type": None,
        "cf_ray": response.headers.get("cf-ray", ""),
        "solve_method": None,
    }

    if status == 200:
        # Check for inline Turnstile widget (not a challenge page)
        if "cf-turnstile" in html:
            result["challenge_type"] = "turnstile_widget"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "none"
        return result

    if status == 503:
        # 503 indicates Managed Challenge or IUAM
        if "managed" in html or "challenge-platform" in html:
            result["challenge_type"] = "managed_challenge"
            result["solve_method"] = "turnstile"  # Managed renders as Turnstile
        elif "jschl" in html:
            result["challenge_type"] = "iuam_js_challenge"
            result["solve_method"] = "turnstile_staging"
        else:
            result["challenge_type"] = "unknown_503"
        return result

    if status == 403:
        if "challenge" in html.lower():
            result["challenge_type"] = "interactive_challenge"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "waf_block"
            result["solve_method"] = None  # Hard block, not solvable
        return result

    return result


# Usage
info = identify_challenge_type("https://protected-site.com/login")
print(f"Challenge: {info['challenge_type']}")
print(f"Solve with: {info['solve_method']}")

Como ler os sinais

Cruzando código HTTP e HTML, dá para separar os quatro casos sem ambiguidade:

  • Código HTTP — 503 no Gerenciado e no IUAM; 403 no Interativo e no bloqueio de WAF.
  • challenge-platform no HTML — presente no Gerenciado e no Interativo; ausente no IUAM e no bloqueio.
  • Caminho managed no script — só aparece no Gerenciado.
  • jschl no HTML — só aparece no IUAM, o desafio JS legado.
  • Widget sempre visível — só no Interativo.
  • Passagem invisível possível — só no Gerenciado.

Checklist antes de automatizar

  • Confirme se a página é um interstitial de desafio completo ou se o widget aparece embutido no fluxo normal do app.
  • Procure marcadores como cf-chl, contêineres do Turnstile e qualquer callback de retorno antes de decidir o caminho de tratamento.
  • Registre o resultado da detecção com a URL e o proxy usados — ajuda a perceber rápido quando o alvo muda de comportamento. Log com dados de visitantes reais? Considere a LGPD (ou o RGPD, em Portugal).

Como resolver cada tipo de desafio

Resolvendo o Desafio Gerenciado

Na maioria dos casos, o Desafio Gerenciado renderiza como um widget Turnstile. Use o método turnstile da CaptchaAI:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_managed_challenge(url, sitekey=None):
    """Solve Cloudflare Managed Challenge."""
    # If sitekey not provided, extract from page
    if not sitekey:
        import re
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 Chrome/120.0.0.0",
        }
        page = requests.get(url, headers=headers, timeout=15)
        match = re.search(
            r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page.text
        )
        sitekey = match.group(1) if match else None

    if not sitekey:
        # No visible Turnstile — try turnstile_staging method
        return solve_js_challenge(url)

    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": 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("Solve timed out")


def solve_js_challenge(url):
    """Fallback to turnstile_staging method."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile_staging",
        "sitekey": "managed",
        "pageurl": 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("Solve timed out")

Resolvendo o Desafio Interativo

O Desafio Interativo sempre mostra um widget visível. O método é o mesmo turnstile:

def solve_interactive_challenge(url, sitekey):
    """Solve Cloudflare Interactive Challenge (legacy)."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": 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("Solve timed out")

Node.js (os dois tipos)

const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveCloudflareChallenge(url, type = "managed") {
  const method = type === "js_challenge" ? "turnstile_staging" : "turnstile";
  const sitekey =
    type === "js_challenge" ? "managed" : await extractSitekey(url);

  const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method,
      sitekey: sitekey || "managed",
      pageurl: url,
      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("Solve timed out");
}

async function extractSitekey(url) {
  try {
    const response = await axios.get(url, {
      headers: { "User-Agent": "Mozilla/5.0 Chrome/120.0.0.0" },
      validateStatus: () => true,
    });
    const match = response.data.match(
      /data-sitekey=["']([0-9x][A-Za-z0-9_-]+)["']/
    );
    return match ? match[1] : null;
  } catch {
    return null;
  }
}

Com workers na região sa-east-1 da AWS (São Paulo), a passagem invisível do Gerenciado não adiciona latência perceptível. Já uma resolução via CaptchaAI soma o round-trip até o endpoint ao tempo de resolução do Turnstile — meça no seu ambiente antes de fixar um timeout curto no polling do res.php.


Sintomas e correções rápidas

Um guia rápido para o que cada combinação de código HTTP e HTML costuma significar:

  1. 503 sem nenhum widget visível → o Desafio Gerenciado passou você de forma invisível; nenhuma ação necessária, a requisição já foi aprovada.
  2. 503 com "Verificando seu navegador" → o Gerenciado foi elevado a desafio JS; use o método turnstile_staging.
  3. 403 com CAPTCHA visível → é o Desafio Interativo (legado); use o método turnstile.
  4. 403 sem nenhum desafio → bloqueio de WAF, não é um desafio solucionável; troque o IP ou o padrão de requisição.
  5. O tipo de desafio muda sem padrão aparente → o Desafio Gerenciado está reagindo aos sinais do visitante; trate tanto Turnstile quanto desafio JS no código.
  6. cookie_qa_validacao de um tipo rejeitado pelo outro → são fluxos de desafio diferentes no mesmo domínio; resolva o desafio que for apresentado, seja qual for.

Depois de cobrir esses seis sintomas, o que sobra quase sempre é migração de configuração — é o que a seção seguinte resume.

O que muda quando o site migra para o Gerenciado

A Cloudflare recomenda migrar do Desafio Interativo para o Desafio Gerenciado. Se um site que você automatiza fizer essa troca, cinco coisas mudam no seu código:

  1. Interativo → Gerenciado: a automação pode começar a passar de forma invisível (~90% de chance).
  2. HTTP 403 → 503: atualize a verificação de código de status.
  3. Sempre visível → adaptativo: o widget Turnstile pode simplesmente não aparecer no HTML.
  4. Mesma sitekey: o código de resolução na CaptchaAI continua igual.
  5. Mesma saída cookie_qa_validacao: o tratamento do cookie não muda.

Perguntas frequentes

  • Como sei se um site trocou o Desafio Interativo pelo Gerenciado? Compare o código HTTP: 403 com CAPTCHA sempre visível é Interativo; 503 — às vezes sem nenhum widget na tela — é Gerenciado. O script de detecção deste guia automatiza essa checagem.
  • Preciso mudar meu código quando a resposta passa de 403 para 503? Sim. Atualize a verificação de status e trate o caso em que o Gerenciado passa o visitante de forma invisível — a resposta chega como 200 normal, sem CAPTCHA para resolver.
  • O Desafio Gerenciado também gera o cookie_qa_validacao? Sim. Os dois tipos produzem o mesmo cookie cookie_qa_validacao, e o tratamento no código é idêntico, não importa qual desafio foi apresentado.
  • Preciso de um plano específico da CaptchaAI para resolver os dois tipos? Não. Os dois usam o método turnstile (ou turnstile_staging para o desafio JS), disponível em qualquer plano — do BASIC (US$ 15/mês, 5 threads) ao VIP-3. O que muda entre os planos é o número de threads simultâneas, não os desafios que você consegue resolver.
  • O Desafio Interativo vai ser desativado? A Cloudflare não anunciou data oficial, mas recomenda o Gerenciado para toda regra nova. O Interativo segue ativo para compatibilidade — sites migram quando quiserem.

Resumo

O Desafio Gerenciado da Cloudflare ajusta a dificuldade por visitante — de passagem invisível a desafio JavaScript completo —, enquanto o Desafio Interativo sempre exibe um CAPTCHA visível, sem exceção. Os dois produzem o mesmo cookie cookie_qa_validacao e são resolvidos com a CaptchaAIturnstile cobre a maior parte dos casos, e turnstile_staging entra para páginas de desafio JavaScript. Na dúvida sobre qual regra o site está usando, o código HTTP (503 ou 403) já responde a maior parte da pergunta.

Artigos relacionados

Os comentários estão desativados para este artigo.