Turnstile
Add invisible bot protection to any form. Cloudflare Turnstile is free, privacy-first, and replaces CAPTCHA without annoying users.
What Is Turnstile?
Cloudflare Turnstile is a free CAPTCHA alternative that verifies visitors are human without making them solve puzzles or click fire hydrants. It runs a series of browser challenges invisibly in the background and shows a simple checkbox only if the challenge fails.
- Free — no usage limits or billing required
- Privacy-first — doesn't use cookies or track users across sites
- Drop-in — one component tag in your form, server verification is automatic
- No external dependencies — the What framework loads the Turnstile script automatically when configured
Get Your Keys
- Go to the Cloudflare Dashboard
- Select Turnstile from the left sidebar
- Click Add Site
- Enter your site name and domain (use
localhostfor local development) - Choose widget type: Managed (recommended) or Non-interactive
- Click Create
- Copy the Site Key (public) and Secret Key (server-side)
localhost as a domain in your Turnstile widget settings so it works during development. You can add multiple domains to a single widget.
Configure what.toml
Add your keys to the [cloudflare] section. The site key is public and embedded in the page. Keep the secret key in an environment variable.
[cloudflare]
turnstile_site_key = "0x4AAAAAAA..."
turnstile_secret_key = "${CF_TURNSTILE_SECRET}"
CF_TURNSTILE_SECRET=0x4AAAAAAA_your_secret_key_here
${ENV_VAR} syntax for the secret key. The site key is safe to include directly since it's public.
Add to Forms
Drop <what-turnstile/> inside any form. That's the entire integration on your side — the What framework handles the client script, token collection, and server-side verification automatically.
<form w-action="create" w-store="comments" w-redirect="/comments" w-validate>
<label>Comment</label>
<textarea name="body" w-required placeholder="Leave a comment..."></textarea>
<label>Name</label>
<input type="text" name="author" w-required placeholder="Your name">
<what-turnstile/>
<button type="submit" class="btn btn-primary">Post Comment</button>
</form>
The component renders a Turnstile widget in the form. On submission, the browser includes the challenge token and What verifies it against the Cloudflare API before saving the record. Requests that fail verification are rejected with a 400 error.
Customization
The <what-turnstile/> component accepts two optional props:
| Prop | Values | Default | Description |
|---|---|---|---|
theme | light, dark, auto | auto | Widget color scheme |
size | normal, compact | normal | Widget dimensions |
<!-- Dark theme, compact size -->
<what-turnstile theme="dark" size="compact"/>
<!-- Auto theme (matches user's OS preference) -->
<what-turnstile theme="auto"/>
The compact size is useful when vertical space is tight, such as inline forms or sidebars. The auto theme switches between light and dark based on the user's operating system preference.
How Verification Works
When a form with <what-turnstile/> is submitted:
- The Turnstile JavaScript widget runs browser-side challenges silently
- A token is written into a hidden
cf-turnstile-responsefield in the form - The form submits normally via POST — the token is included with the other fields
- What extracts the token server-side and calls the Cloudflare verification API
- If verification passes, the form action proceeds (create/update/delete)
- If verification fails, the request is rejected with an error response
This all happens transparently. You don't write any of this code — the component and the framework handle it end to end.
Dev Mode
If turnstile_site_key is not set in what.toml, the <what-turnstile/> component renders a visible warning banner in place of the widget:
<div class="alert alert-warn">
Turnstile not configured. Add turnstile_site_key to [cloudflare] in what.toml.
</div>
This makes it obvious during development if the component is placed in a form but keys haven't been set up yet. In development, server-side verification is also skipped when no secret key is configured, so forms still submit successfully.