glossary · cloudflare turnstile

Cloudflare Turnstile pre-clearance

Pre-clearance is a Turnstile widget setting that makes a solved widget issue a cf_clearance cookie in addition to the usual response token. On the Cloudflare zone the widget is embedded on, that cookie lets subsequent requests — including fetch and XHR calls that cannot render a challenge page — pass WAF challenges at or below the clearance level you configured, for the length of the zone's Challenge Passage window.

What pre-clearance actually does

A default Turnstile widget produces one thing: a response token in the cf-turnstile-response field. You send that token to your backend, your backend calls siteverify, and that is the whole loop. Cloudflare's edge is not involved in the decision — your application is.

Pre-clearance adds a second artefact. When the widget's clearance_level is set to anything other than no_clearance, solving the widget also sets a cf_clearance cookie for the zone the widget is served from. That cookie is read by Cloudflare's edge, before your origin sees the request, and it satisfies WAF challenges at or below the level you chose.

The two artefacts are independent and behave differently. Enabling pre-clearance does not remove your obligation to verify the token.

Turnstile response tokencf_clearance cookie
Consumed byyour backend, via siteverifyCloudflare's edge, before your origin
Lifetime300 secondsthe zone's Challenge Passage window (default 30 minutes)
Reusesingle use; a replay returns timeout-or-duplicatereusable within the window; bound to the visitor and device
Scopewhatever your application decidesthe Cloudflare zone the widget is embedded on
On by defaultyesno — clearance_level defaults to no_clearance

The four clearance levels

Clearance level is a property of the widget, set at creation or update. Cloudflare exposes four values through the clearance_level field on the Turnstile widgets API, and the same choice appears in the dashboard when you answer the pre-clearance question.

LevelAPI valueChallenges it clears
Interactive (high)interactivenon-interactive, managed and interactive challenges
Managed (medium)managednon-interactive and managed challenges
Non-interactive (low)jschallengenon-interactive challenges only
Off (default)no_clearancenone — no clearance cookie is issued

The jschallenge value is the odd one out by name. It maps to what Cloudflare's current documentation calls a non-interactive challenge — the JavaScript-only check that runs without visitor input.

Clearance is hierarchical in one direction. A cookie carrying a higher level satisfies challenges at that level and below. A cookie carrying a lower level does not satisfy a higher-level challenge: a visitor holding non-interactive clearance who then hits a rule with a Managed Challenge action has to solve again.

Cloudflare documents that all widgets start with pre-clearance mode set to false and clearance set to no_clearance. Nothing happens until you change it.

How it interacts with WAF custom rules

There is no rule to write on the consuming side. Cloudflare states that clearance cookies issued by a Turnstile widget are automatically applied to the zone the widget is embedded on, with no configuration necessary. Your existing WAF custom rules keep the expressions and actions they already have; the clearance cookie changes their outcome for cleared visitors.

This only concerns challenge actions. A rule whose action is Managed Challenge, JS Challenge or Interactive Challenge has something for a clearance cookie to satisfy. A rule whose action is Block, Skip or Log does not issue a challenge at all, so clearance is irrelevant to it — pre-clearance is not a way to make a blocked request succeed.

One prerequisite is hard: the hostname configured on the Turnstile widget must match the zone carrying the WAF rules. A widget served from a hostname outside that zone will hand back a token as usual and set no useful clearance.

Challenge Passage — the setting that governs how long the cookie counts — applies to WAF custom rules and IP Access rules. Cloudflare explicitly documents that it does not apply to rate limiting rules. Treat a rate limiting rule with a challenge action as something pre-clearance will not quietly absorb, and test it rather than assuming.

Because a valid cookie is reusable for the whole window, Cloudflare recommends adding a rate limiting rule keyed on the cf_clearance cookie value, so that one legitimately obtained cookie cannot be used to push an unreasonable request volume.

cf_clearance: lifetime, size and revocation

The cookie is not a Turnstile-specific object. cf_clearance is the same cookie Cloudflare sets when a visitor passes an ordinary interstitial challenge page; pre-clearance is a second way to obtain it. Cloudflare's own description is that it proves the visitor passed client-side verification.

  • Validity follows the zone's Challenge Passage setting. The default is 30 minutes, and Cloudflare recommends keeping it between 15 and 45 minutes.
  • When the edge evaluates the cookie it adds documented slack: a few extra minutes for clock skew, and an additional hour for XmlHTTP requests so that in-flight API calls are not cut off mid-session.
  • The cookie cannot exceed 4096 bytes. JavaScript detection results are carried inside it, so the payload is not a bare opaque nonce.
  • It is bound to the visitor and device it was issued to. Copying it to another machine is expected to fail, by design.

Expiry is not the only way clearance ends. Cloudflare describes a second component it calls precursor clearance: an ongoing client-side process that keeps reassessing behaviour during the session. If it decides the session looks suspicious it can reduce or invalidate the challenge clearance, and the visitor gets re-challenged while the cookie is still nominally within its window. A page that assumes clearance holds for the full 30 minutes will occasionally be wrong.

Enabling pre-clearance

In the dashboard, open Turnstile, add a widget or open an existing one's settings, answer yes to the pre-clearance question, pick a clearance level, and save. Over the API, set clearance_level on the widget create or update call to jschallenge, managed or interactive.

Pre-clearance is a property of the sitekey, not of the render call. Cloudflare documents no data attribute and no turnstile.render option that turns it on — the same sitekey either issues clearance everywhere it is embedded, or nowhere. If you want cleared and uncleared flows on one site, use two widgets.

On the client, the only visible difference is the success callback. With pre-clearance active the callback receives a second argument alongside the token, indicating whether clearance was obtained. Cloudflare's own example names it preClearanceObtained and gates the retry on it rather than on the token.

The fetch and XHR case it was built for

The original problem is narrow and worth stating plainly. A browser doing fetch() against a challenged endpoint expects JSON and gets an HTML challenge page instead. There is no document context to render it in, so the challenge can never be solved and the call fails. Pre-clearance moves the challenge earlier: the visitor solves a widget in the page, clearance lands, and the API call goes through.

Challenge responses carry a cf-mitigated header with the value challenge, which is what makes the retry pattern possible. Cloudflare's published approach wraps fetch, watches for that header, renders a pre-clearance widget, and replays the original request once clearance is obtained.

js
const originalFetch = window.fetch;

window.fetch = async function (...args) {
  let response = await originalFetch(...args);

  if (response.headers.get('cf-mitigated') === 'challenge') {
    await new Promise((resolve, reject) => {
      turnstile.render('#turnstile_widget', {
        sitekey: 'YOUR_SITEKEY',
        'error-callback': reject,
        callback: (token, preClearanceObtained) => {
          if (preClearanceObtained) resolve(token);
        },
      });
    });

    // Clearance cookie is set; replay the original request.
    response = await originalFetch(...args);
  }

  return response;
};

Note what this pattern does and does not give you. It gets the request past the edge. It does not authenticate the request — the token in that callback is still the thing your backend should be verifying with siteverify if the endpoint needs per-request proof.

What the documentation does not say

Pre-clearance is thinly documented compared with the rest of Turnstile. Several things people assume are unconfirmed. If your design depends on any of these, test it against your own zone rather than trusting a blog post.

  • The cookie attributes are not published. Domain, path, Secure, HttpOnly and SameSite values for cf_clearance are not stated in the pre-clearance or clearance documentation, so subdomain behaviour within a zone is not something you can read off the docs.
  • Whether clearance obtained from a widget also clears challenges issued by Bot Management or Super Bot Fight Mode is not spelled out. The pre-clearance page frames the effect in terms of firewall and WAF challenge rules.
  • Whether the clearance level you can request is capped by the widget's mode is not documented. Nothing states that an invisible or non-interactive widget is prevented from issuing interactive clearance.
  • The API reference for widget create does not print a default for clearance_level; the default of no_clearance comes from the pre-clearance guide.
  • The precursor clearance mechanism has no documented thresholds, signals or configuration surface. It is described qualitatively only.
  • Whether clearance obtained on one zone has any effect on another zone in the same account is not addressed. The consistent framing is single-zone.

Testing pre-clearance on a zone you own

Pre-clearance is the kind of configuration that breaks quietly: a widget hostname drifts out of the zone, a level gets set one notch too low, a rate limiting rule keeps challenging when everyone assumed it would not. That makes it worth exercising from CI or an uptime check rather than by hand, against staging and production properties you own or are authorised to test.

SolveGate returns Turnstile tokens through a single call. gate: "turnstile" covers an embedded widget — including one you have put behind pre-clearance — and gate: "waf" covers the Cloudflare challenge interstitial that a WAF rule serves when clearance is absent or expired. Tokens typically come back in under 1.5 seconds.

bash
curl -s https://api.solvegate.io/v1/solve \
  -H "Authorization: Bearer $SOLVEGATE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gate": "turnstile",
    "sitekey": "0x4AAAAAAA...",
    "url": "https://staging.example.com/login"
  }'

Poll GET /v1/solve/{id} for a result if you are not waiting inline; polling is free. Credits are prepaid at $0.40 per 1,000 solves, falling to $0.075 at volume, failed solves are never billed, and the first 1,000 solves are free. SDKs are published as solvegate on npm (Node 18+) and PyPI (Python 3.9+).

Common questions

No. The clearance cookie is consumed by Cloudflare's edge and says nothing to your application. The response token is still valid for 300 seconds, still single use, and still needs a siteverify call. Cloudflare's pre-clearance guide repeats this explicitly.

Set the lowest level that clears the challenge actions your rules actually use. If your WAF custom rules use Managed Challenge, managed is enough; interactive grants strictly more than that, and clearance granted is clearance you cannot take back until the window expires.

As long as the zone's Challenge Passage setting, which defaults to 30 minutes and is recommended between 15 and 45. Cloudflare adds a few minutes of slack for clock skew and an extra hour for XmlHTTP requests. Precursor clearance can invalidate it earlier if the session looks suspicious.

Do not assume so. Cloudflare documents that Challenge Passage does not apply to rate limiting rules, and rate limiting is listed separately from WAF custom rules as a challenge issuer. Test the specific rule rather than inferring the behaviour.

None is documented. Pre-clearance is set on the widget itself, in the dashboard or through the clearance_level field on the Turnstile widgets API. The only client-side sign of it is the second argument passed to the success callback.

No. The widget hostname must match the zone that carries the WAF rules. Cloudflare lists this as the prerequisite, and clearance is applied to the zone the widget is embedded on.

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