Skip to content
Troubleshooting

Turnstile callback never fires — diagnose the silent failure

The Turnstile widget renders, the user sees it spin briefly, but your data-callback function never runs. The cf-turnstile-response hidden field stays empty and form submit fails with "Please complete the captcha".

Cause

Cloudflare's scoring detected the session as bot traffic and silently degraded the widget — instead of failing visibly, Turnstile just doesn't resolve. This is the WAF's "shadow ban" behavior on flagged sessions.

Fix

Stop relying on the widget callback. Use Sonic to fetch the token out-of-band and write it to cf-turnstile-response directly. The form post completes with a verified token regardless of what the page widget does.

Runnable example
import { CaptchaSonic } from 'captchasonic'

const sonic = new CaptchaSonic('YOUR_API_KEY')
const { token } = await sonic.solve({
  type: 'TurnstileTaskProxyless',
  websiteURL: window.location.href,
  websiteKey: '0x4AAAAAAA...',
})

// Skip the widget callback entirely — write directly to the hidden field.
document.querySelector('[name=cf-turnstile-response]').value = token
document.querySelector('form').submit()

Frequently asked questions

Servers only verify the token via Cloudflare's siteverify endpoint — they don't track widget callback timing. As long as the token validates, the submission is accepted.

Cloudflare uses "silent-fail" degradation for sessions it scores as bots — instead of showing an error (which would let bots iterate), it lets the widget render forever. Out-of-band tokens skip this entirely.

Yes — same TurnstileTaskProxyless type handles both the embedded widget and the WAF managed-challenge page.

Related guides