Cloudflare Error 1020 — "Access Denied" Explained and Fixed

Key takeaways

  • Error 1020 means your request matched a firewall (WAF) rule the site owner wrote. It is an access decision, not a speed limit.
  • 1020 does not time out. Waiting fixes Error 1015; it does nothing for 1020, because nothing about your request has changed.
  • The most common triggers are country blocking, ASN and datacenter IP-range blocking, VPN exit ranges, blocked user-agent strings, and missing or contradictory headers.
  • A request claiming to be Chrome in its User-Agent while presenting a Python or Go TLS handshake is one of the clearest automation signals there is — and spoofing the user-agent alone makes it worse, not better.
  • For developers, the real fix is a TLS-matching HTTP client such as curl_cffi, not a rewritten header string.
  • Every 1020 page carries a Ray ID. The site owner can look that ID up and see the exact rule you matched — it is the fastest route to a real answer.
  • If a site has deliberately blocked your country or every datacenter range, that is a stated preference, and working around it is a decision worth making consciously.

Error 1020 — Access Denied is the Cloudflare error people most often misdiagnose, because it looks superficially like every other Cloudflare block page and it sits one digit away from a completely different problem.

Here is the distinction that matters more than anything else on this page:

Error 1015 is a rate limit. It expires. Error 1020 is a firewall rule. It does not.

If you arrived here after waiting an hour and reloading to no effect, that is not bad luck. It is the expected behaviour. Nothing about your request changed, so the same rule matched again.

What Error 1020 actually means

Error 1020 means your request matched a WAF or custom firewall rule that the site owner configured with a block action. Cloudflare evaluated the request at its edge, found a condition the operator asked it to deny, and refused it before the origin server was ever contacted. The decision is about the request's characteristics, not its frequency.

Two things follow from that, and both are frequently missed.

First, this is the site owner's rule, not Cloudflare's opinion of you. Cloudflare ships managed rulesets that many sites enable, but the block conditions are switched on by the operator. Cloudflare support cannot lift it. The site owner can.

Second, "access denied" is literal. There is no threshold you dropped below, no counter winding down, and no cooldown. The rule is a boolean, and your request evaluated true. If the number on your page is 1015 rather than 1020, stop here — that is a rate limit that does expire, and every fix below is the wrong one for it.

Every 1020 page prints a Ray ID in small text at the bottom. That string is the identifier for your specific request in the site's Cloudflare firewall event log. If you ever need this resolved by a human, that ID plus a timestamp is what turns "your site blocked me" into a five-second lookup for them.

The triggers that actually cause 1020

Firewall rules can be written against almost any request property, but in practice a short list produces the overwhelming majority of real-world 1020s. Working down it in order is the fastest way to identify your own cause, because the first three are visible without touching any code.

TriggerWho it hitsHow to confirm it
Country blockingOrdinary visitors abroad, travellers, VPN usersTry the site from a connection in a different country
ASN / IP-range blockingAnything from a hosting provider, cloud instance, or datacenter proxyCompare a home connection against a server request
VPN exit rangesConsumer VPN usersDisconnect the VPN and reload
User-agent blockingScripts using default library UAs, old browsers, headless signaturesCompare a real browser against your client
Missing or malformed headersHTTP clients that send four headers where a browser sends fifteenDiff your request against a browser's, header by header
Known-bot signaturesHeadless Chrome with automation flags, common scraping frameworksTest the same URL in a normal browser window
TLS / HTTP2 fingerprint mismatchAny client claiming to be a browser it does not resemble at the transport layerSee the fingerprint section below
Path or method rulesRequests to /wp-login.php, /admin, unusual verbsTry the site's homepage instead

ASN blocking deserves a specific mention because it catches people who did nothing wrong: if you deploy an application on a major cloud provider and it makes outbound requests to a site that blocks hosting ASNs, your perfectly legitimate integration gets a 1020 on its first call, forever, from a clean IP address with no history at all.

Fixes if you are an ordinary visitor

You almost certainly matched a network-level rule rather than anything you did. Work down this list — the first two resolve most consumer reports, and the whole sequence takes under five minutes. Nothing here requires technical knowledge or changing settings you will struggle to reverse.

  1. Disconnect your VPN and reload. This is the highest-hit-rate fix by a wide margin. Blocking known VPN and hosting ASNs is a checkbox in Cloudflare, and plenty of sites tick it.
  2. Try a completely different network. Switch from Wi-Fi to mobile data, or the reverse. If mobile data works and home Wi-Fi does not, your broadband address or its whole range is what matched.
  3. Check whether your country is blocked. If the site is a regional retailer, a government service, or a publisher with licensing restrictions, geoblocking is likely and is deliberate. This is not a bug you can report.
  4. Clear cookies for that domain, then reload. A stale or corrupted cookie can match a rule written against a specific value. This is quick and occasionally decisive.
  5. Try a different browser, and a private window. This isolates extensions. Aggressive privacy extensions strip or reorder headers, and a request missing headers every real browser sends is a rule that some sites do block on.
  6. Disable "secure DNS" or proxy-style browser features temporarily. Browser-level relays and DNS proxies can route you through ranges the site treats as datacenter traffic.

If all six fail and the site is one you need, contact them with the Ray ID. That is not a consolation prize — it is the only mechanism that actually exists for lifting a rule someone else wrote.

Fixes if you are a developer

If your code gets a 1020 while a browser on the same machine loads the page fine, the address is not the problem — your client is. The gap is almost never the user-agent string, and this is the section where most people are working with genuinely bad information from tutorials written years ago.

Headers: the whole set, not one string

A real Chrome request sends a substantial, consistently ordered set of headers: Accept, Accept-Language, Accept-Encoding, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Sec-Fetch-User, Upgrade-Insecure-Requests, and the sec-ch-ua client hints. A default requests call sends four headers, in a different order, with none of the Sec- family.

Copying only the User-Agent across produces the worst of both worlds: a request that claims to be Chrome while lacking every other thing Chrome sends. Copy the full set from your browser's network tab, keep the order, or use a library that does it for you.

TLS and HTTP/2 fingerprinting: the real tell

This is the part that defeats header spoofing entirely, and it is worth understanding rather than working around blindly.

Before a single HTTP header is sent, your client performs a TLS handshake. The exact cipher suites offered, their order, the extensions present, the elliptic curves, and the ALPN values form a fingerprint — commonly expressed as JA3 or the newer JA4 family. Python's requests on OpenSSL produces one fingerprint. Chrome on BoringSSL produces a completely different one. Go's net/http produces a third. The same applies one layer up, where HTTP/2 SETTINGS frames and header-frame pseudo-header order differ per client.

So a request that says User-Agent: Chrome/xxx while presenting a Python TLS fingerprint is not merely unconvincing. It is self-contradictory, and a contradiction is a far stronger detection signal than an honest python-requests/2.x would have been.

The actual fix is a client that matches at the transport layer:

# curl_cffi impersonates a real browser's TLS + HTTP/2 fingerprint,
# not just its headers.
from curl_cffi import requests

r = requests.get("https://example.com", impersonate="chrome")
print(r.status_code)

Equivalent options exist in other ecosystems — tls-client in Python and Go, utls-based clients in Go, and running a real browser under Playwright or Puppeteer when you need full parity. What they share is that they change what the connection looks like, not just what the request claims.

The rest of the checklist

When this becomes an infrastructure problem

Once your client is fingerprint-consistent, carries a real session, and still gets a 1020 from a cloud host but not from your laptop, you have narrowed the cause to your egress range. That is an infrastructure constraint rather than a coding one, and no amount of client work resolves it.

Before spending money on it, though, be honest about which situation you are in. A country block or a blanket datacenter block is a stated preference by the site owner. It is not a misconfiguration and not an accident. Routing around it is a decision — sometimes an entirely defensible one, as with an internal monitoring job for infrastructure you own, or a compliance team collecting evidence, and sometimes not. That call is yours, and it is worth making deliberately rather than by default.

Where routing does make sense, the type of egress address is what changes the outcome:

Egress typeHow ASN rules treat itPractical effect
Cloud / hostingBlocked wholesale by many sitesThe ASN is published; blocking it costs the site no real users
Commercial VPNBlocked by default in many managed rulesetsExit ranges are enumerable and widely shared
Shared residential poolMixedIndividual addresses look ordinary, but pooled reputation follows you
Mobile carrier (4G/5G)Rarely blocked at ASN levelBlocking a carrier ASN blocks that carrier's ordinary phone customers

The last row is the entire mechanism behind mobile proxies, explained properly in what is a mobile proxy. Whether you want one address held over time or many rotating is a separate question, covered in dedicated vs rotating proxies.

Now the caveats that proxy vendors tend to leave out:

A mobile IP does not fix a 1020 caused by your client. If the rule matched your user-agent, your missing headers or your TLS fingerprint, changing the address changes nothing at all. Fix the client first; you will often find you never needed to change networks.

A mobile IP does not make you undetectable. It removes one specific reason to block you — the ASN — and leaves every behavioural and fingerprint signal exactly where it was. The same limitation applies to the IP-reputation side of YouTube's bot prompt.

Shared mobile pools carry shared reputation. If other customers rotate through the same addresses, their firewall history becomes yours. A dedicated device with one tenant is what removes that variable — QuantumProxy sells exactly that shape, though the reasoning holds no matter who you buy from.

The diagnostic that saves the most time

Run this before anything else, because it splits the problem cleanly into two branches:

Send the same request from two places — your laptop's home connection and wherever your code runs — and separately, load the same URL in a normal browser from each.

If the browser works everywhere and your client fails everywhere, it is a client problem: headers and fingerprint. If the browser also fails from one location only, it is a network problem: ASN, country or range. If both fail everywhere including a plain browser at home, the rule is matched on something specific to the path or your account, and the Ray ID is the only route left.

Two minutes of that beats two hours of changing user-agent strings and hoping.

Frequently asked questions

How long does Cloudflare Error 1020 last?

Indefinitely, until something about your request changes. Unlike Error 1015, which is a rate limit with a timer, 1020 is a firewall match. If you send the same request from the same address with the same headers tomorrow, you will get the same 1020.

What is the difference between Error 1020 and Error 1015?

1015 is a rate limit — you went too fast, and it clears when the window expires. 1020 is a firewall rule — something about who you appear to be matched a block condition, and it will keep matching until you change it. Waiting helps with one and is useless for the other.

Why do I get 1020 on my phone but not my laptop?

Because they leave from different addresses and present different clients. Your phone is on carrier CGNAT while the laptop is on home broadband or a VPN, so one of the two is in a blocked range. Different browser builds also produce different TLS fingerprints and header orders.

Does changing my user-agent fix Error 1020?

Rarely on its own, and often it makes things worse. If your user-agent claims Chrome but your TLS handshake, header order and HTTP/2 settings say Python, you have created a contradiction that is easier to detect than the honest default would have been.

Can a VPN cause Error 1020?

Very commonly. Blocking known VPN and hosting ASNs is a one-click configuration on Cloudflare, and many site owners enable it. Disconnecting the VPN and reloading is the single fastest test for whether that is your cause.

How do I get a 1020 lifted?

Contact the site owner with the Ray ID printed at the bottom of the error page, the approximate time, and what you were trying to do. They can search that Ray ID in their Cloudflare firewall events and see the exact rule. Nobody else, including Cloudflare support, can lift a rule the site owner wrote.

Dedicated mobile proxies, one dashboard

Real 4G/5G devices on US carrier SIMs. Sticky IP per customer, rotation on demand.

See plans