Cloudflare Turnstile: como funciona, o que ele vê do seu lado e como integrar — guia passo a passo
Sumário do artigo
- Introdução: o que você vai aprender neste guia
- Preparação inicial: ferramentas e acessos
- Conceitos básicos: como o cloudflare turnstile é estruturado
- Passo 1: entenda o que exatamente o turnstile vê do seu lado
- Passo 2: crie o widget no painel da cloudflare
- Passo 3: integre o widget na página com o formulário
- Passo 4: configure a verificação do token no servidor
- Passo 5: teste o widget em todos os modos com chaves de teste
- Passo 6: veja o turnstile pelos olhos do visitante com proxy móvel
- Verificação do resultado: checklist final
- Erros comuns e como resolver
- Recursos adicionais para avançar
- Faq: perguntas frequentes sobre o cloudflare turnstile
- Conclusão
Introdução: o que você vai aprender neste guia
O Cloudflare Turnstile é aquele pequeno widget com um círculo girando e o texto "Verifying", que aparece cada vez mais no lugar do velho captcha com imagens. Ele está em formulários de cadastro, em carrinhos de lojas online, em landing pages e em áreas de login de serviços. O visitante comum quase nem nota. Mas para o profissional de marketing, o afiliado ou o desenvolvedor que trabalha com proxy móvel e abre dezenas de sites por dia, ele vira um enigma. Por que em um perfil a verificação passa em um segundo e em outro o widget trava, pede para marcar uma caixa ou mostra um código de erro?
Neste guia vamos destrinchar o Cloudflare Turnstile por dois ângulos. Do lado do dono do site — você vai colocar o widget na página com as próprias mãos, configurar a verificação no servidor e aprender a ler as estatísticas. Do lado do visitante — você vai entender exatamente quais sinais o Turnstile coleta, o que ele vê sobre o seu navegador, a sua rede e o seu proxy, e por que ele toma esta ou aquela decisão. Esse conhecimento é útil tanto para quem protege formulários contra bots quanto para quem quer que seus perfis de trabalho pareçam usuários comuns aos olhos da verificação.
Para quem é este guia
- Para donos de negócio e profissionais de marketing que sofrem com spam em formulários e cadastros falsos que estragam as métricas e consomem orçamento.
- Para desenvolvedores que precisam integrar o Turnstile em um formulário de forma rápida e sem erros, e validar o token corretamente no servidor.
- Para afiliados e especialistas em multcontas que trabalham com proxy móvel e querem entender o que o Turnstile enxerga na conexão deles.
O que você precisa saber antes
Não exige conhecimento especial. Basta entender o que é uma página HTML, saber abrir o console do desenvolvedor no navegador e ter pelo menos uma experiência mínima com alguma linguagem no servidor — PHP, Node.js ou Python. Se você não tem servidor, ainda assim vai conseguir fazer boa parte do guia: dá para integrar e testar o widget em uma página local.
Quanto tempo vai levar
O percurso completo leva cerca de uma hora e meia a duas horas. O cadastro e a criação do widget levam de 10 a 15 minutos, a integração na página, 20 minutos, a verificação no servidor, de 30 a 40 minutos, e os testes e o diagnóstico, mais 30 minutos. As partes teóricas podem ser lidas em qualquer ordem e consultadas conforme a necessidade.
Preparação inicial: ferramentas e acessos
Antes de começar, reúna tudo o que vai precisar. Isso evita pausas no meio do processo.
Ferramentas e acessos necessários
- Conta na Cloudflare. Gratuita. O cadastro é feito com e-mail e leva alguns minutos. Não é obrigatório transferir o domínio para a Cloudflare — o Turnstile funciona em qualquer site, onde quer que ele esteja hospedado.
- Site ou página de teste. Serve qualquer página HTML com formulário. Para experimentos locais, basta um arquivo no computador aberto por meio de um servidor local simples.
- Ambiente de servidor. Qualquer hospedagem com PHP, ou Node.js ou Python na sua máquina. É necessário para a segunda metade do guia — a validação do token.
- Navegador atualizado. Chrome, Firefox, Edge ou Safari em versão atual, com as ferramentas de desenvolvedor abertas.
- Proxy móvel com troca de IP. Vai ser útil no trecho de diagnóstico, para observar como o widget reage a redes diferentes e à rotação de endereços.
Requisitos de sistema
O Turnstile é leve. O widget funciona em qualquer navegador que suporte JavaScript moderno e carrega o código dele a partir do domínio challenges.cloudflare.com. Se na sua rede ou nas extensões do navegador esse domínio estiver bloqueado, o widget não carrega — leve isso em conta nos testes. Para a verificação no servidor é preciso poder fazer requisições HTTPS de saída.
O que preparar antes de começar
- Crie um arquivo de texto para anotações. Nele você vai guardar o site key, o nome do widget, a lista de hostnames e os resultados dos testes.
- Abra a página com o formulário que você quer proteger e salve uma cópia com a data marcada. Esta é a sua reserva.
- Se você já tem um handler no servidor para o formulário, faça uma cópia dele também. Vamos adicionar o código de validação nele.
- Confirme que o seu servidor local ou de produção entrega a página por HTTPS ou via localhost. O Turnstile funciona em HTTP comum, mas em site de produção você vai precisar de HTTPS de qualquer forma.
⚠️ Atenção: A chave secreta do widget não pode ficar no HTML, no JavaScript da página nem em repositório público. Ela vive só no servidor. Se você publicou por engano, reemita a chave imediatamente no painel da Cloudflare — a antiga deixa de funcionar.
Conceitos básicos: como o Cloudflare Turnstile é estruturado
Para os próximos passos ficarem claros, vamos ver os termos principais em linguagem simples.
Termos-chave
- Widget — o bloco que o visitante vê. Tecnicamente é um iframe carregado do domínio da Cloudflare e embutido na sua página.
- Site key — o identificador público do widget. Ele entra no HTML e é visível para todos. Com base nele a Cloudflare sabe qual widget renderizar e para quais domínios ele está liberado.
- Secret key — a chave privada. É com ela que o seu servidor confirma que o token recebido é legítimo. Nunca sai do servidor.
- Token — a string que o widget emite após a verificação bem-sucedida. Ela é inserida em um campo oculto do formulário e vai para o seu servidor junto com os demais dados.
- Siteverify — o endpoint da Cloudflare para onde o servidor envia o token junto com a chave secreta e recebe a resposta: sucesso ou não.
- Modo do widget — a forma de exibição: gerenciado (Managed), não interativo (Non-interactive) ou invisível (Invisible). A diferença está explicada abaixo.
- Hostname — o domínio em que o widget pode ser usado. Se o domínio não estiver na lista, o widget vai falhar com erro.
O funcionamento em quatro frases
- A página carrega o script do Turnstile e o widget dispara silenciosamente uma bateria de verificações no navegador.
- A Cloudflare reúne os resultados, avalia tudo junto com os dados da rede e decide: liberar de imediato, mostrar uma caixa de confirmação ou negar.
- Em caso de sucesso, o widget gera um token de uso único e o insere no formulário.
- O seu servidor recebe o formulário, envia o token ao siteverify e só processa a solicitação em caso de resposta positiva.
O que o Turnstile verifica — panorama geral
Aqui é importante entender o essencial. O Cloudflare Turnstile não avalia "humanidade" por meio de quebra-cabeças com imagens. Ele mede a coerência do ambiente: o quanto navegador, rede e comportamento formam um quadro plausível. Os principais grupos de sinais:
- Ambiente do navegador. O script executa uma série de pequenas tarefas em JavaScript e checa se o ambiente se comporta como um navegador de verdade: como os objetos da janela são estruturados, como os gráficos são renderizados, se há indícios de automação e se o User-Agent declarado bate com as capacidades reais da engine.
- Prova de trabalho. O widget pede ao navegador um pequeno cálculo. Para uma pessoa são frações de segundo; para um bot que abre milhares de páginas, é uma carga considerável.
- Sinais de rede. Reputação do endereço IP e do sistema autônomo de onde vem a requisição, compatibilidade entre as características da rede e o navegador declarado, e histórico de requisições desse endereço em toda a rede da Cloudflare.
- Tokens de confiança do dispositivo. Em dispositivos Apple e em alguns outros ecossistemas, o Turnstile pode pedir ao sistema operacional uma confirmação de que ali existe um dispositivo real — e a verificação passa sem nenhum cálculo.
- Comportamento na página. Momento em que o widget aparece, instante do envio do formulário e naturalidade das ações no modo gerenciado.
O que o Turnstile não faz: não coleta dados para perfilamento publicitário, não rastreia o usuário entre sites por meio de cookies de terceiros e nunca mostra quebra-cabeças com imagens. Isso importa tanto do ponto de vista da lei de proteção de dados quanto da conversão — os visitantes não vão embora por causa de um captcha irritante.
Os três modos do widget
- Managed — o modo padrão. O widget fica visível, gira o indicador e, em caso de dúvida, mostra uma caixa para clicar. Serve para a maioria dos formulários.
- Non-interactive — o widget fica visível, mas nunca exige ação. Ou passa sozinho, ou retorna erro. Bom para páginas em que cliques extras não são aceitáveis.
- Invisible — o widget nem é renderizado. A verificação acontece em segundo plano. Prático para botões e formulários em que você não quer mexer no layout, mas exige tratamento cuidadoso de erros.
Passo 1: Entenda o que exatamente o Turnstile vê do seu lado
Objetivo desta etapa: antes de configurar qualquer coisa, você precisa entender quais dados sobre o seu ambiente o widget recebe. Essa é a base do diagnóstico nos próximos passos e do trabalho consciente com proxy móvel.
Como observar o funcionamento do widget com os próprios olhos
- Abra qualquer site que use o Cloudflare Turnstile. Esses widgets são fáceis de reconhecer pelo logotipo da Cloudflare no canto inferior direito do bloco e pelos links "Privacy" e "Terms".
- Aperte F12 ou clique com o botão direito — "Inspecionar" — para abrir as ferramentas de desenvolvedor.
- Vá até a aba "Network" (Rede) e recarregue a página.
- No filtro, digite challenges.cloudflare.com. Você verá várias requisições: o carregamento do api.js, o carregamento do iframe do widget e uma ou mais requisições POST — é aí que vão os resultados das verificações.
- Abra a aba "Elements" (Elementos) e localize o bloco com a classe cf-turnstile. Dentro dele, após a verificação bem-sucedida, vai aparecer um campo input oculto com o nome cf-turnstile-response e uma string longa como valor. Esse é o token.
Dica: O conteúdo das requisições POST é criptografado e ofuscado, não adianta tentar lê-lo. Olhe para outra coisa: quantas requisições saíram, quanto tempo a verificação levou e se o status do widget virou "Success". Esse é o seu indicador externo de confiança.
O que o Turnstile vê sobre o seu navegador
O widget executa JavaScript direto na sua janela, então ele tem acesso a tudo o que qualquer script da página tem: versão da engine, APIs instaladas, dimensões da tela, fuso horário, idiomas de interface, particularidades da renderização de gráficos e fontes, e o comportamento de funções que costumam ser sobrescritas em navegadores automatizados. Ele não lê os seus arquivos nem entra em outras abas. Mas percebe muito bem quando o navegador declara uma coisa e faz outra. Por exemplo, o User-Agent diz "Chrome no Android", mas o ambiente não tem eventos de toque e tem APIs que não existem em celulares.
O que o Turnstile vê sobre a sua rede
Aqui começa a parte mais interessante para quem trabalha com proxy móvel. Todas as requisições do widget vão para os servidores da Cloudflare, ou seja, a Cloudflare vê o seu endereço IP externo, o sistema autônomo dele (isto é, a operadora), o país, além de características de baixo nível da conexão — como exatamente o seu cliente estabelece a conexão segura. Essas características variam entre navegadores, e a Cloudflare as compara com o User-Agent declarado.
As operadoras móveis distribuem endereços de grandes pools compartilhados; centenas de assinantes reais usam o mesmo endereço ao mesmo tempo. Por isso esses endereços têm, por si sós, reputação neutra ou boa — bloqueá-los significaria bloquear pessoas reais. Mas a reputação é só um dos sinais. Se de um endereço móvel chega um navegador cuja impressão digital de rede é de um script de desktop, com fuso horário de outro continente e sinais de automação, o quadro deixa de fazer sentido e o widget muda para o modo interativo ou nega.
O que o Turnstile vê sobre o seu comportamento
No modo gerenciado, o widget presta atenção em quão rápido o formulário é enviado depois do carregamento, se o usuário interagiu com a página e se o clique na caixa parece natural. Nos modos invisível e não interativo, o componente comportamental é mínimo — a decisão se baseia em ambiente e rede.
✅ Verificação: Nesta etapa você deve conseguir abrir a aba Network, filtrar as requisições para challenges.cloudflare.com, ver o campo oculto cf-turnstile-response e explicar com suas palavras os três grupos de sinais: navegador, rede e comportamento. Se conseguiu, siga para a criação do seu widget.
Problemas possíveis
- Não aparece nenhuma requisição para challenges.cloudflare.com. Provavelmente o domínio está sendo bloqueado por uma extensão do navegador ou por um filtro corporativo. Desative os bloqueadores durante os testes.
- O widget fica travado no estado de verificação para sempre. Confira a data e a hora do sistema no computador: uma diferença grande em relação ao horário real quebra a verificação.
Passo 2: Crie o widget no painel da Cloudflare
Objetivo desta etapa: obter o par de chaves — site key e secret key — e configurar corretamente a lista de domínios e o modo de funcionamento.
- Abra o painel da Cloudflare e entre na sua conta. Se não tiver conta, clique em "Sign up", informe e-mail e senha e confirme o e-mail.
- No menu da esquerda, encontre o item Turnstile. Se você tem várias contas, escolha a certa primeiro na página inicial.
- Clique no botão azul Add widget (Adicionar widget).
- No campo Widget name, digite um nome claro, por exemplo "Landing de leads — principal". O nome só você vê, mas com uma dezena de widgets ele salva você da confusão.
- No bloco Hostname management, clique em Add hostnames e informe os domínios em que o widget vai funcionar. Digite sem protocolo e sem caminho: exemplo.com.br, e não https://exemplo.com.br/formulario. Subdomínios devem ser adicionados separadamente, ou informe o domínio raiz — assim os subdomínios também ficam liberados.
- Para testes locais, adicione localhost à lista. Isso é oficialmente suportado e não atrapalha a produção.
- No bloco Widget Mode, escolha o modo. Na primeira vez, use Managed — assim você vê todos os estados do widget, inclusive o interativo.
- Deixe a opção Pre-clearance desligada por enquanto. Ela só é necessária se o site estiver atrás do proxy da Cloudflare, e vamos falar dela na seção avançada.
- Clique em Create.
- Na tela seguinte você verá dois campos: Site Key e Secret Key. Copie os dois para o arquivo de anotações. A chave secreta pode ser consultada depois nas configurações do widget, mas é mais prático salvar na hora.
Dica: Crie logo dois widgets — um para o domínio de produção, outro com o nome "Teste" e o hostname localhost. Assim você experimenta modos e configurações sem mexer nas estatísticas do widget de trabalho.
Como é um resultado correto
Na lista do Turnstile vai aparecer um cartão com o nome do widget, o modo dele e a lista de hostnames. O site key começa com "0x" e tem cerca de 24 caracteres; o secret key também começa com "0x", mas é mais longo. Se a chave parecer diferente, você provavelmente copiou o campo errado.
✅ Verificação: No seu arquivo de anotações estão registrados o site key, o secret key, o nome do widget, a lista de hostnames e o modo escolhido. No painel da Cloudflare o widget aparece na lista com status ativo.
Problemas possíveis
- O botão Create está inativo. Nenhum hostname foi adicionado ou foi digitado com erro (protocolo, barra, espaço).
- Não encontro o item Turnstile no menu. Você está dentro das configurações de um domínio específico. Volte para o nível da conta — o Turnstile fica lá, não dentro de uma zona.
Passo 3: Integre o widget na página com o formulário
Objetivo desta etapa: o widget aparece na sua página, passa pela verificação e insere o token no formulário.
Inclua o script
- Abra o arquivo HTML da página com o formulário no editor.
- Dentro da tag head ou antes do fechamento da tag body, adicione a linha de inclusão do script:
<script src='https://challenges.cloudflare.com/turnstile/v0/api.js' async defer></script>Os atributos async e defer fazem com que a página não espere o carregamento do script. O widget aparece um pouco depois, mas o usuário não sente atraso no carregamento do conteúdo.
Posicione o contêiner do widget
- Localize o formulário que você está protegendo. Normalmente é uma tag form com campos de nome, e-mail e telefone.
- Logo antes do botão de envio, insira um bloco vazio com a classe cf-turnstile e o seu site key:
<form action='/submit.php' method='POST'> <input type='text' name='name' placeholder='Seu nome'> <input type='email' name='email' placeholder='E-mail'> <div class='cf-turnstile' data-sitekey='SEU_SITE_KEY' data-theme='light'></div> <button type='submit'>Enviar</button> </form>- Substitua SEU_SITE_KEY pela chave do arquivo de anotações. A chave secreta não pode entrar aqui.
- Salve o arquivo e abra a página no navegador via localhost.
O que você deve ver
Um ou dois segundos após o carregamento, no lugar do bloco aparece um widget de cerca de 300 por 65 pixels. Primeiro ele mostra o indicador de carregamento e o texto "Verifying"; depois, um check verde e "Success". Se a Cloudflare decidir reverificar o ambiente, aparece uma caixa com o texto "Verify you are human" — clique nela e, em instantes, o widget mostra sucesso.
Abra as ferramentas de desenvolvedor, aba Elements, e expanda o bloco cf-turnstile. Dentro dele apareceu um campo input oculto com o nome cf-turnstile-response. O valor dele é um token longo. É ele que vai para o servidor quando o formulário for enviado.
Atributos úteis do contêiner
- data-theme — light, dark ou auto. O auto se adapta ao tema do sistema do usuário.
- data-size — normal, compact ou flexible. O flexible estica o widget pela largura do contêiner — prático para layout mobile.
- data-language — código do idioma, por exemplo pt-BR. Por padrão o widget usa o idioma do navegador.
- data-action — um rótulo curto, por exemplo login ou checkout. Ele volta na resposta do siteverify e ajuda a diferenciar formulários nas estatísticas.
- data-callback — nome da função JavaScript chamada após o sucesso. O token chega nela.
- data-error-callback — função que recebe o código de erro, caso algo dê errado.
- data-refresh-expired — o que fazer quando o token expira: auto pede um novo sozinho, manual mostra um botão de atualização e never não faz nada.
Dica: Já adicione o data-error-callback e imprima o código de erro no console. Os códigos do Turnstile são informativos: a série 110xxx indica problemas com a chave ou o domínio, a 300xxx, falha de execução no navegador, e a 600xxx, que a verificação não foi aprovada. Sem isso, você vai ficar adivinhando por que o widget está calado.
Caminho alternativo: renderização explícita via JavaScript
Se você trabalha em um framework ou quer controlar o momento em que o widget aparece, troque a renderização implícita pela explícita. Adicione o parâmetro render=explicit ao endereço do script e chame turnstile.render com os parâmetros desejados:
turnstile.render('#my-widget', { sitekey: 'SEU_SITE_KEY', theme: 'auto', action: 'signup', callback: function(token) { console.log('Token recebido', token.length); } });Essa forma permite redesenhar o widget após um erro com o método turnstile.reset e obter o token atual com turnstile.getResponse.
✅ Verificação: O widget aparece na página, mostra "Success", o campo cf-turnstile-response com o token existe no DOM e não há erros no console. Tente recarregar a página três ou quatro vezes — a cada vez deve surgir um token novo.
Problemas possíveis
- O widget mostra erro 110200. O domínio de onde a página foi aberta não está nos hostnames do widget. Verifique se você abriu via localhost, e não via 127.0.0.1 ou file:// — são hostnames diferentes.
- O widget não aparece e o console está vazio. O script não carregou. Confira se o endereço do script está sem erros de digitação e se não há bloqueadores ativos.
- O widget quebra o layout. Use data-size='flexible' ou envolva o bloco em um contêiner com a largura desejada.
Passo 4: Configure a verificação do token no servidor
Objetivo desta etapa: o servidor rejeita qualquer envio de formulário sem um token válido. Esse é o passo mais importante — sem ele o widget não passa de enfeite, porque o bot pode enviar um POST direto para o handler, sem passar pela página.
Como é a requisição ao siteverify
O seu servidor faz um POST para https://challenges.cloudflare.com/turnstile/v0/siteverify com os campos:
- secret — a sua chave secreta;
- response — o token do campo cf-turnstile-response;
- remoteip — o IP do visitante, opcional, mas útil;
- idempotency_key — identificador único opcional da requisição, do qual falaremos na seção avançada.
A resposta vem em JSON. Os campos principais:
{ "success": true, "challenge_ts": "2026-03-14T10:22:31.000Z", "hostname": "exemplo.com.br", "error-codes": [], "action": "signup", "cdata": "" }O token dura 300 segundos e é de uso único. Validar o mesmo token de novo retorna o erro timeout-or-duplicate.
Exemplo em PHP
- Abra o arquivo que processa o formulário, por exemplo submit.php.
- Logo no início, antes de qualquer manipulação dos dados do formulário, adicione o bloco de verificação:
<?php $token = $_POST['cf-turnstile-response'] ?? ''; if ($token === '') { http_response_code(400); exit('Verificação não aprovada: sem token'); } $data = [ 'secret' => getenv('TURNSTILE_SECRET'), 'response' => $token, 'remoteip' => $_SERVER['REMOTE_ADDR'] ]; $ch = curl_init('https://challenges.cloudflare.com/turnstile/v0/siteverify'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $raw = curl_exec($ch); curl_close($ch); $result = json_decode($raw, true); if (empty($result['success'])) { http_response_code(403); exit('Verificação não aprovada: ' . implode(',', $result['error-codes'] ?? ['no-response'])); }