turnstile-spin
Set up, repair, or migrate to Cloudflare Turnstile bot verification in an existing frontend and backend, including server-side Siteverify.
Install
npx skills add https://github.com/cloudflare/skills --skill turnstile-spinVanilla HTML
For static sites or any project without a JS framework. The widget renders client-side; the form submits to whatever backend handles your form (a Node/PHP/Ruby/Go server, a Cloudflare Worker, a Pages Function, a third-party form host that supports server-side hooks, etc.).
When the form submits, the browser includes cf-turnstile-response automatically. Your backend reads it and calls canonical siteverify.
Backend (any language)
Add this to your existing /api/subscribe handler before the rest of its logic:
Equivalent calls in other backend languages (each also compares result.hostname to a TURNSTILE_HOSTNAMES allowlist):
subscribe is the stable action for this surface. Preserve an existing custom migration action and compare the returned action to the same value. Siteverify is mandatory for every widget mode, including pre-clearance. Set TURNSTILE_HOSTNAMES to the deployment-specific frontend hostnames; a production value must not include localhost or 127.0.0.1.
Variant: AJAX submit instead of form action
For an AJAX flow, replace the native form and API script with explicit rendering. Keep this surface's widget ID and reset it in finally, which covers network, JSON, validation, and server failures as well as successful same-page completion.
No backend?
If your project is pure-static (no server-side handler — just HTML served from a CDN), Spin doesn't apply. Siteverify is server-side by design. Options:
- Add a Cloudflare Pages Function (
functions/api/subscribe.js) to host the siteverify call. - Deploy a tiny Cloudflare Worker that does siteverify against your existing form host.
- Use a third-party form host that exposes a server-side webhook where you can wire siteverify.