Troubleshooting

Tempo de expiração do token Cloudflare Turnstile e condições de corrida

O Cloudflare Turnstile dá cerca de 300 segundos entre gerar o token e recusá-lo. Se uma automação funciona em testes e falha em produção sem motivo aparente, o relógio é o culpado. Veja onde essa corrida contra o tempo se perde e como resolver o Turnstile no momento certo com a CaptchaAI.

Quanto tempo um token Turnstile continua válido

O token do Turnstile expira aproximadamente 300 segundos (5 minutos) depois de criado — mais folgado que os ~120 segundos do reCAPTCHA, mas ainda curto o suficiente para gerar condições de corrida. Para comparar:

  • reCAPTCHA v2/v3: ~120 segundos.
  • Cloudflare Turnstile: ~300 segundos.
  • hCaptcha: ~120 segundos.

O cronômetro começa quando a Cloudflare gera o token — não quando a CaptchaAI devolve o resultado, nem quando seu código o recebe.

Por que a corrida contra o tempo acontece

A linha do tempo abaixo mostra um fluxo típico de resolução via API:

Time 0:00  — You submit a Turnstile task to CaptchaAI
Time 0:15  — CaptchaAI begins solving
Time 0:20  — Token is generated (timer starts here)
Time 0:25  — CaptchaAI returns token to you
Time 0:25+ — Your code processes the token
Time ???   — Your code submits the token to the site

A contagem começa em 0:20; você tem até por volta de 5:20 para enviar o token. Parece bastante, até somar cada etapa de um fluxo real:

Time 0:20  — Token generated
Time 0:25  — Received by your code
Time 0:30  — Fill form fields
Time 0:35  — Navigate to next page
Time 1:00  — Handle additional dialogs
Time 2:00  — Wait for page load
Time 4:00  — Network latency spike
Time 5:30  — Submit token → EXPIRED

Cada passo é rápido; a soma é que estoura os 300 segundos. Regra prática de bolso:

  • Receba o token e envie-o em segundos, não em minutos.
  • Qualquer coisa acima de 240 s de intervalo já é risco de rejeição.

Situações que mais derrubam o token antes da hora

Três padrões respondem pela maioria dos casos de token expirado em produção:

1. Formulários com várias etapas

Fluxos com várias telas antes da confirmação final são o cenário mais comum:

Step 1: Fill personal info → Step 2: Fill address → 
Step 3: Solve CAPTCHA → Step 4: Review → Step 5: Submit

Se o CAPTCHA é resolvido na Etapa 3, mas o envio só acontece na Etapa 5, o intervalo pode passar de 5 minutos — comum em cadastros e checkouts com revisão manual.

2. Filas de processamento em lote

Resolver vários tokens de uma vez e guardá-los é o segundo padrão mais comum:

# DON'T: Solve all tokens first, then use them
tokens = []
for url in urls:
    tokens.append(solve_turnstile(url))  # Tokens age while waiting

for url, token in zip(urls, tokens):
    submit_form(url, token)  # Early tokens may be expired

Os primeiros tokens envelhecem enquanto os últimos ainda são resolvidos.

3. Nova tentativa com o mesmo token

O terceiro padrão aparece em retries mal planejados:

token = solve_turnstile(site_key, page_url)

for attempt in range(3):
    result = submit_form(page_url, token)
    if result.ok:
        break
    # BUG: Retrying with the same token — it may be expired OR already consumed

Reenviar o mesmo token raramente funciona: pode estar vencido ou já consumido.

Como evitar a expiração do token

Estratégia 1: resolver just-in-time

Peça o token só quando o fluxo estiver pronto para enviá-lo:

import requests
import time

def solve_turnstile(site_key, page_url):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "turnstile",
        "sitekey": site_key,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("Solve timed out")

# Complete all form steps FIRST
fill_personal_info()
fill_address()
navigate_to_review()

# THEN solve and submit immediately
token = solve_turnstile(site_key, page_url)
submit_form(token)  # Submit within seconds of receiving the token

Exemplo prático: uma equipe de QA autorizado com workers na região sa-east-1 (São Paulo) reduziu as falhas só ao mover a resolução do Turnstile para o último passo do fluxo.

Estratégia 2: acompanhar a idade do token

Guarde o horário de criação e verifique a validade antes de cada envio:

import time

class TimedToken:
    def __init__(self, token, created_at=None):
        self.token = token
        self.created_at = created_at or time.time()
        self.max_age = 270  # 4.5 min — safety margin from 5 min limit

    @property
    def is_valid(self):
        return (time.time() - self.created_at) < self.max_age

    @property
    def remaining_seconds(self):
        return max(0, self.max_age - (time.time() - self.created_at))

# Usage
timed_token = TimedToken(solve_turnstile(site_key, page_url))

# Check before using
if timed_token.is_valid:
    submit_form(timed_token.token)
else:
    # Solve a fresh token
    timed_token = TimedToken(solve_turnstile(site_key, page_url))
    submit_form(timed_token.token)

Estratégia 3: token novo a cada nova tentativa (JavaScript)

Em vez de reenviar o mesmo token no retry, resolva um novo a cada tentativa:

async function submitWithFreshToken(siteKey, pageUrl, formData) {
  const maxRetries = 3;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    // Always solve a fresh token for each attempt
    const token = await solveTurnstile(siteKey, pageUrl);

    const response = await fetch(pageUrl, {
      method: 'POST',
      body: JSON.stringify({ ...formData, 'cf-turnstile-response': token }),
      headers: { 'Content-Type': 'application/json' }
    });

    if (response.ok) return await response.json();

    console.log(`Attempt ${attempt + 1} failed, solving fresh token...`);
  }

  throw new Error('All attempts failed');
}

Como reconhecer um token expirado

O site raramente exibe a mensagem "token expirado". Estes sinais costumam indicar isso:

  • HTTP 403 depois de enviar o token — token inválido ou vencido.
  • Redirecionamento de volta para o formulário — falha na verificação do token.
  • Mensagem genérica "falha na verificação" — pode ser expiração, mas não é exclusivo disso.
  • A página do desafio reaparece — token rejeitado; a Cloudflare desafia de novo.

Registro para diagnóstico

Registrar os horários de criação e de envio facilita a investigação:

import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("turnstile")

token_received_at = time.time()
token = solve_turnstile(site_key, page_url)
logger.info(f"Token received, length: {len(token)}")

# ... workflow steps ...

submit_time = time.time()
age = submit_time - token_received_at
logger.info(f"Submitting token, age: {age:.1f}s")

if age > 270:
    logger.warning(f"Token may be expired (age: {age:.1f}s > 270s safety limit)")

Atualização automática do widget no navegador

Em fluxos no navegador, o widget do Turnstile renova o token sozinho antes de expirar, disparando data-expired-callback:

turnstile.render('#captcha', {
  sitekey: '0x4AAAA...',
  callback: (token) => {
    console.log('New token:', token);
  },
  'expired-callback': () => {
    console.log('Token expired — widget will auto-refresh');
  }
});

Em automações via API, sem navegador, essa renovação não existe: controlar a idade do token é tarefa do seu código.

Diagnóstico rápido: sintoma, causa e correção

  1. Funciona em testes, falha em produção — causa: fluxo de produção mais lento. Correção: resolver just-in-time, nunca com antecedência.
  2. Primeiro envio funciona, novas tentativas falham — causa: reenvio de token já consumido. Correção: resolver um token novo a cada tentativa.
  3. Falhas intermitentes em formulários longos — causa: token expira durante o fluxo. Correção: mover a resolução do CAPTCHA para a última etapa.
  4. Lote com alta taxa de falha — causa: tokens resolvidos em massa expiram antes de usados. Correção: resolver sob demanda, nunca em lote.

Perguntas frequentes

É possível aumentar a validade de um token Turnstile?

Não. O prazo é definido pela Cloudflare. Resolva um token novo quando o atual vencer.

Por que o token funciona nos testes, mas falha em produção?

Porque produção costuma ser mais lenta — fila, terceiros na página, picos de latência — e o token passa dos 300 segundos.

Meu formulário tem várias etapas — em qual delas devo resolver o CAPTCHA?

Na etapa mais próxima do envio final. Resolver o Turnstile logo no começo é o erro mais comum por trás de tokens expirados.

O widget do Turnstile também expira sozinho no navegador?

Sim, mas o próprio widget renova o token antes do vencimento. A expiração é praticamente exclusiva de integrações via API.

Artigos relacionados

Próximas etapas

Elimine tokens expirados do seu fluxo — obtenha sua chave de API da CaptchaAI e aplique a resolução just-in-time deste guia.

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