Skip to content

Troubleshooting

Cloudflare Turnstile Siteverify Errors: Why a Token Is Rejected

Every Cloudflare Turnstile siteverify error code with Cloudflare's meaning and fix, and why a site rejects a token when you automate a form.

By 6 min readPublished Updated

Cloudflare Turnstile’s siteverify API rejects a token with one of seven error codes: missing-input-secret, invalid-input-secret, missing-input-response, invalid-input-response, bad-request, timeout-or-duplicate and internal-error. Only two are about the token itself: timeout-or-duplicate (“Token has already been validated”, and also what an expired token gets) and invalid-input-response (“Token is invalid, malformed, or expired”). A token can also pass siteverify and still be refused, because the site compares the reply’s action or hostname with what it expects, or never finds the token where it looks.

The site’s server makes the siteverify call, so when you automate a form you rarely see these codes: you see the site’s own error message. This article lists each code with Cloudflare’s wording, then maps each cause to what you, the developer automating the form, can change. Only automate sites you are allowed to; see responsible captcha automation.

Every Cloudflare Turnstile siteverify error code

Cloudflare’s complete list, with its description and required action verbatim (checked 1 October 2026), and who can act on it:

Error code Cloudflare’s description Cloudflare’s action Who can fix it
missing-input-secret “Secret parameter not provided” “Ensure secret key is included” The site
invalid-input-secret “Secret key is invalid or expired” “Check your secret key in the Cloudflare dashboard” The site
missing-input-response “Response parameter was not provided” “Ensure token is included” You, if the token was not in the field the site reads
invalid-input-response “Token is invalid, malformed, or expired” “User should retry the challenge” You: send a new, complete token
bad-request “Request is malformed” “Check request format and parameters” The site
timeout-or-duplicate “Token has already been validated” “Each token can only be used once” You: one fresh token per submission
internal-error “Internal error occurred” “Retry the request” The site retries; you can resubmit with a new token

Three rules about the call itself explain the site-side codes. Siteverify is POST https://challenges.cloudflare.com/turnstile/v0/siteverify, and “The API accepts both application/x-www-form-urlencoded and application/json requests, but always returns JSON responses”, so a GET-style check copied from another CAPTCHA does not fit it. It needs secret and response. And it should be called only from the site’s backend. What a Cloudflare Turnstile token is covers the full request and reply.

Why a token is rejected when you automate a form

Expired or reused: timeout-or-duplicate

Cloudflare gives a token a “Validity period: 300 seconds (5 minutes) from generation” and makes it “Single use”. The server-side docs say a replayed token “will be rejected with the timeout-or-duplicate error code”, and that a form submitted after the 300 seconds gets the same code. In automated code, this usually means a token was solved too early, shared between two requests, or reused on a retry after the site refused the first attempt for another reason, such as a wrong password.

What you can change: create the task when your code reaches the form, submit as soon as the token is ready, and get a new token for every attempt. ZeroCaptcha’s ready reply includes expiresAt, so your code can check the time left before submitting. The patterns are in Cloudflare Turnstile token expiry.

A damaged or wrong token

invalid-input-response, “Token is invalid, malformed, or expired”, covers a token that was cut short or altered on its way to the site. A token can be up to 2,048 characters, so a field, a column or a URL that truncates it breaks it; so does URL-encoding it twice. The testing dummy token XXXX.DUMMY.TOKEN.XXXX fails too: “Production secret keys will reject the dummy token.”

Each widget has its own sitekey and secret key, and the site verifies with its widget’s secret. A token solved for a different sitekey, such as the sign-up widget’s when you submit the login form, or a sitekey your code cached before the site changed it, is not a token for this widget. Cloudflare does not document which code that case returns; expect a failure.

What you can change: read the sitekey from the page at run time, from the widget inside the form you submit (find a Cloudflare Turnstile sitekey), and pass the token through unchanged.

Action and hostname checks on the site’s side

Siteverify returns action, cdata and hostname with every result, and Cloudflare’s best practices tell sites to use them: “Check additional fields. Validate the action and hostname when specified.” Its own sample code does exactly that, with lines such as if (expectedAction && validation.action !== expectedAction) {. A site that follows it rejects a token whose action differs from the widget’s, even though siteverify said success: true. Siteverify returns no error code for this; the refusal is the site’s.

What you can change: copy the widget’s data-action (or the action option passed to turnstile.render()) into the task’s action, and its data-cdata into cdata. Cloudflare limits action to 32 and cData to 255 characters, alphanumerics plus _ and -. Cloudflare Turnstile action and cData shows where to find both. For the hostname, “Hostname where the challenge was served”, use the exact URL of the page that shows the widget as websiteURL, including its subdomain.

The token never reached siteverify: the field name

missing-input-response means the site’s server called siteverify without a token. When you automate, the usual cause is that the token went into a field the server does not read. The widget’s input is named cf-turnstile-response by default, but sites can rename it (response-field-name), turn it off (response-field) and send the token from JavaScript, or run Turnstile in reCAPTCHA compatibility mode, where the input is g-recaptcha-response.

What you can change: submit the form once by hand with the browser’s developer tools open and copy the field name from the real request. Submit a Cloudflare Turnstile token covers form fields, callbacks and JSON bodies.

Errors that are the site’s to fix

missing-input-secret, invalid-input-secret and bad-request come from the site’s own request, and nothing in your submission changes them. internal-error is Cloudflare’s; its action is “Retry the request”, and sites can retry safely with an idempotency_key, “A UUID you generate to safely retry validation requests”. If the site shows an error after a Cloudflare problem, submit again later with a new token.

When the site is yours

If you run the site and your own users are refused, log the error-codes array from every failed siteverify reply, and test each branch with Cloudflare’s testing keys: the secret 2x0000000000000000000000000000000AA always fails validation, and 3x0000000000000000000000000000000AA returns the “token already spent” error. In our own check on 30 September 2026 (an observation, not Cloudflare’s documentation), siteverify answered the dummy token with invalid-input-response under the 2x secret and timeout-or-duplicate under the 3x secret. Test Cloudflare Turnstile in CI wires the keys into a test suite.

What a solving API can and cannot fix

A solving API fixes one thing: getting a valid token for the page when your client cannot produce one. ZeroCaptcha returns a token for the websiteURL, websiteKey, action and cdata you send, usable once within 300 seconds. It cannot fix a submission under the wrong field name, a token held past expiresAt, or the site’s own secret-key errors. Tasks that fail cost nothing; a token you let expire was solved, so it is charged, and getTaskResult then answers ERROR_TOKEN_EXPIRED.

Don’t confuse siteverify’s codes with the solving API’s own codes, such as ERROR_CAPTCHA_UNSOLVABLE: those are covered in CAPTCHA API error codes and the errors reference. The full solving flow is on the Cloudflare Turnstile solver page.

See the codes for yourself

The Cloudflare Turnstile token checker asks siteverify about a token from any of this site’s demo widgets and explains each code it returns. Check the same token twice to see timeout-or-duplicate.

Sources

The team that builds and runs the ZeroCaptcha API. Articles are drafted with AI tools, then checked against the API's code and the primary sources each one cites.

Questions

What does timeout-or-duplicate mean in Cloudflare Turnstile?

Siteverify received a token that had already been validated, or one older than 300 seconds. Get a new token for every submission and submit it as soon as it is ready.

Can I call siteverify myself to check a token before I submit it?

No. Siteverify needs the site's secret key, which only the site's server holds, and each token can be validated only once, so a check of your own would spend it.

Why is a fresh, unused token still rejected?

Siteverify may accept it while the site refuses it: sites compare the action and hostname in the reply with what they expect, or read the token from a different field. Send the widget's action and cData with the task and submit under the field name the page uses.

Read next

This article is part of the Cloudflare Turnstile solver hub. Every task is charged only when a token is ready.

Get an API key