API Tutorials

Como resolver Cloudflare Turnstile pela API

Para resolver o Cloudflare Turnstile pela API: extraia o sitekey (começa com 0x), envie-o com a URL da página ao endpoint /in.php, faça polling em /res.php e injete o token no campo oculto cf-turnstile-response. É esse fluxo, em quatro passos, que este guia detalha com código pronto em Python e Node.js.

Diferente dos CAPTCHAs tradicionais, o Turnstile raramente mostra desafio visível: coleta sinais do navegador em segundo plano e emite um token que o backend valida. Ainda sem conta? Veja o Quickstart da CaptchaAI.

Os quatro passos, em resumo:

  1. Extraia o sitekey (0x...) do HTML ou do script que inicializa o widget.
  2. Envie sitekey e pageurl para o endpoint /in.php.
  3. Faça polling em /res.php até status retornar 1.
  4. Injete o token no campo cf-turnstile-response e envie o formulário.

Requisitos

Item Valor
API key da CaptchaAI No painel em captchaai.com
Sitekey do Turnstile Extraído da página (começa com 0x)
URL da página URL completa onde o Turnstile aparece
Linguagem Python 3.7+ ou Node.js 14+

Com esses quatro itens em mãos, siga os passos abaixo na ordem — cada um depende do resultado do anterior.


Passo 1: encontre o sitekey

O sitekey do widget aparece no HTML da página, normalmente dentro de uma div ou de um bloco <script>:

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

Ou renderizado por JavaScript:

turnstile.render('#widget', {
  sitekey: '0x4AAAAAAAC3DHQFLr1GavNl',
  callback: function(token) { /* ... */ }
});

Três formas de extrair:

  1. DevTools do navegador — aba Elements, busque data-sitekey ou cf-turnstile.
  2. Código-fonteCtrl+U e procure strings que comecem com 0x.
  3. Aba Network — filtre por challenges.cloudflare.com; o sitekey vai nos parâmetros da requisição.

O sitekey do Turnstile sempre começa com 0x e geralmente tem 22 caracteres. Isso o diferencia das chaves de reCAPTCHA, que começam com 6L.


Passo 2: envie a tarefa

Envie um POST para https://ocr.captchaai.com/in.php com method=turnstile, o sitekey e a URL da página:

import requests

API_KEY = "YOUR_CAPTCHAAI_KEY"
SITEKEY = "0x4AAAAAAAC3DHQFLr1GavNl"
PAGEURL = "https://staging.example.com/qa-login"

r = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": SITEKEY,
    "pageurl": PAGEURL,
    "json": 1,
})
data = r.json()
if data["status"] != 1:
    raise RuntimeError(f"submit failed: {data}")
task_id = data["request"]
print("task id:", task_id)

O mesmo fluxo em Node.js:

const axios = require("axios");

const { data } = await axios.post("https://ocr.captchaai.com/in.php", null, {
  params: {
    key: process.env.CAPTCHAAI_KEY,
    method: "turnstile",
    sitekey: "0x4AAAAAAAC3DHQFLr1GavNl",
    pageurl: "https://staging.example.com/qa-login",
    json: 1,
  },
});
if (data.status !== 1) throw new Error(`submit failed: ${JSON.stringify(data)}`);
const taskId = data.request;

Uma resposta bem-sucedida devolve {"status": 1, "request": "<task_id>"}. Guarde esse task_id — ele é a referência para o polling no próximo passo.


Passo 3: faça polling do resultado

O Turnstile costuma resolver em 10–25 segundos. Aguarde 10 segundos antes da primeira consulta e repita a cada 5 segundos, até 40 vezes:

import time

time.sleep(10)
for _ in range(40):
    r = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "get",
        "id": task_id,
        "json": 1,
    })
    res = r.json()
    if res["status"] == 1:
        token = res["request"]
        break
    if res["request"] != "CAPCHA_NOT_READY":
        raise RuntimeError(f"solver error: {res}")
    time.sleep(5)
else:
    raise TimeoutError("turnstile solving timed out")

print("token (60 primeiros caracteres):", token[:60])

Rodando workers em sa-east-1 (São Paulo), o RTT até a CaptchaAI cresce um pouco, mas raramente sai da faixa de 10–25 s. E se o pipeline loga pageurl e dados de usuário, trate isso como dado pessoal sob a LGPD.

O token retornado é uma string Base64 que normalmente começa com 0. e tem entre 400 e 600 caracteres.


Passo 4: injete o token na página

Com o token em mãos, insira-o no campo oculto cf-turnstile-response do formulário e envie normalmente.

Selenium:

driver.execute_script(
    "document.querySelector('[name=cf-turnstile-response]').value = arguments[0];",
    token,
)
driver.find_element("css selector", "form").submit()

Playwright:

page.evaluate(
    "(t) => document.querySelector('[name=cf-turnstile-response]').value = t",
    token,
)
page.click("button[type=submit]")

HTTP puro: adicione cf-turnstile-response=<token> no corpo application/x-www-form-urlencoded.

O token do Turnstile vale por 120–300 segundos. Envie-o assim que possível — depois desse intervalo o backend responde timeout-or-duplicate.


Exemplo completo em Python

import os, time, requests

API = "https://ocr.captchaai.com"
KEY = os.environ["CAPTCHAAI_KEY"]

def solve_turnstile(sitekey: str, pageurl: str) -> str:
    r = requests.post(f"{API}/in.php", data={
        "key": KEY, "method": "turnstile",
        "sitekey": sitekey, "pageurl": pageurl, "json": 1,
    }, timeout=30)
    j = r.json()
    if j["status"] != 1:
        raise RuntimeError(f"submit: {j}")
    tid = j["request"]

    time.sleep(10)
    for _ in range(40):
        r = requests.get(f"{API}/res.php", params={
            "key": KEY, "action": "get", "id": tid, "json": 1,
        }, timeout=30)
        j = r.json()
        if j["status"] == 1:
            return j["request"]
        if j["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(f"poll: {j}")
        time.sleep(5)
    raise TimeoutError("timeout")

if __name__ == "__main__":
    print(solve_turnstile("0x4AAAAAAAC3DHQFLr1GavNl", "https://staging.example.com/qa-login"))

Erros comuns

Código Significado Ação
ERROR_WRONG_USER_KEY Formato de API key inválido Verifique se CAPTCHAAI_KEY está completo
ERROR_KEY_DOES_NOT_EXIST API key não encontrada Copie novamente do painel
ERROR_ZERO_BALANCE Saldo zero Recarregue e tente de novo
ERROR_PAGEURL Falta o pageurl Envie a URL completa com https://
ERROR_CAPTCHA_UNSOLVABLE Falhou após várias tentativas Verifique se sitekey e pageurl batem; tente uma vez mais

Mais detalhes no guia de reCAPTCHA v2.


Quando não funciona

Sitekey dinâmico

Alguns sites com Cloudflare emitem um sitekey novo a cada visita ou a cada deploy do widget. Se o sitekey que funcionava ontem parou de funcionar hoje, esse costuma ser o motivo — reextraia o sitekey imediatamente antes de montar cada tarefa, nunca a partir de um valor salvo em cache.

pageurl fora do padrão esperado

O backend do Turnstile compara a pageurl de forma estrita. Envie o caminho exato onde o widget é renderizado, sem parâmetros de query extras, sem barra final divergente da página real e sem misturar http com https.

Assinatura TLS do cliente

A Cloudflare também observa a assinatura TLS da própria conexão, não só o token do Turnstile, para identificar clientes automatizados. Bibliotecas HTTP genéricas (requests, axios puro) têm uma assinatura diferente de um navegador real. Use curl_cffi, Playwright ou um navegador real para a requisição que carrega a página com o widget.

Token expirado antes do envio

O token vale entre 120 e 300 segundos após emitido. Se o seu pipeline tem uma fila entre "resolver" e "enviar o formulário", meça esse intervalo — se ultrapassar o limite, o desafio precisa ser resolvido de novo.

Qualidade do proxy

IPs de datacenter baratos, sobretudo os já reconhecidos por outros bots, disparam desafios extras com mais frequência. Prefira egress de rede autorizado, com reputação de IP estável e histórico limpo — troque a faixa de IP se a taxa de desafios subir de forma consistente.


Perguntas frequentes

Quanto custa resolver Turnstile com a CaptchaAI?

Cobrança por thread simultânea, não por captcha. O BASIC (US$ 15/mês, 5 threads) já inclui solves ilimitados; veja a tabela completa em captchaai.com/pricing.

O CaptchaAI resolve Turnstile invisível, sem widget na tela?

Sim, e o processo é o mesmo: você continua precisando do sitekey (extraído do HTML ou do script de inicialização) e da pageurl exata.

Existe SDK oficial ou preciso montar as requisições manualmente?

Só a API REST — não há SDK para Turnstile em Python ou Node.js. Encapsule requests/axios em uma função própria, como no exemplo completo acima.

Quanto tempo leva para resolver um Turnstile?

Entre 10 e 25 segundos na maioria dos casos, medido do envio da tarefa até a resposta com o token pronto. A cobrança é por thread simultânea, então rodar várias tarefas em paralelo não aumenta o tempo de cada uma individualmente.

O token funciona em qualquer subdomínio do site?

Não necessariamente. O token é emitido para a pageurl enviada na tarefa; se o formulário de destino está em outro subdomínio ou caminho, reenvie a tarefa com a pageurl correta antes de tentar validar o token nesse endereço.


Próximos passos

Para entender o que acontece por trás do widget antes de automatizar a resolução, veja o material abaixo:

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