Solução de Problemas

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

Um token Turnstile que funciona em testes falha na produção. A causa: expiração do token. Os tokens da catraca têm vida útil limitada e, se o seu fluxo de trabalho demorar muito entre o recebimento do token e o envio, o site o rejeitará. Veja como lidar com o tempo corretamente.

Vida útil do token

Os tokens da catraca expiram aproximadamente 300 segundos (5 minutos) após a criação. Isso é mais generoso do que os aproximadamente 120 segundos do reCAPTCHA, mas ainda surgem condições de corrida em fluxos de trabalho complexos.

Tipo CAPTCHA Vida útil do token
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 CaptchaAI o retorna para você e não quando você o recebe em seu código.

A condição da corrida

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

O relógio está contando a partir de 0:20. Você tem até aproximadamente 5h20 para enviar o token. Isso parece generoso, mas considere o que acontece em um fluxo de trabalho 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

Cenários comuns de condições de corrida

1. Formulários de várias etapas

Formulários que requerem várias páginas antes do envio final:

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

Se o CAPTCHA estiver na Etapa 3, mas o envio ocorrer na Etapa 5, o atraso entre a resolução e o envio poderá exceder 5 minutos.

2. Filas de processamento em lote

Resolvendo tokens antecipadamente e usando-os posteriormente:

# 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

3. Tentar novamente loops com tokens antigos

Reutilizando um token após um envio com falha:

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

Prevenindo a Expiração

Estratégia 1: Resolver Just-in-Time

Solicite o token somente quando estiver pronto para enviar:

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

Estratégia 2: Rastrear a Idade do Token

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: novo token na nova tentativa (JavaScript)

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');
}

Detectando tokens expirados

O site normalmente não informa explicitamente "token expirado". Procure estes sinais:

Sinal Indicação
HTTP 403 após enviar token Token inválido ou expirado
Redirecionar de volta para a página do formulário Falha na verificação do token
Mensagem de erro: "falha na verificação" Falha genérica – pode ser expiração
A página do desafio reaparece Token rejeitado, Cloudflare desafia novamente

Registro para diagnóstico

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)")

Comportamento de atualização automática do Turnstile

Em fluxos baseados em navegador, os widgets Turnstile atualizam automaticamente os tokens antes que expirem. O data-expired-callback é acionado quando um token expira:

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

Na automação somente API (sem navegador), você não se beneficia da atualização automática. Você mesmo deve gerenciar a atualização do token.

Solução de problemas

Problema Causa Correção
O token funciona em testes, mas não em produção O fluxo de trabalho de produção é mais lento Resolva just-in-time, não antecipadamente
O primeiro envio foi bem-sucedido, as novas tentativas falharam Reutilizando tokens consumidos Resolva um novo token para cada tentativa
Falhas intermitentes em formulários longos O token expira durante o fluxo de várias etapas Mova a resolução CAPTCHA para a última etapa
Trabalhos em lote têm alta taxa de falhas Os tokens resolvidos em massa expiram antes do uso Resolva tokens sob demanda, não em lotes

Perguntas frequentes

Posso estender a vida útil de um token Turnstile?

Não. A validade é definida pela Cloudflare e não pode ser modificada. Sua única opção é resolver um novo token.

Quão exato é o limite de 300 segundos?

É aproximado. A Cloudflare pode ajustar o tempo com base na configuração. Use 270 segundos (4,5 minutos) como máximo prático para uma margem de segurança.

Devo validação antecipada em staging os tokens para economizar tempo?

Somente se o seu fluxo de trabalho puder usá-los em alguns minutos. Para processamento em lote, resolva tokens sob demanda, e não antecipadamente.

Artigos relacionados

Próximas etapas

Impedir a expiração do token Turnstile —obtenha sua chave API CaptchaAIe implementar soluções just-in-time com taxa de sucesso de 100%.

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