A scraper flood on Cloudflare's Free plan: what stopped it, and what we left switched off

Ops

One morning a listings site of ours stopped opening. Cloudflare showed visitors a 524, the origin took two to six minutes per page, and nothing told us for about ten hours. The cause was a scraper going through residential proxies at about 225 requests a second.

The shape of the flood

Every page was rendered for every request, so each worker queued hundreds of renders and hit its CPU limit.

Why per-address limits could not help

A rate limit counts requests per address. With one to three requests from each of thousands of addresses, no single address ever comes near a limit. Blocking countries would have blocked our visitors. What the scraper could not fake cheaply was behaving like a browser that has been to the site before.

At Cloudflare's edge: three free rules

The Free plan allows five WAF custom rules per zone. We used three, all with a managed challenge rather than a block, so a person caught by mistake clicks through:

All three let through Cloudflare's verified bots, user agents that name themselves as robots, our own addresses, the API and webhook paths, and files that are not pages. Two days later the flood was still going: in one hour the fake-browser rule challenged more than 10,000 requests. The 10,000 events Cloudflare returns per query came from 9,627 addresses, none with more than 4.

At the origin: a gate in the app

The headless half has full browser headers, so the edge rules alone do not catch it while the emergency rule is off. In the app itself we put a small middleware in front of the page renderer:

In its first minute the gate refused about 6,700 fake browsers and turned away about 6,700 strangers, while serving strangers about 9 pages a second. Slow requests dropped to zero, the workers' CPU fell from their limit to 12 to 15 percent, and their memory from 4 to 5 GB each to 0.65 GB.

What we left switched off

The takeaway

A flood through residential proxies is easy to spot by what it lacks: browser fetch headers, cookies and Referers. Challenge that at the edge, keep strangers within what your workers can render, and make sure something outside the server notices when a page stops opening. Night Watch packages all three: the watch, the rules with an automatic switch for the emergency one, and the gate for Python web apps.

Updated: