Troubleshooting

Cloudflare Turnstile 403 após envio de token: guia de correção

Token do Turnstile validado — e mesmo assim a chamada seguinte devolve 403? O problema quase nunca é o CAPTCHA: é o que acontece depois dele. Sessão recriada, cookie não reaproveitado, token enviado tarde ou no campo errado respondem pela maioria dos casos. Veja as cinco causas mais comuns, na ordem certa para descartá-las, com o código de correção.

Antes de abrir um chamado de suporte, descarte nesta ordem:

  • A mesma sessão HTTP foi usada do solve até o envio do token.
  • O token chegou ao servidor em menos de 240 segundos após ser resolvido.
  • O campo de envio é cf-turnstile-response (ou o nome que o site espera).
  • Origin e Referer batem com a página real, não com um valor genérico.
  • O IP de saída não mudou entre o solve e o envio.

Por que o Turnstile retorna 403 mesmo com token válido

Causa Probabilidade
Cookie de sessão (cookie_qa_validacao) ausente Muito comum
Token expirado antes do envio Comum
Campo de envio errado Comum
Cabeçalhos de requisição ausentes Moderado
IP diferente entre resolução e envio Moderado
Confundir o Turnstile com o desafio de página inteira Ocasional

Causas ligadas à sessão e ao token

As duas primeiras causas explicam a maioria dos 403 que aparecem logo depois do solve — o problema está em como a sessão e o token são reaproveitados, não na resolução do desafio em si.

O Turnstile grava um cookie quando o token é validado. Sem esse cookie na próxima requisição, a Cloudflare trata você como visitante não verificado. Reaproveite a mesma sessão HTTP do início ao fim.

import requests

session = requests.Session()

# Step 1: Load the page to get initial cookies
session.get("https://example.com")

# Step 2: Solve Turnstile
token = solve_turnstile(
    api_key="YOUR_API_KEY",
    sitekey="TURNSTILE_SITEKEY",
    pageurl="https://example.com",
)

# Step 3: Submit token to the validation endpoint
# This sets cookie_qa_validacao cookie
resp = session.post("https://example.com/api/verify", data={
    "cf-turnstile-response": token,
}, headers={
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://example.com",
    "Referer": "https://example.com/",
})

# Step 4: Now make your actual request WITH the session cookies
resp = session.get("https://example.com/protected-page")
print(resp.status_code)  # Should be 200 now

Causa 2: token expirado antes do envio

O token vale cerca de 300 segundos; quanto mais rápido for enviado, menor o risco de rejeição. Trate qualquer solve acima de 4 minutos como suspeito e resolva de novo.

import time

# Solve
start = time.time()
token = solve_turnstile(...)
solve_time = time.time() - start

# Check if token is still fresh
if solve_time > 240:  # > 4 minutes is risky
    print("Token may be too old, solving again...")
    token = solve_turnstile(...)

# Submit immediately
submit_token(token)

Causas ligadas à requisição e ao ambiente

As três causas seguintes aparecem quando a sessão já está correta, mas a requisição em si não bate com o que o site espera.

Causa 3: campo de envio errado

Cada site espera o token em um lugar diferente: campo oculto, cabeçalho customizado ou corpo JSON. Inspecione a chamada real antes de escrever código.

# Some sites use a hidden form field
data = {
    "cf-turnstile-response": token,
    "username": "user",
    "password": "pass",
}

# Some sites use a custom header
headers = {
    "X-Turnstile-Token": token,
}

# Some sites use JSON body
json_data = {
    "turnstileToken": token,
    "email": "user@example.com",
}

Como achar o campo certo: DevTools → aba Rede → complete o desafio manualmente → veja o nome do campo no corpo da requisição de envio.

Causa 4: cabeçalhos ausentes ou inconsistentes

A Cloudflare compara os cabeçalhos com os de um navegador real. Faltar Origin, Referer ou Sec-Fetch-* já basta para um 403, mesmo com cookie e token corretos.

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Origin": "https://example.com",
    "Referer": "https://staging.example.com/qa-login",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
}

session.headers.update(headers)

Causa 5: confundir o Turnstile com o desafio de página inteira

O widget do Turnstile (a caixinha visível) e a tela de desafio que a Cloudflare mostra em modo mais agressivo são coisas diferentes, com métodos distintos na CaptchaAI.

Recurso Turnstile Cloudflare Turnstile em staging
Widget Caixa de seleção visível na página Tela de desafio de página inteira
Método CaptchaAI turnstile turnstile_staging
Campo token cf-turnstile-response N/A (baseado em cookie)

Tela de carregamento em vez do checkbox? Troque para method=turnstile_staging — vale descartar essa causa antes de seguir.


Caso real: 403 intermitente em QA distribuído (São Paulo ↔ origem)

Um time de QA com workers em sa-east-1 (São Paulo) recebia 403 em 1 a cada 5 execuções, sempre na segunda chamada. O worker que resolvia o desafio saía por um IP e o envio do formulário saía por outro, porque o pool de saída trocava de endereço a cada requisição — a Cloudflare bloqueava a divergência. A correção: fixar o mesmo IP do início ao fim da sessão. Trocar de IP no meio do fluxo derruba tanta sessão quanto cookie ausente.

Sinais de que você está no mesmo caso:

  • O primeiro envio do token funciona; a chamada seguinte falha.
  • O erro é intermitente, não em toda execução.
  • Os workers rodam atrás de um pool de saída com múltiplos IPs.

Exemplo completo: do sitekey até a página protegida

Sitekey, resolução via CaptchaAI, polling e envio do token na mesma sessão — a base das correções acima.

import requests
import time
import re


def solve_turnstile_and_access(target_url, api_key):
    """Complete flow: solve Turnstile and access protected page."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    })

    # Load page, get cookies and sitekey
    resp = session.get(target_url)
    match = re.search(r'data-sitekey="([^"]+)"', resp.text)
    if not match:
        raise RuntimeError("Turnstile sitekey not found")

    sitekey = match.group(1)

    # Solve via CaptchaAI
    submit_resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": target_url,
        "json": 1,
    }, timeout=30)
    task_id = submit_resp.json()["request"]

    # Poll
    for _ in range(12):
        time.sleep(5)
        poll = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = poll.json()
        if data.get("status") == 1:
            token = data["request"]
            break
    else:
        raise TimeoutError("Solve timeout")

    # Submit token using the same session
    form_resp = session.post(target_url, data={
        "cf-turnstile-response": token,
    }, headers={
        "Origin": f"https://{requests.utils.urlparse(target_url).netloc}",
        "Referer": target_url,
    })

    return session, form_resp


# Usage
session, resp = solve_turnstile_and_access(
    "https://staging.example.com/qa-login",
    "YOUR_API_KEY",
)
# session now has valid cookies for subsequent requests

Tabela rápida de diagnóstico

Problema Causa Correção
403 apesar do token válido Sessão não reaproveitada Use a mesma sessão em todas as requisições
403 só nas páginas seguintes cookie_qa_validacao não foi salvo A validação do token precisa devolver esse cookie
Funciona uma vez, depois falha Cookie expirou Resolva de novo
Sempre 403 Página de desafio inteira, não o widget Troque para turnstile_staging

Perguntas frequentes

Um 403 depois do Turnstile é sempre bug no meu código?

Não necessariamente. A maior parte vem de sessão não reaproveitada ou cookie perdido entre chamadas, não de erro na resolução. Descarte a Causa 1 primeiro.

Preciso reenviar o token em cada requisição seguinte?

Não. O token é de uso único; depois de liberar o cookie de sessão, é o cookie que precisa acompanhar cada requisição protegida.

Normalmente entre 30 minutos e 24 horas, conforme o site. Se as chamadas passarem a falhar, resolva o Turnstile de novo em vez de reaproveitar o cookie antigo.

Preciso de proxy para resolver o Turnstile?

Na maioria dos casos não — o CaptchaAI resolve em menos de 10 segundos com alta taxa de sucesso, mesmo sem proxy. Use um só se o site checar consistência de IP, e mantenha o mesmo durante toda a sessão (veja o caso de São Paulo acima).

O 403 pode vir do site, não do Turnstile?

Sim. Algumas aplicações aplicam regras de WAF adicionais depois do desafio — nesse caso o 403 continua mesmo com sessão e cookie corretos. Descarte as cinco causas acima antes de investigar regras específicas do site.


Guias relacionados


Corrija o 403 de uma vez — resolva o Turnstile com a CaptchaAI.

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