What the numbers mean
A request is one HTTP fetch that reached the edge, and the count is one log record per fetch. That is the whole definition. Everything below is the consequences of it — which numbers are exact, which are estimates, how big the error is, and what any of it is next to the size of the web.
What counts as one request
Every single thing a client asks for is one request: an HTML page, an API call, one JavaScript chunk, one image, the favicon, robots.txt, a redirect, an analytics beacon. It is not a visit and not a page view. Nobody “visits” in these numbers; things get fetched.
A request earns a place in the count by reaching Vercel's edge. What happens next decides which of two very different streams it lands in, and that difference is the single most important thing on this page.
One request, end to end
The firewall looks first. If it says no, Vercel answers 403 or 429 and writes one firewall record — and all of those are drained. If it says yes, the site serves the request and writes one record of five kinds — and only one in ten of those is drained, head-sampled on a hash of the request ID. That asymmetry is deliberate: it holds the log bill near $2 a month instead of $34, and it costs us nothing on the side of the numbers we most want to be exact.
Why a person and a bot are not comparable
One person loading one page of aboutus.com produces something like five to fifteen requests: the page itself, several script and style chunks, the favicon, the analytics beacon. One bot probing one URL produces exactly one. So a raw share of requests systematically overstates humans — every person arrives pre-multiplied by a dozen, and every probe arrives as one.
That is what the per address-hour column on the observatory is for. It counts how many requests came from each source address within each hour. A person browsing shows up as a burst on one address. A fleet renting a thousand addresses shows one request on each, and lands at about 1.0 — which is a shape no real person has.
A person and a fleet, the same twelve requests, opposite shapes
Identical totals, and nothing else in common. This is why the observatory ranks networks by requests per address-hour rather than by request count: it is the measure that separates a residential ISP with real customers from a hosting network running browser-shaped software. It is also why we key rate limits to a TLS fingerprint rather than an address — on shared carrier-grade NAT, a per-address limit hits the person and misses the fleet.
Requests for HTML documents only, worldwide: 47% human, 44% ordinary bots, 4.2% AI crawlers. Cloudflare Radar, 2025 Year in Review, 2025-12-02. HTML is the one slice where a request and a page nearly mean the same thing, which is why this is the split everybody quotes — and why it says nothing about total request traffic, where one page load is a dozen requests and one probe is one.
Refused, and its three shapes
Refused means the firewall answered instead of the site. It comes in three kinds, and collapsing them loses the thing worth knowing. Denied is a 403: the client got nothing. Challenged is an interstitial asking the client to prove it is a browser. Rate-limited is a 429 for going over the cap on a TLS fingerprint.
The trap is that a challenged person is counted twice — once here, when the interstitial is served, and again a second later as the handful of allowed requests that make up the real page. So when most of “refused” is challenges rather than denials, the headline number is softer than it sounds. Denials are the requests that truly got nothing.
What the refused number is actually made of
Live, from the last 24 hours. Both segments are the same hue because both are refusals; the hatch marks the softer one. Every count here comes from the 100% firewall stream, so unlike almost everything else on the observatory these are exact request counts, not estimates.
Allowed, and the ten-times
Everything the firewall lets through is served and logged as one of five record kinds: lambda for a server-rendered page or API route, static for a cached or static file, plus redirect, edge and external for the analytics beacons. The baseline drain keeps one record in ten. The rollup multiplies by ten to get back to a request count.
Ten requests in, one record kept, ten back out
Head sampling is a deterministic hash of the request ID, not a coin flip — but for any slice chosen without reference to that hash (a site, an hour, a named crawler) it behaves exactly like one. Which means the estimate is unbiased, and wrong on any particular bucket by an amount you can calculate. That amount is the next section.
This is why every allowed and total figure on the observatory is printed with a tilde, and why the feed also publishes the unscaled *_raw counts next to the scaled ones. The raw count is the only honest denominator for an error bar.
How exact this really is
“One line equals one request” is an assumption, and it is checkable: every drained record carries Vercel's request ID, so counting distinct IDs and dividing says exactly how far off it is. Here is a whole hour, audited.
| Record kind | What it means | Records | Distinct requests | Records per request |
|---|---|---|---|---|
| firewall | the firewall answered it: denied, challenged or rate-limited | 67,204 | 67,204 | 1.000 |
| lambda | a server-rendered page or an API route ran | 3,604 | 3,447 | 1.046 |
| static | a cached or static file was served | 358 | 358 | 1.000 |
| redirect | the edge answered with a redirect | 229 | 229 | 1.000 |
| edge | middleware or an edge function ran | 161 | 161 | 1.000 |
| external | an analytics beacon | 100 | 100 | 1.000 |
| all | plus 43 requests that produced records of more than one kind | 71,656 | 71,456 | 1.003 |
One whole hour of raw drain records, the hour beginning 2026-09-03T22:00Z. Counting distinct request IDs is the only way to tell a log line from a request. Overall the records run 0.28% above the true request count.
Three things fall out of that. Firewall records are one per request — 67,204 records for 67,204 requests, dead level, so refused counts are true request counts. Lambda records are not: a function that logs twice during one request writes two lines, so function traffic reads about 5% high. And a few requests produce records of more than one kind — a redirect line and a lambda line for the same fetch — adding a little more on the allowed side.
Netted out, the records for that hour ran 0.28% above the true request count. So the honest statement of the whole thing is: the refused numbers are exact, and the allowed and total numbers are ten-times estimates of a record count that sits a couple of percent above true requests, with sampling noise on top. Vercel's own billing counter is lower than our record count for precisely this reason.
The error you should attach
Scaling a sample up by ten is exactly right on average and wrong on any given bucket. How wrong has a clean answer. Writing n for the number of records the drain actually kept and p for the sample rate, the relative standard error of the scaled count is √((1−p)/n) — which at a 1-in-10 sample is almost exactly one over the square root of the records you kept.
The striking part is what is not in that formula: the size of the true number. A bucket is uncertain because it is thinly sampled, never because it is small or large. A crawler with twenty kept records is ±21% whether those twenty represent two hundred requests or two hundred thousand.
Certainty is bought with kept records, and only with kept records
One standard error against the number of records the drain kept, logarithmic. The marked points are real buckets from the live feed. The practical reading: site and week totals are solid to a fraction of a percent, and the long tail of rarely-seen crawlers is soft — which is why the observatory sorts the named-bot table by volume and does not invite you to read the bottom of it too closely.
| To be sure within | the drain must have kept | which means roughly |
|---|---|---|
| ± 50% | 4 records | 40 real requests |
| ± 20% | 23 records | 230 real requests |
| ± 10% | 90 records | 900 real requests |
| ± 5% | 360 records | 3,600 real requests |
| ± 1% | 9,000 records | 90,000 real requests |
One standard error, at a 1-in-10 sample. Refused counts are not sampled at all and do not appear here.
How many of these exist at a single moment
A request is not an event with no duration — it is alive for a while. So “how many exist right now” is a real question with a real answer, and it is not the same question as how many happen per second. The bridge is Little's Law: the number in flight is the arrival rate multiplied by how long each one lives. Nothing more.
Cloudflare answers about 81 million HTTP requests a second on average and sits in front of roughly a fifth of the web, which puts the whole web on the order of 405 million requests a second. A request lives at the edge for somewhere between about 50 milliseconds and half a second. Multiply: at any instant, somewhere between 20 million and 203 million HTTP requests are in flight across the Internet, call it 81 million.
One pixel per request in flight, right now
Give every in-flight request in the world one pixel and they fill about 10 4K screens. Give ours the same pixel and they fit in 23 of them, drawn actual size on the right. Both halves of that come from the same arithmetic; only the rectangle is not to scale, because it cannot be.
The band matters more than the midpoint here, and it is honest about where the softness is: the request lifetime is an assumption, and Cloudflare's “one in five sites” is a share of sites being used as a stand-in for a share of requests. Treat the result as an order of magnitude — tens of millions in flight, not hundreds of thousands and not billions.
How many happen in a day
405 million a second is about 35 trillion HTTP requests a day across the Internet. For scale in the other direction: the entire DNS root server system — all thirteen identities, the thing the whole naming system hangs from — answers around 130 billion queries a day, which is under half a percent of that. The web asks for far more than it looks up.
From one request to a day of the Internet
Logarithmic: every gridline is a hundredfold. Our own traffic is in orange. A useful thing to notice is how small the interesting range is — a single page load and the entire web are separated by twelve orders of magnitude, and almost everything anyone argues about lives in the middle four.
Which puts our own numbers in their place. Our five sites saw about 10 million requests in the last 24 hours and refused 5,512,334 of them. Everything we saw in a whole day passes across the world's servers in about 25 milliseconds.
Our whole day, on the world's clock
The bar is one second of the world's web traffic and the orange sliver is our entire day, drawn to scale. This is not self-deprecation, it is calibration: it is why an attack that would be invisible in any global statistic can still be the largest thing that has ever happened to these sites, and why a firewall rule tuned on somebody else's scale will be wrong on ours.
Every published figure, with its source
Two kinds of number appear on this page and they are never mixed. Measured means somebody counted it and published it; each one below carries the source and the date the figure speaks for, not the date we read it. Derived means we did arithmetic on those, and the assumption is stated in words next to the result so you can disagree with the assumption rather than the number.
| What | Figure | Source | Speaks for |
|---|---|---|---|
| HTTP requests Cloudflare answers, per second, on average | 81,000,000 | Cloudflare Radar, 2025 Year in Review | 2025-12-02 |
| The same at peak | 129,000,000 | Cloudflare Radar, 2025 Year in Review | 2025-12-02 |
| Share of the web sitting behind Cloudflare A share of sites, not a share of requests. We use it as a stand-in for the request share, which is the weakest step in the estimate below. | 20% | Cloudflare, “powers 1 in 5 sites on the Internet” | 2026-09-04 |
| DNS queries Cloudflare answers, per second Authoritative and resolver combined. | 67,000,000 | Cloudflare Radar, 2025 Year in Review | 2025-12-02 |
| DNS queries the thirteen root server identities answer, per day Huston's figure is “more than 130B queries per day at the start of 2025”, up 40% from about 90B at the start of 2023. We carry the lower bound. | 130,000,000,000 | Geoff Huston, “The root of the DNS”, APNIC | 2025-01-01 |
| Websites that answered Netcraft's survey | 1,494,915,628 | Netcraft Web Server Survey, July 2026 | 2026-07-01 |
| Domains behind them | 305,348,459 | Netcraft Web Server Survey, July 2026 | 2026-07-01 |
| Web-facing computers behind those A billion and a half sites run on fifteen million machines. Most of the web is one server wearing many names. | 14,772,048 | Netcraft Web Server Survey, July 2026 | 2026-07-01 |
The two derived figures are the world's request rate (405 million a second — Cloudflare's average divided by Cloudflare's share) and the in-flight count (81 million — that rate times an assumed 200-millisecond lifetime). Both are order-of-magnitude claims and are marked as such wherever they appear. Our own counts are not estimates of anybody else's traffic; they are measurements of ours, with the exactness set out above.
A note on what is never counted: DNS lookups, connections that failed before an HTTP request existed, traffic Vercel's own DDoS layer drops before the firewall sees it, and anything on a preview or *.vercel.app hostname. There is a whole layer of refused traffic below our floor, and we do not have it.
Glossary of every field
Every number the observatory and the public feed publish, what it counts, and whether it is exact.
| Word | Field in the feed | What it counts | How solid |
|---|---|---|---|
| Request | — | One HTTP fetch that reached Vercel's edge for one of our production hostnames. Not a visit, not a page view. The favicon is a request. | exact |
| Refused | blocked | The firewall answered instead of the site: denied, challenged or rate-limited. Counted from the 100% firewall stream, so it is a true request count. | exact |
| Denied | denied | A 403. The client got nothing. This is the number to use when you mean 'we turned it away'. | exact |
| Challenged | challenged | An interstitial asking the client to prove it is a browser. A person who passes is counted here once and then again in allowed. | exact |
| Rate-limited | rate_limited | A 429: over the cap for that TLS fingerprint. Usually a rounding error next to the other two. | exact |
| Allowed | allowed | Everything the firewall let through, served and logged. Recovered from a 1-in-10 sample by multiplying by ten, so it carries sampling error and reads a few percent high. | estimate |
| Raw | *_raw | The unscaled count of records the drain actually kept. The honest denominator for any error bar; the reason the feed publishes it at all. | exact |
| Requests (total) | requests | Refused plus allowed. Exact on one side, a ten-times estimate on the other, which is why the page prints it with a tilde. | estimate |
| Per address-hour | hits_per_ip_hour | Requests divided by the number of distinct source addresses seen in each hour, summed. A person browsing sits well above 1; a fleet on rented addresses sits at about 1. | derived |
| Network | asn | The autonomous system the source address belonged to. The address is resolved to an ASN and then discarded — we never store or publish IPs. | exact |
| Bypass | bypass | Requests the firewall deliberately waved through on a system rule, mostly Vercel's own infrastructure. | exact |
The feed these all come from is public at n1.snowc.one/public/bots.json. Back to the observatory, or on to the daily zone census. Live counts on this page are from the feed generated 2026-10-19 01:25 UTC.