Turnstile
Proves your visitors are human — usually without making them click a single thing.
What is Turnstile?
Turnstile is Cloudflare's free replacement for CAPTCHA — those 'select all the traffic lights' tests. It checks visitors are real humans, usually without making them solve anything.
Instead of puzzles, it runs tiny invisible JavaScript checks in the background to gather signals about the browser. From those signals it decides whether the visitor is trustworthy, only showing a simple checkbox when something looks risky.
Think of it like…
An automatic door that quietly senses a real person approaching and opens — versus the old turnstile where everyone had to stop and fumble with a token.
Why use it?
Better UX
No frustrating image grids. Most users sail through without doing anything.
Privacy-first
Doesn't track users across the web or harvest data to sell, unlike some ad-funded CAPTCHAs.
Stops bots
Blocks spam sign-ups, fake comments, and automated form abuse.
Accessible
WCAG 2.2 AA compliant, so it works for users with disabilities.
How to add it
Turnstile works in two parts: a widget on your page (client side) and a verification check on your server (server side). You always need both — never trust the client alone.
Create a widget
In the Cloudflare dashboard go to Turnstile → Add widget. Enter your domain and pick a widget type. You'll get two keys: a Sitekey (public, for the page) and a Secret key (private, for your server).
Embed the widget in your page
Add the Turnstile script in the <head>, then drop a div with class cf-turnstile and your sitekey inside your form. It auto-creates a hidden field named cf-turnstile-response when solved.
<head> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> </head> <body> <form action="/submit" method="POST"> <input type="email" name="email" placeholder="Email" required /> <!-- Replace YOUR_SITEKEY with your real sitekey --> <div class="cf-turnstile" data-sitekey="YOUR_SITEKEY" data-theme="auto"></div> <button type="submit">Sign up</button> </form> </body>Verify the token on your server
When the form is submitted, send the cf-turnstile-response token plus your Secret key to Cloudflare's Siteverify API. Only accept the form if the response says success: true.
// Node.js / server-side const token = formData.get('cf-turnstile-response'); const res = await fetch( 'https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ secret: process.env.TURNSTILE_SECRET_KEY, // never hardcode! response: token, }), } ); const data = await res.json(); if (!data.success) { return new Response('Failed the human check', { status: 403 }); } // data.success === true -> continue processing the form
Test keys for local development
Use sitekey 1x00000000000000000000AA (always passes) with secret 1x0000000000000000000000000000000AA while developing, so you don't trigger real challenges. Swap in your real keys before going live.
Key concepts
Sitekey
Public key placed on your page. Safe to expose in HTML.
Secret key
Private key used only on your server to verify tokens. Keep it secret!
Token
A one-time pass the widget issues after a visitor passes. Valid 300s, usable once.
Siteverify
The Cloudflare API your server calls to confirm a token is genuine.
Managed widget
Default mode — decides on its own whether to show a checkbox based on risk.
Invisible widget
Runs completely in the background with no visible element at all.
Tips & billing
Always verify server-side
A clever bot can fake the client widget. The Siteverify check on your server is the part that actually keeps you safe — never skip it.
- Turnstile is free with unlimited verifications, even on the Free plan.
- It does not require your whole site to be proxied through Cloudflare — it works on any site.
- Tokens expire after 300 seconds and can only be validated once, so verify promptly.
- Pick widget size (normal, flexible, compact) and theme (auto/light/dark) with data- attributes.
Related products
menu_bookOfficial docsopen_in_new