Cloudflare Turnstile widget modes: managed, non-interactive and invisible
Cloudflare Turnstile runs in one of three widget modes — managed, non-interactive or invisible — chosen per widget in the Cloudflare dashboard and carried by that widget's sitekey, not by your page markup. Managed shows a checkbox only when Cloudflare decides an interaction is needed, non-interactive shows a widget with a loading spinner but never prompts the visitor, and invisible runs the challenge in the background with no widget and no loading indicator.
The three widget modes
A Turnstile widget is a configuration object in your Cloudflare account. Cloudflare's own definition: a widget "defines how Turnstile behaves on your webpage" and "has a mode, a label, a sitekey, and a secret key". You can create as many widgets as you need, each with its own mode, and each with its own sitekey and secret key pair.
| Mode | What renders | Visitor interaction | Cloudflare's stated use case |
|---|---|---|---|
| Managed (recommended) | A visible widget that adapts to the visitor | A checkbox, only when a further check is needed | Simple setup with adaptive security |
| Non-Interactive | A visible widget with a loading spinner | Never | Minimise friction while showing verification is occurring |
| Invisible | Nothing visible | Never | Maximise visual experience with zero visible verification elements |
The mode is the only thing that decides whether a human is ever asked to click. Everything else — size, theme, when the widget appears — is presentation, set from markup, and cannot turn one mode into another.
What each mode renders
Managed mode is fully managed by Cloudflare. It chooses an action from client-side signals and risk level, and "will only require interaction if a further check is necessary to verify that the visitor is human". When that happens the visitor is prompted to select a box. There are no images or text to decipher — Turnstile has no picture grids at any point.
Non-interactive mode shows the same physical widget with a loading spinner while the challenge runs in the browser, but the visitor "will never be required or prompted to interact with the widget". It is a visible receipt for work happening in the background.
Invisible mode behaves like non-interactive with the widget removed: no widget, and no indication that a browser challenge is in progress. Cloudflare attaches a condition to it — as a condition of enabling invisible mode, you must reference Cloudflare's Turnstile Privacy Addendum in your own privacy policy.
- Managed can be interactive. Non-interactive and invisible cannot.
- Managed and non-interactive occupy layout space. Invisible has no visual footprint.
- All three run the same underlying challenge platform; the mode governs presentation and whether a click is ever demanded.
Widget states, and where an interaction can appear
A widget moves through loading (processing), interaction (visitor checks the box, managed mode only) and success. That parenthetical is the single most useful fact on this page for identification: if you ever see a Turnstile checkbox, the widget is in managed mode.
Four documented error states replace success, and each one is a distinct visual:
| State | When it appears |
|---|---|
| Unknown error | An unknown error occurred during the challenge. The visitor can follow the troubleshooting guidance in the widget or reload. |
| Interaction timed out | A checkbox was presented and not interacted with for an extended period. The challenge must be reissued by reloading the page or the widget. |
| Challenge timed out | Verification completed but no further action was taken, so the outcome is no longer valid — for example a login page solved but never submitted. |
| Outdated or unsupported browser | The visitor's browser is not supported. |
Whatever the mode, the token that comes out is the same object: valid for five minutes, single-use, and rejected on replay by the siteverify endpoint with timeout-or-duplicate.
How the mode is set
In the dashboard, Turnstile lives at the account level. Select Add widget, then fill in the widget name, hostname management (the domains it will be deployed on), the widget mode, and optionally pre-clearance support. Select Create, then store the sitekey and the secret key. An existing widget's configuration is edited under its Settings and applied with Save.
Over the API, the widget object carries mode with exactly three values — managed, non-interactive, invisible — alongside sitekey, name, domains and clearance_level (no_clearance, jschallenge, managed, interactive). Note that region (world or china) cannot be changed after creation.
Everything here assumes automation against properties you own or are authorised to test — QA, CI, uptime monitoring, staging, and tuning your own anti-bot configuration. That is the boundary SolveGate is built for.
Data attributes change the presentation, not the mode
Implicit rendering is a script tag plus a container with the cf-turnstile class. Inside a form, an invisible input named cf-turnstile-response is created automatically and carries the token.
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> <form method="POST" action="/login"> <div class="cf-turnstile" data-sitekey="0x4AAAAAAAAA_target" data-size="flexible" data-appearance="interaction-only"></div> <button type="submit">Sign in</button> </form>
api.js must be fetched from that exact URL — proxying or caching it will break Turnstile when Cloudflare ships updates. Turnstile is hosted under challenges.cloudflare.com, so a Content Security Policy has to allow connections to that origin.
| Data attribute | Default | Values | What it does |
|---|---|---|---|
data-sitekey | required | your sitekey | Identifies the widget — and therefore the mode |
data-size | normal | normal, flexible, compact | Widget dimensions |
data-theme | auto | light, dark, auto | Visual theme |
data-language | auto | ISO 639-1, e.g. es, en-US | Widget language |
data-appearance | always | always, execute, interaction-only | When the widget becomes visible |
data-execution | render | render, execute | When the challenge runs and a token is generated |
data-action | — | alphanumeric, _, -, max 32 chars | Label returned at validation, for analytics |
data-cdata | — | alphanumeric, _, -, max 255 chars | Custom payload returned at validation |
data-response-field | true | true, false | Whether to create the hidden token input |
data-response-field-name | cf-turnstile-response | any | Name of that hidden input |
data-retry | auto | auto, never | Automatic retry on a failed challenge |
data-retry-interval | 8000 | positive integer < 900000 | Milliseconds between retries |
data-refresh-expired | auto | auto, manual, never | Behaviour when a token expires |
data-refresh-timeout | auto | auto, manual, never | Behaviour when an interactive challenge times out |
data-tabindex | 0 | any | tabindex of the widget iframe |
data-feedback-enabled | true | true, false | Visitor feedback link |
Callbacks follow the same pattern: data-callback, data-error-callback, data-expired-callback, data-timeout-callback, data-unsupported-callback, and the pair that matters for identification — data-before-interactive-callback and data-after-interactive-callback, invoked before and after the challenge enters interactive mode. With explicit rendering the same names are passed as object keys to turnstile.render(), minus the data- prefix.
Sizes apply to the two visible modes only. Invisible widgets have no visual footprint regardless of the size configured.
| Size | Width | Height | Use case |
|---|---|---|---|
normal | 300px | 65px | Standard implementation |
flexible | 100% (min 300px) | 65px | Responsive design |
compact | 150px | 140px | Space-constrained layouts |
The same restriction applies to appearance: always shows the widget from page load, execute reveals it once the challenge begins, and interaction-only reveals it only when interaction is required — but appearance modes affect visible widget types only, and invisible widgets are never shown whatever it is set to. data-appearance="interaction-only" on a managed widget is what produces a page that looks empty until a suspect visitor arrives; it is not the same thing as invisible mode.
How to tell which mode a site uses
Start with the markup. These are the reliable markers that Turnstile is present at all:
- A script tag for
https://challenges.cloudflare.com/turnstile/v0/api.js, optionally with?render=explicitand&onload=<fn>. - A container with
class="cf-turnstile"and adata-sitekeyattribute. - A
turnstile.render()call carrying asitekeyoption, for explicit rendering in single-page apps. - A hidden input named
cf-turnstile-responsein the submitted form — or whateverdata-response-field-namerenamed it to. - An iframe inserted into the container and served from
challenges.cloudflare.com, plus CSP entries allowing that origin.
What the markup will not tell you is the mode. The mode lives on the widget in Cloudflare's account configuration and travels with the sitekey; the Turnstile API exposes mode only for widgets in your own account. Reading the page gives you the sitekey, and then you have to observe.
Two observations settle most cases. If the container renders with zero height and nothing appears at any point, the widget is invisible. If a checkbox ever appears, the widget is managed, because interaction is a managed-mode state. A visible widget that solves without a prompt is the ambiguous case — that is managed passing silently, or non-interactive, and a single page load cannot separate them.
For a widget you own, or a sitekey whose hostname list includes the page you are testing on, render it explicitly and instrument the interactive callbacks:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=onTurnstileLoad" defer></script> <div id="probe"></div> <script> function onTurnstileLoad() { turnstile.render("#probe", { sitekey: "0x4AAAAAAAAA_target", "before-interactive-callback": function () { console.log("entered interactive challenge -> managed mode"); }, "after-interactive-callback": function () { console.log("left interactive challenge"); }, callback: function (token) { var box = document.querySelector("#probe").getBoundingClientRect(); console.log("height", box.height, "-> 0 means no visual footprint"); console.log("token chars", token.length); }, "error-callback": function () { console.log("challenge error"); } }); } </script>
If the sitekey you find is one of Cloudflare's documented dummy keys, you are looking at a test or staging build, not production traffic:
| Sitekey | Behaviour | Widget type |
|---|---|---|
1x00000000000000000000AA | Always passes | Visible |
2x00000000000000000000AB | Always fails | Visible |
1x00000000000000000000BB | Always passes | Invisible |
2x00000000000000000000BB | Always fails | Invisible |
3x00000000000000000000FF | Forces an interactive challenge | Visible |
Matching dummy secret keys exist for the server side: 1x0000000000000000000000000000000AA always passes validation, 2x0000000000000000000000000000000AA always fails, and 3x0000000000000000000000000000000AA returns the token-already-spent error.
Widget modes are not WAF challenge pages
A Turnstile widget is embedded by the site owner into their own page and works without routing traffic through Cloudflare. A WAF challenge page is served by Cloudflare in front of the origin, as an interstitial, before the page you asked for exists. They share a challenge platform but they are different surfaces, and they fail differently: a widget failure leaves you on the page with an unusable form, a WAF challenge failure leaves you never reaching the page.
Pre-clearance is the documented bridge between them. A widget configured with pre-clearance issues a cf_clearance cookie, which lets a visitor bypass WAF challenges on subsequent requests across the zone, including API requests, at the clearance level the customer set. That is why a login page can carry a Turnstile widget and the API calls after it can pass without further challenges.
SolveGate treats the two as separate targets: gate: "turnstile" for the embedded widget in any of its three modes, gate: "waf" for a Turnstile WAF challenge page. Those are the only two gates it handles — it does not solve reCAPTCHA, hCaptcha, GeeTest, FunCaptcha or AWS WAF.
Solving Turnstile against your own properties
For automation purposes the mode barely matters. Managed, non-interactive and invisible all resolve to the same thing on the wire — a sitekey, a page URL, and a token that your server-side validation will accept for five minutes, once. You send the same request whichever mode the widget was configured in.
curl -s https://api.solvegate.io/v1/solve \ -H "Authorization: Bearer $SOLVEGATE_KEY" \ -H "Content-Type: application/json" \ -d '{ "gate": "turnstile", "sitekey": "0x4AAAAAAAAA_target", "url": "https://staging.example.com/login" }'
A token typically comes back in under 1.5 seconds. Pass "async": true to return immediately and poll GET /v1/solve/{id} instead; retrieving a solve is free. Failed solves are never billed. Prepaid credits start at $0.40 per 1,000 solves and fall to $0.075 at volume, and the first 1,000 solves are free.
The SDKs are published as solvegate on npm (Node 18+) and PyPI (Python 3.9+). Both wrap auth, the error envelope, 429 backoff and async polling, and both take the same gate, sitekey, url and optional action arguments.
Common questions
No. The markup carries the sitekey; the mode is stored on the widget in the Cloudflare account that owns that sitekey. You can infer it by observing: nothing rendered means invisible, and a checkbox means managed, because interaction is a managed-mode state. A visible widget that never prompts could be either managed or non-interactive.
No. data-size takes normal, flexible or compact, and it applies to managed and non-interactive widgets only. Invisible is a widget mode set in the Cloudflare dashboard, and an invisible widget has no visual footprint regardless of the size configured.
interaction-only is a presentation setting on a visible widget: it stays hidden until an interaction is required, then appears. It only affects managed and non-interactive widgets. Invisible mode has no widget at any point and can never show one, whatever appearance is set to.
The mode is part of a widget's configuration, editable from that widget's Settings in the Turnstile dashboard and applied with Save. Region (world or china) is the field that cannot be changed after creation.
No. Whichever mode issued it, the Turnstile token is valid for five minutes, can be validated once, and a replayed token is rejected by siteverify with timeout-or-duplicate.
Yes. POST /v1/solve with gate: "turnstile", the sitekey and the page URL covers managed, non-interactive and invisible widgets, and gate: "waf" covers Turnstile WAF challenge pages. Use it against properties you own or are authorised to test.
Related
More in Glossary
Automating a gate you own or are authorised to test?
// SolveGate clears Cloudflare Turnstile and WAF challenges through one REST call · first 1,000 solves free