DEV Community

Cover image for Cloudflare wasn't blocking our IP. It was blocking our browser.
MH Habib
MH Habib

Posted on • Originally published at inteldif.com

Cloudflare wasn't blocking our IP. It was blocking our browser.

A 20-minute experiment that saved us from buying residential proxies, and the escalation ladder we found underneath.


At IntelDif, we crawl competitor pages on a schedule, diff them, and alert our users only when something meaningful changes. That business dies if the crawler can't see the page. So, when one of the domains we monitor started returning Cloudflare's "Attention Required" challenge on every crawl, it immediately went to the top of the queue.

The internet has one answer for this: your IP reputation is bad, buy residential proxies. Every scraping forum, every proxy vendor's blog, every Stack Overflow thread. Residential proxies are also expensive, metered by the gigabyte, and a recurring cost that scales with your crawl volume.

Before paying, we did something embarrassingly simple that we'd recommend to anyone hitting bot walls: we ran a 2×2 experiment.

The experiment

Two variables, four runs, real production stack (Chromium via Patchright, same code path as our crawler):

Browser Egress IP Result
Headless Direct (residential-grade) ❌ Blocked
Headless Datacenter proxy ❌ Blocked
Headed Direct (residential-grade) ✅ Real page
Headed Datacenter proxy ✅ Real page

Read the columns, then read the rows. The IP made zero difference in either direction. The headless flag flipped the outcome every time.

Cloudflare's managed challenge wasn't scoring our IP reputation at all. It was fingerprinting the browser mode. A headless Chromium on a clean residential IP: blocked. A headed Chromium on a flagged datacenter IP: waved through.

If we'd bought residential proxies, we'd have paid a monthly bill to change the one variable that didn't matter.

The fix: a fake monitor in Docker

Headed Chrome needs a display, and crawl workers run in containers that don't have one. The classic answer is Xvfb, an X server that renders to memory. Add it to the image, point DISPLAY at it, and Chrome believes it's on a desktop.

One production gotcha worth noting: avoid launching your process as xvfb-run node dist/worker. That makes xvfb-run PID 1, and it doesn't forward SIGTERM, so your graceful shutdown hooks (draining the job queue, closing browser pools) silently never run on deploys. Start Xvfb in the background in your entrypoint, export DISPLAY, then exec your actual process so it is PID 1 and receives signals directly.

The plot twist: there's a ladder, not a wall

Going the block was fixed. It also exposed the next one immediately.

During the headless era, our escalation logic had learned to route this failing domain through the proxy, and it latched that flag. So our first headed crawls went out through the datacenter proxy and got challenged again. Same domain, headed browser, two different IPs: direct passed, datacenter IP blocked.

So the real structure is an escalation ladder, not a single wall:

  1. Rung 1: headless fingerprint. The cheapest signal, checked first. Killed by going headlong.
  2. Rung 2: datacenter ASN reputation. Only matters once you clear rung 1. Avoided by not proxying at all. Direct egress from a normal network beats the proxy.

The uncomfortable conclusion: for this class of protection, the datacenter proxy we were paying for was worse than nothing. It converted passing crawls into blocked ones. Our escalation logic now releases the proxy flag when proxied attempts fail and retries directly, instead of ratcheting one way forever.

Caveats: this is one wall, not all walls

This result is proven for Cloudflare's managed challenge tier. Enterprise anti-bot products (DataDome, PerimeterX-class) blend fingerprint and IP scoring. There, a head-of-household mode is necessary, but maybe not sufficient, and residential IPs might genuinely help. The point is not "never buy proxies." The point is:

Run the 2×2 before you spend. Twenty minutes of controlled testing (headless/headed, direct/proxy) tells you which variable your blocker actually keys on. Most teams skip the experiment and buy the product the forums told them to buy.


IntelDif watches your competitors' pages and alerts you only when something real changes: pricing, positioning, product. The crawling is the easy part; deciding what's meaningful is the moat. inteldif.com

Top comments (0)