Cloudflare Turnstile Setup Guide (2026): Add CAPTCHA-Free Bot Protection
- 6 min read
Setting Up Cloudflare Turnstile
Turnstile is Cloudflare’s alternative to reCAPTCHA. It runs a set of background checks (browser behavior, request patterns, device signals) instead of asking users to click traffic lights or type distorted text. Most visitors never see a challenge at all. It’s free, and it’s a straightforward way to stop automated form spam without adding friction to a real user’s checkout, signup, or contact form.
Prerequisites
- A Cloudflare account (the zone doesn’t need to be on Cloudflare’s DNS, Turnstile works independently)
- A form you control the frontend and backend submission handling for
Getting Your Site Keys
- In the Cloudflare dashboard, go to Turnstile and add a new site.
- Enter the domain(s) the widget will run on.
- Cloudflare issues two keys: a site key (public, goes in your HTML) and a secret key (private, used server-side to verify the token).
Adding the Widget
Drop the widget div anywhere before your submit button:
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
Load Cloudflare’s script once, anywhere on the page (the <head> or right before </body> both work):
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
On submit, Turnstile automatically adds a hidden field named cf-turnstile-response to the form. That token is what gets verified server-side.
Verifying the Token Server-Side
The widget alone doesn’t block anything, it just generates a token. Verification has to happen on your backend, or the check is trivial to bypass:
POST https://challenges.cloudflare.com/turnstile/v0/siteverify
secret: YOUR_SECRET_KEY
response: <the cf-turnstile-response value from the form submission>
The response comes back with a success: true/false field. Reject the submission server-side if success is false, before doing anything else with the form data.
Common Pitfalls
- Verifying only on the frontend. The widget rendering and the token existing proves nothing by itself. If the secret-key verification step is skipped, a bot can simply submit the form without ever loading the widget.
- Forgetting the token expires. Tokens are single-use and expire after a short window. If a user takes a long time filling out a form before submitting, the token can go stale, causing a false rejection. Consider re-running the widget’s
execute()method right before submission for longer forms. - One secret key hardcoded across environments. Use separate site/secret key pairs for staging and production so a compromised staging key doesn’t affect production traffic.
- Widget not rendering: almost always a domain mismatch between what’s registered in the Turnstile site settings and the domain the page is actually served from (including
wwwvs non-www).
Turnstile is a low-effort addition for any public form (contact, signup, application) that’s getting spam submissions, and it doesn’t cost real users the friction that traditional CAPTCHAs do.