Cloudflare Turnstile Contact Form Protection
Section titled “Cloudflare Turnstile Contact Form Protection”This update protects the public NutsNews contact form with Cloudflare Turnstile.
What changed
Section titled “What changed”- The contact form renders a Cloudflare Turnstile widget before the Send button.
- The browser sends the Turnstile token to
/api/contactasturnstileToken. - The API route verifies the token server-side with Cloudflare Siteverify before sending the Resend email.
- The existing hidden
websitehoneypot remains in place as an extra spam trap. - Turnstile copy is localized for English, French, and Japanese.
Required environment variables
Section titled “Required environment variables”Add these to web/.env.local for local testing and to Vercel for Production:
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your_cloudflare_turnstile_site_keyTURNSTILE_SECRET_KEY=your_cloudflare_secret_keyThe public site key is safe to expose to the browser. The secret key must stay server-side only.
Cloudflare setup
Section titled “Cloudflare setup”- Open the Cloudflare dashboard.
- Go to Turnstile.
- Create a widget for NutsNews.
- Use a clear widget name, such as
NutsNews Contact Form. - Add these hostnames:
nutsnews.comwww.nutsnews.comlocalhostfor local testing
- Copy the generated site key and secret key.
- Add the site key as
NEXT_PUBLIC_TURNSTILE_SITE_KEY. - Add the secret key as
TURNSTILE_SECRET_KEY. - Redeploy the web app after adding Vercel environment variables.
Local verification
Section titled “Local verification”cd /Users/ramideltoro/WebstormProjects/nutsnews2/web
npm run lintnpx tsc --noEmitnpm run buildnpm run devThen open:
http://localhost:3000/contactExpected behavior:
- The Turnstile widget appears above the Send button.
- Submitting without a token is blocked.
- Submitting with a valid token sends the message.
- The widget resets after success or error so tokens are not reused.
Troubleshooting
Section titled “Troubleshooting”The contact page says the anti-spam check is not configured
Section titled “The contact page says the anti-spam check is not configured”One of these is missing:
NEXT_PUBLIC_TURNSTILE_SITE_KEYin the browser/build environmentTURNSTILE_SECRET_KEYin the server environment
Add both values and restart/redeploy.
Localhost does not work
Section titled “Localhost does not work”Make sure the Turnstile widget in Cloudflare includes localhost as an allowed hostname.
The widget appears but sending fails
Section titled “The widget appears but sending fails”Check Vercel logs for:
NutsNews Turnstile verification rejectedCommon causes:
- Wrong secret key
- Token expired
- Hostname not allowed in the Turnstile widget
- Using a production secret with a Cloudflare test site key, or the opposite
