Explainer
Cloudflare Turnstile Retry and Refresh-Expired Settings Explained
What Cloudflare Turnstile's retry, retry-interval, refresh-expired and refresh-timeout settings do, their defaults, and when to change them.
By ZeroCaptcha Engineering5 min readPublished
A Cloudflare Turnstile widget has four settings that decide what it does after something goes
wrong: retry (auto by default, or never) retries a failed challenge by itself;
retry-interval sets the wait between those retries, 8,000 ms by default and 900,000 ms at
most; refresh-expired (auto by default, manual or never) decides what happens when the
token expires after 300 seconds; and refresh-timeout (auto by default in Managed mode,
manual or never) decides what happens when an interactive challenge is not completed in time.
Each can be set as a data- attribute or as a turnstile.render option.
This explainer describes each one with Cloudflare’s wording, as checked on 1 October 2026, shows a widget that handles failure and expiry itself, and says what the settings mean for automated clients.
The four settings
turnstile.render option |
Data attribute | Values | Default | What it controls |
|---|---|---|---|---|
retry |
data-retry |
auto, never |
auto |
“Controls whether the widget should automatically retry to obtain a token” |
retry-interval |
data-retry-interval |
milliseconds, up to 900,000 | 8,000 | “the time between retry attempts” |
refresh-expired |
data-refresh-expired |
auto, manual, never |
auto |
What happens when the token expires |
refresh-timeout |
data-refresh-timeout |
auto, manual, never |
auto in Managed mode |
What happens when an interactive challenge times out |
Cloudflare describes the values like this:
retry: auto“Automatically retries failed challenges. Auto retry provides better visitor experience by automatically recovering from temporary network issues or processing errors.”retry: never“Disables automatic retry. This requires manual intervention and gives you full control over error handling.”refresh-expired: autorefreshes expired tokens automatically;manual“gives visitors control but requires them to take action”;neverleaves all refresh logic to your page.refresh-timeout: auto“Automatically refreshes upon encountering an interactive timeout”;manual“Prompts the visitor to manually refresh”;never“Will show a timeout”.
The callbacks that go with them
| Option | Cloudflare’s description |
|---|---|
callback |
“A JavaScript callback invoked upon success of the challenge” |
error-callback |
“A JavaScript callback invoked when there is an error” |
expired-callback |
“Invoked when the token expires and does not reset the widget” |
timeout-callback |
“Invoked when the challenge presents an interactive challenge but was not solved within a given time” |
And the widget’s methods: turnstile.reset(widgetId), “To reset the widget if the given widget
timed out or expired”; turnstile.getResponse(widgetId) to read the current token;
turnstile.isExpired(widgetId) to check it; and turnstile.remove(widgetId).
When to change the defaults
The defaults suit most forms: failures retry on their own, and a visitor who leaves a form open for more than five minutes gets a new token without noticing. Change them when your page needs control:
retry: neverwhen you show your own error message and let the visitor try again, or when you log every failure before retrying. Pair it witherror-callback.- A longer
retry-intervalwhen many failures in a row would only add load, such as on a page behind a slow network. refresh-expired: manualwhen a silent refresh would surprise the visitor, for example if you disable the submit button while the widget works.refresh-expired: neverwhen your page manages tokens itself: it hearsexpired-callbackand callsturnstile.reset()when it is ready.
Here is a widget, rendered explicitly (the script loaded with ?render=explicit), that shows its
own error message, and refreshes an expired token only when the visitor submits:
const submit = document.querySelector("#signup button[type=submit]");const message = document.querySelector("#signup .captcha-message");
const widgetId = turnstile.render("#signup .captcha", { sitekey: "0x4AAAAAAAB1cD2eF3gH4iJ5", action: "signup", retry: "never", "refresh-expired": "never", callback: () => { message.textContent = ""; submit.disabled = false; }, "error-callback": (code) => { submit.disabled = true; message.textContent = `The security check failed (${code}). Press "Try again".`; }, "expired-callback": () => { submit.disabled = true; message.textContent = "The security check expired. It will run again when you submit."; },});
document.querySelector("#signup .captcha-retry").addEventListener("click", () => { turnstile.reset(widgetId);});
document.querySelector("#signup").addEventListener("submit", (event) => { if (turnstile.isExpired(widgetId) || !turnstile.getResponse(widgetId)) { event.preventDefault(); turnstile.reset(widgetId); }});The error codes your error-callback receives are listed in
Cloudflare Turnstile error codes. Whatever the widget
does, your server must still validate each token with siteverify: the settings above only change
the page.
What the settings do not change
- The token’s lifetime. “Tokens are single-use and expire after 300 seconds (five minutes).”
refresh-expired: autogets a new token; it never makes an old one last longer. See Cloudflare Turnstile token expiry. - Server-side checks. A retried or refreshed token is a new token, validated once like any
other. A replayed one fails with
timeout-or-duplicate. - The widget’s mode. Managed, Non-Interactive and Invisible are set on the widget in the Cloudflare dashboard; see Cloudflare Turnstile widget modes.
What they mean for automated clients
When your automation puts a token from a solving API into a page, the page’s widget settings still run around it:
- Your token has its own 300 seconds. The widget does not know when it was issued, and its refresh settings do not extend it. Fill the field just before you submit.
- Pages that gate the button on callbacks (as in the example above) need the
callbackcalled with your token, or the button stays disabled. Submit a Cloudflare Turnstile token shows how to find and call it. - A widget that keeps retrying in an automated browser, with
retry: auto, can change the page while you work. Read the sitekey once, then write the token and submit in one step.
ZeroCaptcha returns a token for the page and sitekey you name, valid for 300 seconds and good for one submission; the Cloudflare Turnstile solver page shows the call in ten languages and tools.
Sources
- Cloudflare Turnstile: widget configurations (checked 1 October 2026).
- Cloudflare Turnstile: embed the widget,
for explicit rendering and the
turnstilemethods (checked 1 October 2026). - Cloudflare Turnstile: server-side validation (checked 1 October 2026).
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.