What actually fails against Cloudflare

By Mechelle Henderson · Published: 27 July 2026 · 8 min read

TL;DR: Four combinations of exit IP and TLS stack, seven Cloudflare-fronted targets, 28 requests, all logged. A clean residential IP plus a browser-accurate TLS fingerprint clears the HTTP layers - and still scores 0/7 on sites running an interactive challenge. The JA3 fingerprint also changed on every single request, which breaks the assumption that impersonation gives you one stable identity.

Most advice about scraping Cloudflare-fronted sites is asserted, not measured. "Use residential IPs." "Match Chrome's JA3." People repeat these like folklore. We run a proxy network, so we had the tooling to actually test them — and the results contradicted the two most common pieces of advice.

Here's what we ran, and what failed.

The test

Two variables, four combinations:

Seven Cloudflare-fronted sites, two passes each — 28 requests total, US exits, 27 July 2026. A "pass" required HTTP 200 and a body without challenge markers. A 200 that returns "Just a moment…" is a block wearing a success code, and it does not count.

The numbers

CombinationPassed
Datacenter IP + default Python TLS0 / 7
Datacenter IP + Chrome-impersonated TLS0 / 7
Residential IP + default Python TLS0 / 7
Residential IP + Chrome-impersonated TLS0 / 7

Every combination failed identically. Two things in that table contradict advice you'll read everywhere.

The residential IP bought us nothing

Not a single site treated the Frontier residential exit differently from the Psychz datacenter one. That does not mean IP reputation is a myth — it means these sites never got as far as judging our IP. A request that fails the bot-management check is refused on other grounds first.

IP quality decides outcomes in the middle of the difficulty curve. At the hard end it isn't the binding constraint, and buying better IPs won't move it. If you're stuck at 403 on a genuinely aggressive Cloudflare config, a residential proxy is not the missing piece.

Chrome TLS impersonation didn't flip a single site either

curl_cffi with impersonate="chrome" is great tooling, but on these targets it changed nothing. The sites require executing the JavaScript challenge, which no HTTP client does, no matter how convincing its TLS handshake. If you're stuck, adding a TLS library isn't the fix — you need something that runs JS.

For calibration: the same script sailed through Cloudflare-fronted sites that aren't running aggressive bot mode, on every combination including plain Python from a bare datacenter host. "Protected by Cloudflare" spans an enormous range of strictness. Establish which end your target sits at before spending money on tooling.

Bonus: stop chasing a specific JA3 hash

While measuring, we checked what fingerprint our own requests presented. Three consecutive curl_cffi requests with the same impersonate="chrome" setting, from the same host, produced three different JA3 hashes (a0052cf3…, 0899dce7…, d2de58db…).

That's not a bug. Real Chrome shuffles TLS extensions and injects GREASE values, so its JA3 changes per connection — and a good impersonation library reproduces that. Any guide telling you to match one specific JA3 string is describing a browser that stopped existing years ago.

What did stay identical across all our requests — direct, via residential proxy, and via datacenter proxy — was the HTTP/2 fingerprint (52d84b11…), derived from the SETTINGS frame, header table size, window size and pseudo-header order. It's far more stable than JA3, which is exactly why it's worth more to the people fingerprinting you. Check both when you debug a silent block; we used tls.browserleaks.com/json.

So what actually works?

Match the tool to where your target sits on the curve:

The mistake I see most often is spending money on better proxies to solve a problem that lives in the JavaScript layer. Test the cheap hypothesis first: does plain Python already work? Does a headless browser with no proxy work? Only then start paying for exit quality.

Reproduce it

The method is boring on purpose: 28 requests, 7 sites, 4 tool combinations, pass = 200 with no challenge markers in the body. If you want to run the same matrix against your own targets, the request-side code (requests, httpx, curl_cffi, Playwright) is in a public examples repo: github.com/roamproxy/proxy-examples.

If you want a residential pool to test the "does a better IP help my target" hypothesis without a subscription, the network I work on (Roam) gives 300MB free on signup — enough to run the matrix above against your actual target before spending anything.

Got a Cloudflare block that behaves differently from this? I'd genuinely like to hear it — drop the details in the comments.

Running this kind of work through a proxy network? Roam is pay-as-you-go residential and datacenter IPs from $2/GB — see how it works, or browse the guides. Runnable examples live at github.com/roamproxy/proxy-examples.