Skip to content
ZeroCaptcha

Cloudflare WAF and 5-second challenges

Some sites answer a first visit with a Cloudflare challenge page instead of the page itself. It goes by several names, all one thing to solve:

  • A Cloudflare WAF challenge: a WAF rule (a custom, rate limiting or IP Access rule) whose action is Managed Challenge, Non-Interactive Challenge or Interactive Challenge. Bot Fight Mode and Under Attack mode show the same page.
  • “Just a moment…” or “Checking your browser”: the interstitial page itself, answered with HTTP 403 and the header cf-mitigated: challenge.
  • The 5-second challenge: the old name for Cloudflare’s JavaScript challenge, after the few seconds its page took. Today it is a Managed or Non-Interactive Challenge (js_challenge), which Cloudflare says typically takes less than five seconds.

A CloudflareChallengeTask passes that page for you and returns what a browser gets for passing it: the cf_clearance cookie, and the user agent the cookie is bound to. Send both with your requests to the site, through the same proxy, and the site serves its pages. A Cloudflare block, such as error 1020, is a refusal rather than a challenge: no task passes it.

A challenge task is priced, held and charged like any other task: the price shows in the price list, and nothing is charged unless the task is solved.

cf_clearance is the cookie Cloudflare sets when a visitor passes a challenge. While it is valid, the site lets that visitor through without challenging it again. Cloudflare ties it to “the specific visitor and device it was issued to”, so in practice it is accepted only:

  • from the same IP address that earned it: so a challenge task always runs through your proxy, and you use the clearance through that proxy;
  • with the same user agent that earned it: the User-Agent header in solution.userAgent, exactly;
  • for as long as the site allows: its Challenge Passage setting, 30 minutes by default. We serve the clearance for 30 minutes after it is issued (tokenExpiresAt), then delete it 10 minutes later.

A client whose TLS handshake does not look like the browser the user agent names may be challenged again, whatever its cookie: Cloudflare’s bot detection looks at TLS fingerprints as well as headers. A plain HTTP library’s handshake does not look like Chrome’s. For sites that check, use a client that impersonates the browser, such as curl-impersonate, or a real browser.

A cookie earned from our solver’s address would be refused from yours, so there is no proxyless challenge task: a CloudflareChallengeTaskProxyless is refused, with validation_failed on REST and ERROR_TASK_NOT_SUPPORTED in the createTask format, and nothing is held. Your proxy also looks the page up and connects to it, so the solve comes from the address you will use.

POST /v1/tasks with the page and your proxy. A challenge page has no widget, so the task takes no websiteKey, action or cdata; sending one is refused.

Field Required What it is
type Yes CloudflareChallengeTask. CapSolver’s name, AntiCloudflareTask, works too.
websiteURL Yes The page behind the challenge: a public http or https page.
proxy Yes Your proxy, http or https, with its port, such as http://user:pass@proxy.example.net:8080. The same rules apply as for TurnstileTask: a public host, and a port no other protocol reserves.
callbackUrl No Where to POST the result when the task ends. See Polling and callbacks.

The same checks as a Turnstile task apply before the task is held and again before each attempt: the page must be on a public domain and not on the blocklist, and your proxy must resolve to public addresses only. Your proxy’s password is never logged, and it is deleted when the task ends.

Terminal window
curl "$ZEROCAPTCHA_API/v1/tasks" \
-H "Authorization: Bearer $ZEROCAPTCHA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type": "CloudflareChallengeTask", "websiteURL": "https://shop.example.com/",
"proxy": "http://user:pass@proxy.example.net:8080",
"callbackUrl": "https://example.com/zerocaptcha/callback"}'

The SDKs do all of this in one call: solveChallenge in Node, solve_challenge in Python and SolveChallenge in Go return the clearance and its user agent.

Read the task with GET /v1/tasks/{id} until it ends. A solved one carries the clearance:

{
"id": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b",
"type": "CloudflareChallengeTask",
"kind": "cloudflare",
"status": "succeeded",
"websiteURL": "https://shop.example.com/",
"websiteKey": null,
"usesProxy": true,
"solution": {
"token": "Dyw1BhDnEAGRy5fh…",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
"cookie": { "name": "cf_clearance", "value": "Dyw1BhDnEAGRy5fh…", "expiresAt": null }
},
"tokenState": "available",
"tokenIssuedAt": "2026-09-30T14:02:14Z",
"tokenExpiresAt": "2026-09-30T14:32:14Z"
}
Field What it is
solution.cookie.value The cf_clearance cookie’s value. solution.token holds the same value.
solution.userAgent The User-Agent to send with the cookie.
solution.cookie.expiresAt When the site stops accepting the cookie, if it is known; null when it is not, as today. The site’s own setting decides (its Challenge Passage, 30 minutes by default), and the solver does not learn it.
tokenExpiresAt Until when the API serves the clearance: 30 minutes after it was issued. It is deleted 10 minutes after that.

In the createTask format, getTaskResult answers as CapSolver’s AntiCloudflareTask does:

{
"errorId": 0,
"taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b",
"status": "ready",
"solution": {
"token": "Dyw1BhDnEAGRy5fh…",
"type": "cloudflare",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
"cookies": { "cf_clearance": "Dyw1BhDnEAGRy5fh…" }
},
"cost": "0.001200",
"createTime": 1790776925,
"endTime": 1790776934,
"solveCount": 1,
"expiresAt": "2026-09-30T14:32:14Z"
}

A createTask for a challenge page ignores the fields other providers take for one, such as userAgent and html, and any websiteKey, action or cdata.

Send the cookie and the user agent with each request to the site, through the proxy that earned them. Reuse them for every request until the site challenges you again, then create a new task.

Terminal window
curl "https://shop.example.com/" \
--proxy "$PROXY_URL" \
-H "User-Agent: $USER_AGENT" \
-H "Cookie: cf_clearance=$CF_CLEARANCE"

A client that impersonates the browser’s TLS handshake, such as curl-impersonate, keeps the clearance accepted where plain HTTP libraries may be challenged again. When the site challenges you again, its clearance has ended: create a new task.

In a browser you drive, set the cookie for the site’s domain and the browser’s user agent to solution.userAgent before loading the page, and route the browser through the same proxy. See Browser automation.

The Cloudflare WAF managed challenge test page, the Cloudflare 5-second JS challenge test page and the Cloudflare WAF interactive challenge test page each sit behind a Cloudflare WAF rule of that kind, and show whether a request carried a clearance. Point a challenge task at one to see the whole flow, then load the page with its clearance. Every test page is on the Cloudflare Turnstile demo and CAPTCHA test pages.

A challenge that is not passed after every attempt fails with ERROR_CAPTCHA_UNSOLVABLE, and one still unsolved at its deadline expires with ERROR_TASK_TIMEOUT; neither is charged. A proxy that resolves to a private address by the time the task runs fails with ERROR_PROXY_NOT_ALLOWED. See error codes for every code.