Troubleshooting

Erros do Cloudflare Turnstile e como resolvê-los

Se o CaptchaAI devolve um token do Turnstile mas a página continua recusando o envio, o problema quase nunca está no serviço de resolução. Ele está em três coisas que você controla: a sitekey que capturou, o pageurl que enviou e o campo onde injetou o token. Acerte esses três pontos e a maioria das falhas do Turnstile desaparece.

O CaptchaAI resolve o Turnstile com alta taxa de sucesso em menos de 10 segundos. Portanto, quando a integração quebra, vale começar a investigação pelos parâmetros da requisição e pela forma como você aplica o token retornado — não pelo serviço.

Um exemplo comum: um time de QA em São Paulo testa o formulário de login em staging.example.com, o envio à API funciona, o token volta, mas a página recarrega sem entrar. Na quase totalidade desses casos, o culpado é o pageurl levemente diferente ou o token indo para o campo errado. Este guia percorre cada etapa onde isso acontece.


Antes de tudo: é o widget Turnstile ou o desafio de página inteira?

Muitas integrações falham porque tratam dois produtos diferentes da Cloudflare como se fossem um só. Vale confirmar qual deles está na sua frente antes de depurar qualquer código de erro, porque o método e a integração mudam por completo:

Sinal Widget Turnstile Desafio de página inteira
O que você vê Widget embutido na página (checkbox ou invisível) Tela de verificação da Cloudflare ocupando a página toda
O que a CaptchaAI devolve Um token para injetar no formulário Um cookie de validação
Método da API turnstile cloudflare_challenge
Precisa de proxy? Opcional Sim (obrigatório)

Se o que aparece é uma tela de verificação de página inteira (e não um widget embutido), este guia não é o seu ponto de partida: você precisa do solucionador de desafios de página inteira da Cloudflare, que devolve um cookie de validação e exige um proxy. O restante do artigo trata do widget Turnstile e do token que ele gera.


O que torna o Turnstile diferente

Três características do Turnstile explicam a maioria dos problemas que você não vê em outros tipos de CAPTCHA.

O pageurl precisa ser exato

Os tokens do Turnstile ficam fortemente atrelados ao contexto da página. Nas telas de verificação de página inteira da Cloudflare, usar o URL errado — mesmo que seja apenas um caminho ligeiramente diferente — faz o token ser rejeitado. Não basta o domínio estar certo; o caminho e os parâmetros de consulta também contam.

O token tem dois caminhos de aplicação

O token retornado pode ser aplicado de duas formas, e escolher a errada falha em silêncio:

Método Quando usar
Campo oculto — insira em cf-turnstile-response (e, às vezes, em g-recaptcha-response) Quando a página usa um formulário padrão com um input oculto
Função de callback — chame a função definida em turnstile.render() ou em data-callback Quando a página usa validação programática em vez de um formulário

Os tokens são de uso único

Um token do Turnstile só pode ser verificado uma vez. Se a sua automação o enviar duas vezes por engano, ou se houver uma condição de corrida, a segunda tentativa falha.


Onde os erros do Turnstile acontecem

Antes de olhar códigos de erro, mapeie a etapa. Toda falha do Turnstile cai em uma destas três:

  1. Etapa de envio — sua requisição a in.php é recusada antes mesmo de a tarefa entrar na fila.
  2. Etapa de consulta — a tarefa foi aceita, mas o polling em res.php falha ou estoura o tempo limite.
  3. Etapa de validação — a API devolve um token válido, mas a página de destino o rejeita.

Se você não sabe em qual etapa a falha vive, está adivinhando a correção. Identifique a etapa primeiro; as seções abaixo detalham cada uma.


Erros na etapa de envio

Estes aparecem ao enviar a tarefa para https://ocr.captchaai.com/in.php — a requisição é recusada antes de a tarefa entrar na fila. Localize o código na tabela e aplique a correção:

Erro Causa Correção
ERROR_WRONG_USER_KEY Chave de API com formato incorreto (deve ter 32 caracteres) Confira a chave em captchaai.com/api.php
ERROR_KEY_DOES_NOT_EXIST Chave bem formatada, mas sem conta ativa vinculada Abra o painel e confirme que a conta está ativa e a chave está correta
ERROR_ZERO_BALANCE Sem threads livres no seu plano Aguarde a liberação das threads, reduza a simultaneidade ou faça upgrade de plano
ERROR_PAGEURL O parâmetro pageurl está ausente Informe o URL completo — protocolo, domínio e caminho (exemplo abaixo)
ERROR_BAD_PARAMETERS Parâmetro obrigatório ausente ou malformado Confira todos os campos obrigatórios da tabela abaixo
Respostas em HTML ou 500/502 Erro temporário no servidor Aguarde de 5 a 10 segundos e tente novamente

No caso do ERROR_PAGEURL, o valor precisa trazer o endereço inteiro, e não apenas o domínio:

pageurl=https://staging.example.com/qa-login

Já o ERROR_BAD_PARAMETERS quase sempre recai sobre um destes campos obrigatórios do Turnstile:

Parâmetro Tipo Obrigatório Descrição
key String Sim Sua chave de API da CaptchaAI
method String Sim Deve ser turnstile
sitekey String Sim A sitekey do widget Turnstile
pageurl String Sim URL completo da página

Estes são opcionais, mas úteis quando a página exige proxy ou uma action específica:

Parâmetro Tipo Descrição
action String Valor de data-action ou do parâmetro action em turnstile.render()
proxy String Formato: login:password@IP:PORT
proxytype String HTTP, HTTPS, SOCKS4, SOCKS5

Como localizar a sitekey do Turnstile

A sitekey é o parâmetro mais errado com frequência. Há três lugares onde encontrá-la.

Opção 1 — o atributo data-sitekey:

<div class="cf-turnstile" data-sitekey="0x4AAAAAAAB1example"></div>

Opção 2 — uma chamada turnstile.render():

turnstile.render('#captcha-container', {
  sitekey: '0x4AAAAAAAB1example',
  callback: function(token) {
    document.getElementById('cf-turnstile-response').value = token;
  }
});

Opção 3 — interceptar a chamada de renderização (avançado):

Se a sitekey for carregada dinamicamente, redefina turnstile.render antes de o widget inicializar para capturar os parâmetros:

// Inject this before the Turnstile script loads
const originalRender = window.turnstile.render;
window.turnstile.render = function(container, params) {
  console.log('Sitekey:', params.sitekey);
  console.log('Action:', params.action);
  return originalRender.call(this, container, params);
};

Erros na etapa de consulta de resultado

Estes aparecem durante o polling em https://ocr.captchaai.com/res.php. Um aviso primeiro: o CAPCHA_NOT_READY não é um erro — significa apenas que a resolução ainda está em andamento (no Turnstile, costuma levar menos de 10 segundos na CaptchaAI). Os demais códigos, sim, pedem uma ação:

Código Causa Correção
CAPCHA_NOT_READY Resolução ainda em andamento (não é erro) Aguarde 5 segundos e consulte novamente
ERROR_WRONG_ID_FORMAT O ID do CAPTCHA contém caracteres não numéricos Use o ID exato retornado por in.php, sem nenhuma alteração
ERROR_WRONG_CAPTCHA_ID O ID não corresponde a nenhuma tarefa enviada Confirme que está consultando o ID que veio na resposta do envio
ERROR_EMPTY_ACTION Falta o parâmetro action na requisição de consulta Inclua sempre action=get (veja o formato abaixo)
ERROR_CAPTCHA_UNSOLVABLE Falha na resolução — possível sitekey errada ou página não suportada Confira a sitekey, refaça a requisição e tente de novo
ERROR_INTERNAL_SERVER_ERROR Problema no servidor Aguarde 10 segundos e tente novamente

Uma requisição de consulta bem formada, com action=get e json=1, fica assim:

https://ocr.captchaai.com/res.php?key=YOUR_KEY&action=get&id=CAPTCHA_ID&json=1

Observação: use json=1 na consulta para receber respostas no formato {"status": 1, "request": "<token>"}. Sem esse parâmetro, o endpoint devolve texto puro, como OK|<token> ou CAPCHA_NOT_READY. As duas formas funcionam — escolha a que for mais simples de tratar no seu parser.


Quando a página recusa um token válido

Estas são as falhas mais difíceis de depurar: a API devolve um token com sucesso, mas a página de destino o rejeita. Percorra as quatro causas na ordem abaixo.

Falha 1: token inserido no campo errado

Sintoma: o formulário é enviado, mas a página exibe erro de validação ou apenas recarrega.

As páginas com Turnstile podem esperar o token em campos diferentes:

  • cf-turnstile-response — o input oculto principal do Turnstile
  • g-recaptcha-response — algumas páginas o usam como alternativa

Correção: inspecione o formulário e preencha ambos os campos, por segurança. Na automação de navegador:

# Selenium — inject into both fields for safety
driver.execute_script("""
    var cfField = document.querySelector('[name="cf-turnstile-response"]');
    var gField = document.querySelector('[name="g-recaptcha-response"]');
    if (cfField) cfField.value = arguments[0];
    if (gField) gField.value = arguments[0];
""", token)

Falha 2: callback não disparado

Sintoma: o token está no campo, mas o formulário continua bloqueando o envio.

Causa: a página usa uma função de callback em vez do campo oculto (ou além dele). O callback cuida da lógica extra, como habilitar o botão de envio ou disparar uma requisição AJAX.

Correção: localize e chame o callback:

// Check data-callback attribute
const callbackName = document.querySelector('.cf-turnstile').getAttribute('data-callback');
if (callbackName && window[callbackName]) {
  window[callbackName](token);
}

// Or if it was passed in turnstile.render()
// You may need to intercept the render call to capture it

Falha 3: contexto de página incorreto

Sintoma: o token é rejeitado mesmo com a sitekey certa e uma resolução nova.

Causa: o pageurl usado na requisição não corresponde ao contexto real da página. Isso é especialmente comum em:

  • Telas de verificação de página inteira da Cloudflare — o URL pode incluir parâmetros de consulta ou trechos de caminho que fazem diferença
  • Aplicações de página única (SPAs) — o URL visível pode ser diferente do URL que carregou o widget Turnstile

Correção: abra a aba Network do DevTools e encontre o URL exato de onde o widget Turnstile é carregado. Use esse URL como pageurl.

Falha 4: reutilização de token

Sintoma: a primeira resolução funciona; as seguintes falham.

Causa: os tokens do Turnstile são de uso único. Depois de verificados pelo servidor da Cloudflare, são invalidados.

Correção: peça uma nova resolução para cada envio de formulário. Não guarde em cache nem reutilize tokens.


Referência rápida: erro e correção

Erro / sintoma Etapa Causa provável Correção
ERROR_WRONG_USER_KEY Envio Chave de API malformada Confira a chave de 32 caracteres
ERROR_KEY_DOES_NOT_EXIST Envio Chave inválida Verifique o painel
ERROR_ZERO_BALANCE Envio Sem threads livres Aguarde ou faça upgrade do plano
ERROR_PAGEURL Envio Falta o pageurl Informe o URL completo
ERROR_BAD_PARAMETERS Envio Falta sitekey, method ou pageurl Confira todos os campos obrigatórios
CAPCHA_NOT_READY Consulta Resolução em andamento Aguarde 5 segundos e tente de novo
ERROR_WRONG_ID_FORMAT Consulta ID do CAPTCHA não numérico Use o ID exato de in.php
ERROR_WRONG_CAPTCHA_ID Consulta ID do CAPTCHA inválido Confira o ID do envio
ERROR_EMPTY_ACTION Consulta Falta action=get Adicione o parâmetro action
Token rejeitado pela página Validação Campo errado, callback não disparado, URL errado Confira o nome do campo, chame o callback, valide o pageurl exato
Segunda resolução falha Validação Reutilização de token Peça um token novo a cada envio

Exemplo completo em Python

import time
import requests

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "0x4AAAAAAAB1example"
PAGE_URL = "https://staging.example.com/qa-login"

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


def solve_turnstile(api_key, sitekey, pageurl):
    """Submit a Turnstile challenge and return the solved token."""

    # Submit
    submit_resp = requests.post(
        SUBMIT_URL,
        data={
            "key": api_key,
            "method": "turnstile",
            "sitekey": sitekey,
            "pageurl": pageurl,
            "json": 1,
        },
        timeout=30,
    )
    submit_resp.raise_for_status()
    submit_data = submit_resp.json()

    if submit_data.get("status") != 1:
        raise RuntimeError(f"Submit failed: {submit_data}")

    captcha_id = submit_data["request"]
    print(f"Task created — captcha ID: {captcha_id}")

    # Wait before first poll (Turnstile is fast — 10 seconds is usually enough)
    time.sleep(10)

    # Poll for result
    for _ in range(60):
        result_resp = requests.get(
            RESULT_URL,
            params={
                "key": api_key,
                "action": "get",
                "id": captcha_id,
                "json": 1,
            },
            timeout=30,
        )
        result_resp.raise_for_status()
        result_data = result_resp.json()

        if result_data.get("request") == "CAPCHA_NOT_READY":
            time.sleep(5)
            continue

        if result_data.get("status") == 1:
            return result_data["request"]

        raise RuntimeError(f"Polling error: {result_data}")

    raise TimeoutError("Turnstile solve timed out")


# Usage
token = solve_turnstile(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

# Inject into cf-turnstile-response and/or g-recaptcha-response
# Then submit the form

Exemplo completo em Node.js

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "0x4AAAAAAAB1example";
const PAGE_URL = "https://staging.example.com/qa-login";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveTurnstile(apiKey, sitekey, pageurl) {
  // Submit
  const submitResp = await fetch(SUBMIT_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      key: apiKey,
      method: "turnstile",
      sitekey: sitekey,
      pageurl: pageurl,
      json: "1",
    }),
  });

  const submitData = await submitResp.json();
  if (submitData.status !== 1) {
    throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
  }

  const captchaId = submitData.request;
  console.log(`Task created — captcha ID: ${captchaId}`);

  // Turnstile is fast — wait 10 seconds before first poll
  await sleep(10_000);

  // Poll for result
  for (let i = 0; i < 60; i++) {
    const resultResp = await fetch(
      `${RESULT_URL}?${new URLSearchParams({
        key: apiKey,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );

    const resultData = await resultResp.json();

    if (resultData.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (resultData.status === 1) {
      return resultData.request;
    }

    throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
  }

  throw new Error("Turnstile solve timed out");
}

// Usage
solveTurnstile(API_KEY, SITEKEY, PAGE_URL)
  .then((token) => {
    console.log(`Solved token: ${token.slice(0, 80)}...`);
    // Inject into cf-turnstile-response and/or g-recaptcha-response
  })
  .catch(console.error);

Perguntas frequentes

Quanto tempo o CaptchaAI leva para resolver um Turnstile?

Menos de 10 segundos na maior parte dos casos. Por isso o exemplo em Python aguarda 10 segundos antes da primeira consulta e depois faz polling a cada 5 segundos. Se a sua integração estoura o tempo limite bem além disso, suspeite dos parâmetros de envio, não da velocidade de resolução.

Posso reutilizar o mesmo token do Turnstile em mais de um envio?

Não. Os tokens do Turnstile são de uso único: assim que o servidor da Cloudflare os verifica, eles são invalidados. Peça uma nova resolução para cada envio de formulário e nunca guarde tokens em cache.

Preciso de proxy para resolver o Turnstile?

Para widgets Turnstile isolados, o proxy é opcional — basta enviar sitekey e pageurl. Já nas telas de verificação de página inteira ele é obrigatório. Quando quiser usar um, acrescente os parâmetros proxy e proxytype à requisição.

Como diferencio um widget Turnstile de um desafio de página inteira?

Se há um formulário com uma caixinha de verificação (ou nada visível, no modo invisível), é o widget Turnstile e você recebe um token. Se a página inteira é substituída por uma tela de verificação da Cloudflare, é o desafio de página inteira, que devolve um cookie e exige proxy.

O CaptchaAI funciona com hCaptcha ou FunCaptcha?

Não. O hCaptcha e o FunCaptcha (Arkose Labs) não são suportados no momento. A CaptchaAI cobre reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3, CAPTCHAs de imagem/OCR e desafios de grade de imagens, além de CaptchaFox (beta), Friendly Captcha (beta) e Lemin (beta).


Corrija o seu fluxo do Turnstile

Se a integração do seu Turnstile está falhando, siga esta lista antes de qualquer outra coisa:

  1. Confira a sitekey — extraia de data-sitekey ou de turnstile.render().
  2. Confira o pageurl — use o URL exato, com protocolo e caminho.
  3. Confira o caminho do token — a página espera cf-turnstile-response, g-recaptcha-response ou um callback?
  4. Use json=1 — sempre consulte os resultados do Turnstile em JSON.
  5. Não reutilize tokens — peça uma resolução nova a cada envio.

Uma nota de contexto para times no Brasil e em Portugal: ao registrar logs de requisição em ambientes de QA, evite gravar o token completo ou dados pessoais do formulário — é uma boa prática de conformidade com a LGPD (ou o RGPD, em Portugal) e não atrapalha em nada a depuração.

Comece pelo solucionador de Turnstile da CaptchaAI, valide seus parâmetros na documentação da API e, se precisar entender a mecânica do widget, leia como o Cloudflare Turnstile funciona.


Resumo dos recursos visuais

Imagem principal

  • Texto alternativo: desenvolvedor depurando erros do Cloudflare Turnstile — fluxo de envio, requisição controlada ao endpoint de QA e falhas de validação
  • Deve mostrar: o fluxo de diagnóstico com as etapas de erro e os caminhos de correção
  • Nome do arquivo: cloudflare-turnstile-errors-troubleshooting-hero.png

Visual 1 no artigo

  • Posicionamento: após "Erros na etapa de consulta de resultado"
  • Tipo: árvore de decisão
  • Texto alternativo: árvore de decisão para falhas do Cloudflare Turnstile — erros de envio, erros de consulta e rejeição pela página
  • Nome do arquivo: cloudflare-turnstile-error-decision-tree.png

Visual 2 no artigo

  • Posicionamento: após "Quando a página recusa um token válido"
  • Tipo: diagrama de causas e correções
  • Texto alternativo: diagrama mostrando por que os tokens do Turnstile são rejeitados e a correção de cada causa
  • Nome do arquivo: cloudflare-turnstile-validation-causes-fixes.png

Artigos relacionados

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