Fix Turnstile 'Verification failed' in production
If your contact form works locally but fails in production with errors like:
Please complete the verification challengeVerification failed. Please try again.
the issue is usually configuration, not form code.
Fast diagnosis checklist
1) Confirm site and secret keys are both set in production
You need:
PUBLIC_TURNSTILE_SITE_KEY(public var)TURNSTILE_SECRET_KEY(secret)
If one is missing, token verification will fail.
2) Confirm Turnstile widget domain settings
In Cloudflare Turnstile, allowed domains should include:
- your real domain (e.g.
mayfield.io) localhostfor local testing
If production domain is missing, valid challenges may still fail verification.
3) Verify server sends token to Turnstile endpoint
Your backend should POST token + secret to:
https://challenges.cloudflare.com/turnstile/v0/siteverify
and check success === true before sending email.
4) Test API path directly
Without a valid token, this should fail (that is expected):
curl -i -X POST "https://yourdomain.com/api/contact" \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@example.com","message":"hello"}'
If this succeeds without token, server-side verification is not enforced correctly.
Common production mistakes
TURNSTILE_SECRET_KEYset locally but not on Worker/host- secret accidentally added as public var instead of secret
- domain mismatch in Turnstile widget settings
- stale deploy running old env values
Concrete fix flow
- set/update keys in production env
- redeploy
- submit form once from production URL
- confirm API returns success and message sends
If your app uses email provider fallback logic, ensure failure in Turnstile verification blocks send path completely.
Turnstile issues can feel random, but once env + domain + server verification are aligned, it is usually very stable.