Skip to content

Explainer

Cloudflare WAF Bypass: What Gets an Automated Client Through

Looking for a Cloudflare WAF bypass? What each WAF action does to a scraper, which ones can be passed, which only the site owner can lift, and the request.

By 7 min readPublished

There is no general Cloudflare WAF bypass, and what gets an automated client through depends on which action the site’s rule took. A challenge action (Managed, Non-Interactive or Interactive Challenge) shows the “Just a moment…” page, and passing it earns a cf_clearance cookie that lets later requests through. A Block action, such as error 1020, refuses the request, and only the site’s owner can lift it. A rate limit (error 1015) means slow down. So the useful question is not how to bypass the WAF, but which of the three you met, and whether you are allowed to be there.

This article sorts out what people mean by “bypass”, how to tell the actions apart from the response, and the full request that passes a WAF challenge, as Cloudflare documented it on 1 October 2026. Only automate sites you are allowed to: your own, a client’s, or one whose terms permit it. See responsible captcha automation.

What “bypass” usually means

Four different things get called a Cloudflare WAF bypass. Only two are something an automated client should do.

What people mean What it is Should you
Passing the challenge Running Cloudflare’s challenge to the end, as a browser does, and keeping the cf_clearance cookie it earns Yes, on sites you may automate. It is what the challenge asks for
Being exempted The owner allows your address, skips rules for your traffic, or lets your bot in as a verified bot Yes: it is the owner’s own decision, and the most reliable route for a partner or a long-running feed
Going around Cloudflare Sending requests straight to the site’s origin server, past the WAF No. It defeats protection the owner chose, and ZeroCaptcha does nothing of the kind
Disguising the client Changing user agents, addresses or TLS fingerprints until a Block rule stops matching No. A Block rule is a decision the owner made on purpose

Cloudflare’s own words for the first route: the cf_clearance cookie “enables visitors to bypass WAF Challenges” at its clearance level. That is the only bypass this article covers.

Which WAF action did you meet?

A Cloudflare WAF custom rule pairs an expression with an action. Its terminating actions are Block (“Matching requests are denied access to the site”), and the three challenges: Managed Challenge, Non-Interactive Challenge (API value js_challenge, often still called the JS Challenge, and once the 5-second challenge) and Interactive Challenge. Rate limiting rules take the same actions once a client goes over a count. What each one does to your client:

Action What your client gets What gets it through
Managed Challenge HTTP 403, cf-mitigated: challenge, the “Just a moment…” page Passing the challenge: a Managed or Interactive clearance
Non-Interactive Challenge (JS, the old 5-second challenge) The same Passing the challenge: a clearance of any level
Interactive Challenge The same Passing the challenge: an Interactive clearance
Block Usually HTTP 403 with a 1xxx code, such as 1020, or the owner’s custom response Nothing on your side: only the owner can change the rule
Rate limiting rule HTTP 429 (error 1015) for a block, or a challenge page Fewer requests; for rate limiting, “The Challenge Passage does not apply”
Skip Nothing visible: the request continues Nothing to do

Every challenge page carries the response header cf-mitigated: challenge, which is the reliable way to tell a challenge from a block. This function sorts a response into the rows above:

import requests
def waf_verdict(url: str) -> str:
"""What a Cloudflare WAF did with one request, from the response alone."""
response = requests.get(url, timeout=30)
if response.headers.get("cf-mitigated") == "challenge":
return "challenged: pass the challenge once, then reuse cf_clearance"
if response.status_code == 429:
return "rate limited: slow down, a clearance does not help"
if response.status_code == 403:
return "refused: a 1xxx code in the body, such as 1020, is a Block only the owner can lift"
return f"served: HTTP {response.status_code}"
print(waf_verdict("https://shop.example.com/"))

The 5-second challenge and “Just a moment…” and “Checking your browser” articles cover the challenge page itself, and Cloudflare WAF rules explained has every action, the plan limits and the order the rules run in.

Passing a WAF challenge with one request

A challenge page is passed by a browser that runs Cloudflare’s checks, from one address, with one user agent. The cookie it earns is tied, in Cloudflare’s words, to “the specific visitor and device it was issued to”, which in practice means that address and that user agent. So a challenge is solved through your own proxy, and you use the result through the same proxy.

ZeroCaptcha’s CloudflareChallengeTask does this: you send the page and your proxy, and the task returns the cf_clearance cookie with the user agent it was issued for. The whole request, from the shell, with every field a real integration sends:

#!/usr/bin/env bash
# Pass a Cloudflare WAF challenge on a site you may automate, then fetch the page with the clearance.
set -euo pipefail
API=${ZEROCAPTCHA_API:-https://api.zerocaptcha.io}
KEY=${ZEROCAPTCHA_KEY:?Set ZEROCAPTCHA_KEY to your API key, zc_live_..., from the dashboard.}
PROXY=${PROXY_URL:?Set PROXY_URL to your proxy, such as http://user:pass@proxy.example.net:8080.}
PAGE=https://shop.example.com/
# 1. Create the task: the page behind the challenge (websiteURL), your proxy, where to POST the
# result when the task ends (callbackUrl), and an Idempotency-Key, so a retried request returns
# the same task instead of a second, paid one. A challenge page has no sitekey, so a challenge
# task takes no websiteKey.
TASK_ID=$(curl -sS --fail-with-body "$API/v1/tasks" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"type\": \"CloudflareChallengeTask\", \"websiteURL\": \"$PAGE\", \"proxy\": \"$PROXY\",
\"callbackUrl\": \"https://example.com/zerocaptcha/callback\"}" | jq -r .id)
# 2. Read the task every 2 seconds until it ends, or wait for the callback instead.
while :; do
TASK=$(curl -sS "$API/v1/tasks/$TASK_ID" -H "Authorization: Bearer $KEY")
STATUS=$(jq -r .status <<<"$TASK")
if [ "$STATUS" != queued ] && [ "$STATUS" != running ]; then break; fi
sleep 2
done
CLEARANCE=$(jq -r '.solution.cookie.value // empty' <<<"$TASK")
USER_AGENT=$(jq -r '.solution.userAgent // empty' <<<"$TASK")
if [ -z "$CLEARANCE" ]; then
jq -r '"\(.errorCode): \(.errorDescription)"' <<<"$TASK" >&2
exit 1
fi
# 3. Fetch the page with the cookie and exactly its user agent, through the same proxy.
curl -sS -o /dev/null -w '%{http_code}\n' "$PAGE" \
--proxy "$PROXY" \
-H "User-Agent: $USER_AGENT" \
-H "Cookie: cf_clearance=$CLEARANCE"

Reuse the cookie for every request until the site challenges you again, then create a new task: one task per session, not one per request. The price per 1,000 solved tasks is on the pricing page; a task that fails or expires costs nothing, and there is no free tier. The same request in Node, Python, Go and PHP, and the createTask format, are in the Cloudflare WAF and 5-second challenges docs.

What a solver cannot do

  • Lift a Block. A clearance passes challenges, at its level. Cloudflare’s clearance docs say nothing of lifting a Block, and a Block rule matches whether or not you hold a cookie. Error 1020 needs the owner.
  • Skip the proxy. A clearance earned from a solver’s address is refused from yours, so there is no proxyless challenge task: CloudflareChallengeTaskProxyless is refused before anything is held.
  • Fix a mismatched client. A client whose TLS handshake does not look like the browser its user agent names may be challenged again despite a valid cookie, since Cloudflare’s bot detection reads TLS fingerprints. Use a browser, or a client that impersonates one; see TLS fingerprints and Cloudflare.
  • Other vendors’ WAFs. ZeroCaptcha solves Cloudflare’s challenges only, not AWS WAF, Akamai or others; see WAF challenges across vendors.

If you run a feed for a partner, ask them to exempt your traffic instead: an IP Access rule that allows an address “will bypass any configured custom rules, rate limiting rules, WAF Managed Rules, and firewall rules”, which no solver can match for reliability. The Cloudflare WAF and 5-second challenge solver page has the rest of the task’s details.

Sources

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.

Questions

Can you bypass a Cloudflare WAF?

Not in general. A WAF rule that challenges a request can be passed by solving the challenge, which earns a cf_clearance cookie. A rule that blocks a request, such as error 1020, can only be lifted by the site's owner, who can change the rule or exempt your traffic.

Does a cf_clearance cookie get past every Cloudflare WAF rule?

No. Cloudflare documents the cookie as a way past WAF challenges, at its clearance level. It does nothing against a Block action or a rate limit, and it works only from the address and with the user agent that earned it.

Does ZeroCaptcha bypass Cloudflare's WAF?

No. It solves Cloudflare's challenge pages, the Managed, Non-Interactive (JS) and Interactive challenges a WAF rule shows, through your own proxy, and returns the cf_clearance cookie. It does not get past Block rules, find origin servers or hide traffic, and every task is paid.

Read next

This article is part of the Cloudflare WAF and 5-second challenge solver hub. Every task is charged only when a token is ready.

Get an API key