Explainer
Cloudflare's Challenge Platform and cf_chl Parameters Explained
What /cdn-cgi/challenge-platform, window._cf_chl_opt, the cf_chl cookies and the __cf_chl_ URL parameters are, and what an automated client should do.
By ZeroCaptcha Engineering6 min readPublished
The Cloudflare challenge platform is the machinery behind Cloudflare’s challenge pages
(“Just a moment…”) and its JavaScript detections. Its scripts are served from
/cdn-cgi/challenge-platform/ on the protected site’s own hostname, a challenge page carries
its settings in a window._cf_chl_opt object, the response carries the header
cf-mitigated: challenge, and a passed challenge ends with a cf_clearance cookie. The cf_chl_*
cookies and the __cf_chl_ URL parameters you may see along the way are internal to Cloudflare
and undocumented; the only piece a client can build on is cf_clearance.
This explainer takes each visible piece in turn, with what Cloudflare documents about it, as checked on 1 October 2026. Automate only sites you are allowed to: see responsible captcha automation.
The pieces of a challenge response
When a WAF rule, Bot Management or a rate limiting rule decides to challenge a request, Cloudflare answers with an interstitial page instead of the site’s content. Here is what an HTTP client sees:
| Piece | What it is | Documented? |
|---|---|---|
Status 403 |
Cloudflare lists “WAF Custom or Managed Rules with challenge or block actions” among its causes of a 403 | Yes |
cf-mitigated: challenge header |
Set on every challenge page; “challenge” is its only value | Yes |
Content-Type: text/html |
“All challenge responses have text/html as the content-type, even if you requested a different resource type” |
Yes |
Scripts under /cdn-cgi/challenge-platform/ |
The challenge’s code, served from the site’s own hostname | Yes, as a path to allow |
window._cf_chl_opt |
The challenge page’s settings object; Cloudflare sets cTplC: 1 in it when a custom template is in use |
Partly |
Cookies cf_chl_rc_i, cf_chl_rc_ni, cf_chl_rc_m |
“for internal use which allows Cloudflare to identify production issues on clients” | Yes, as internal |
Query parameters beginning __cf_chl_ |
Added to URLs by the challenge flow | No |
cf_clearance cookie |
Set when the visitor passes; proves the visitor passed | Yes |
The first scripts load from the site’s own origin, but the check itself also needs
challenges.cloudflare.com, the domain the Cloudflare Turnstile widget loads from too. Cloudflare
says that “Challenge Pages are issued through the Cloudflare Challenge Platform, which uses the
same underlying technology as Turnstile.” When a blocker or a network filter stops that domain,
the page asks you to unblock it
(see Please unblock challenges.cloudflare.com).
/cdn-cgi/challenge-platform
Cloudflare names the path in two places. Its JavaScript detections are injected as a script
whose path follows the pattern /cdn-cgi/challenge-platform/…, only “in response to requests for
HTML pages or page views, excluding AJAX calls”, and their result is stored in cf_clearance for
15 minutes. And its guidance for custom challenge pages says: “Do not block
/cdn-cgi/challenge-platform/” through the page’s Content Security Policy.
For a site owner, that means allowing the site’s own origin in script-src, using nonces for
inline scripts as the JavaScript detections page asks, and keeping Transform Rules that rewrite
response headers off challenge responses (the rule expression is below). A Cloudflare Turnstile
widget needs
https://challenges.cloudflare.com in script-src and frame-src as well, and pre-clearance
mode needs 'self' in connect-src for its calls to /cdn-cgi/.
For an automated client, /cdn-cgi/challenge-platform/ requests in a browser’s network log are a
sign that a challenge or JavaScript detections ran on that page view. They are not an API to call:
the scripts’ URLs and payloads are undocumented and change.
window._cf_chl_opt
A challenge page defines a JavaScript object named _cf_chl_opt on window. Cloudflare mentions
it once, in its custom challenge page requirements: it “sets cTplC: 1 in window._cf_chl_opt
when custom templates are active”. Nothing else about its fields is documented. In a browser you
drive, its presence is a quick check that you are looking at a challenge page rather than the site:
// Run in the page, for example with Playwright's page.evaluate().() => ({ challengePage: typeof window._cf_chl_opt === "object", title: document.title,});The header check below is better, because it needs no browser and no guess about page internals.
The _cf_chl URL parameters
While a challenge runs, the address bar can show query parameters whose names begin with
__cf_chl_. You may find such URLs in logs, in links people copy from their browser, or even in
search results for Cloudflare’s own documentation. Cloudflare’s documentation, checked on
1 October 2026, does not describe them. What follows is our advice, not Cloudflare’s:
- Strip them before you store or queue a URL. They make the same page look like many different URLs, which fills a crawler’s queue with duplicates.
- Don’t treat them as a pass. The documented proof of a passed challenge is the
cf_clearancecookie. Nothing in the documentation says a URL parameter grants access, so don’t build on one. - Don’t replay them. They belong to one visitor’s challenge.
This Python helper removes them and keeps every other parameter:
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
def strip_challenge_params(url): parts = urlsplit(url) query = [ (name, value) for name, value in parse_qsl(parts.query, keep_blank_values=True) if not name.startswith("__cf_chl_") ] return urlunsplit(parts._replace(query=urlencode(query)))
print(strip_challenge_params("https://shop.example.com/item?id=7&__cf_chl_example=abc"))The cf_chl cookies and cf_clearance
The cf_chl_rc_i, cf_chl_rc_ni and cf_chl_rc_m cookies are, in Cloudflare’s words, “for
internal use which allows Cloudflare to identify production issues on clients”. Cloudflare sets the
Partitioned attribute on them and on cf_clearance, and cf_clearance also carries
SameSite=None; Secure, so “a clearance obtained in one top-level context is not reused in a
different top-level context”.
cf_clearance is the result. It “proves to Cloudflare that the visitor is a verified human and has
passed Cloudflare’s client-side verifications”, it lasts for the zone’s Challenge Passage, and it is
tied to the visitor and device that earned it: in practice the IP address and user agent. The
cf_clearance cookie explained covers how to use one, and
the __cf_bm cookie the bot-detection cookie beside it.
Detect a challenge in code
Cloudflare documents one reliable signal: the cf-mitigated header. Its own example is
JavaScript:
const response = await fetch("https://shop.example.com/api/items");if (response.headers.get("cf-mitigated") === "challenge") { console.log("Cloudflare challenged this request; it needs a cf_clearance cookie.");} else { console.log(response.status);}A site owner can also match challenge responses in rules: Cloudflare’s example for keeping
Transform Rules off challenge pages is
not cf.response.error_type in {"managed_challenge" "iuam" "legacy_challenge" "country_challenge"},
which names the kinds of challenge response the field reports (iuam is
Under Attack mode).
Getting past it, where you are allowed to
A challenge page is passed by a browser that runs its scripts, or by a service that does so for you. ZeroCaptcha’s challenge task passes the page through your own proxy and returns the cf_clearance cookie with the user agent it is bound to, which your client then sends through the same proxy. See Cloudflare WAF and 5-second challenges and the Cloudflare WAF and 5-second challenge solver. If a page keeps coming back after you pass it, the challenge loop article lists the causes.
Sources
- Cloudflare challenges: challenge pages (checked 1 October 2026).
- Cloudflare challenges: detect a challenge response (checked 1 October 2026).
- Cloudflare challenges: additional configuration,
for
/cdn-cgi/challenge-platform/,window._cf_chl_optandcf.response.error_type(checked 1 October 2026). - Cloudflare challenges: clearance (checked 1 October 2026).
- Cloudflare challenges: challenge solve issues (checked 1 October 2026).
- Cloudflare challenges: JavaScript detections (checked 1 October 2026).
- Cloudflare: Cloudflare cookies and SameSite cookie interaction with Cloudflare (checked 1 October 2026).
- Cloudflare: Error 403 (checked 1 October 2026).
- Cloudflare Turnstile: Content Security Policy (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.