The Crawl Price Index.

How we measure

Methodology

What we measure, how we measure it, what counts as an observation versus an inference, what we deliberately do not measure, and how to check our work.

Methodology version 2026-09-13.1 · machine-readable at /v1/methodology
The short version

The short version

Twice a week — Sunday and Wednesday — we read the robots.txt and homepage response headers of a ranked 50,000-domain frame using our own identified, cryptographically signed crawler. We record what each site tells AI crawlers: who is blocked, who is allowed, whether a price or payment wall is quoted, and what changed since the previous edition. We publish the aggregates free and the per-domain detail to subscribers. The census runs twice a week; the newsletter mails the Sunday edition, and its change window runs from one Sunday edition to the next.

This page in ten lines.
  1. Frame: the top 50,000 domains of a custom Tranco list (CPI-50K v1), fixed since 21 August 2026.
  2. Denominator: every rate is a share of the 31,469 domains that served a readable robots.txt — never of the frame, never of “the web”.
  3. Cadence: a full census on Sunday and Wednesday; only scheduled runs are editions; the series starts 23 August 2026.
  4. Declared layer: 18 named AI crawlers, five states each (blocked, allowed, partial, unlisted, no file), read from robots.txt with our signed, identified crawler.
  5. Wire layer: a wide probe of the top 2,000 domains plus every domain blocking a tracked crawler. Each reached domain is knocked on three ways in one sweep: as our own self-identified crawler (the honest-identity control), then, where that first knock was answered, presenting GPTBot's published user-agent string, and with a current Chrome user-agent string — a string, not a browser. Alongside it, a 331-domain identity matrix asked under several identities. Both are purposive sets, reported with their n, and neither is a sample of the web.
  6. Prices: recorded only when a site returns one in a machine-readable payment response. We never model, infer or extrapolate a price.
  7. Changes: edition-over-edition differences on domains readable in both editions; frame churn is never a policy change.
  8. Suffix groups: a rate is published only for groups of at least 100 domains; a suffix is not a country.
  9. One vantage point: a residential connection in Luxembourg, 8-second timeout, no retries to get past a refusal.
  10. Corrections: dated notes, published as JSON at /corrections.json and in the free feed’s corrections array; past editions are never silently amended.
The distinction that matters most. “GPTBot is disallowed in this site’s robots.txt” is an observation. “15.8% of domains with a readable robots.txt block GPTBot” is a derivation from those observations. “A site of this size could charge $0.05 per crawl” is an inference — a judgement, not a measurement. We record the first two, label each everywhere it appears, and never model a price: the third kind of statement does not appear on this site as a figure.
What we measure

What we measure

SignalHowType
Robots stance
per crawler, per domain
GET /robots.txt with our identified user agent; parse User-agent / Disallow / Allow groups. Values: blocked, allowed, partial, unlisted, no_robots.observed
Observed priceRecorded only when a site returns a price in a machine-readable payment response — HTTP 402 with a crawler-price or payment header, or an equivalent x402 offer. Where a price is printed we print the quote and the domain that gave it: this edition that is the identity-matrix panel’s one posted price, $0.50 at stackoverflow.com. The wide probe’s protocol-confirmed prices are a different instrument and are published as a count only — the home page’s “named a price” figure — so the quotes and domains behind that count are not on this site. Counted, not quoted; the two are never summed.observed
Payment signalsStatus codes and headers on identified-crawler requests: 402 responses, TollBit-style token walls, licensing redirects, payment:free declarations.observed
EnforcementCompares a site’s declaration against what an identified crawler actually receives. Wide probe: 7,491 domains reached, on a set built to over-represent blockers, so a rate over that set describes the set and nothing wider.observed
(wide probe)
Block ratesShare of parsed domains blocking each crawler. Denominator is domains successfully parsed, never the nominal top-N.derived
Suffix groupsSegmented by country-code TLD suffix. Every group with at least 8 domains is listed with its n; a rate is published only where at least 100 domains are present, on the public site and in the Terminal alike. A ccTLD is a domain suffix, not a country — not operator location, ownership, audience or hosting.derived
Trends & moversDifference between editions in our archive — the previous one, or any baseline the reader chooses.derived
What we do not measure

What we do not measure

  • Revenue actually earned by any site.
  • Traffic volumes of any site.
  • Prices for domains that do not publish one — we never model or extrapolate a price.
  • The value of private AI licensing deals.
  • Whether an AI company honoured a payment request after it was made.
How we identify ourselves

How we identify ourselves

Our crawler sends a truthful user agent and signs every request cryptographically, so any site can verify that traffic claiming to be ours really is:

User-Agent: CrawlPriceIndexBot/1.0 (crawl-economy measurement;
            robots.txt study; contact: hello@crawlpriceindex.com)
Signature-Agent: "https://crawlpriceindex.com"
Signature-Input: sig=("@authority" "signature-agent");created=…;keyid="…";tag="web-bot-auth"

Signatures follow RFC 9421 under the Web Bot Auth profile. Our public key directory is served at /.well-known/http-message-signatures-directory. We have applied to Cloudflare’s verified bots programme using signature verification.

The identity matrix, identity by identity

The wide probe above covers the whole reached frame and presents one named crawler, which is why a wall that fires at ClaudeBot and not at GPTBot is invisible to it. The identity matrix makes the opposite trade: 331 domains rather than tens of thousands, asked under six identities apiece. That is where ClaudeBot is asked, and the two instruments should be read as the pair they are rather than as one claim.

A sixth identity starts on 17 September 2026, and why it exists — and why it waits — is worth stating. The fifth identity — ClaudeBot's user-agent string carrying crawler-max-price: 0.001 — differs from the plain ClaudeBot leg in two ways at once: it is an impersonated identity and it carries an offer to pay. When a door answered it differently, nothing in the data could say which of the two did it. The sixth is our own CrawlPriceIndexBot/1.0 carrying that same header at that same value, so the price signal is isolated from who is asking. It adds no further impersonation: it is the crawler we already declare, with one header added. It starts four days after it was ruled, deliberately. The identity matrix keeps no archived per-identity distribution, so a leg switched on without a five-leg edition beside it has no control to be read against — and a before-and-after that is failing for other reasons in both runs is not a control. The 13 September census runs the five legs and records their distribution; the 17 September census starts the sixth. It costs one edition to have a real comparison.

Its readings are archived from the day it starts. Its level is published from its first edition, with the number of editions it has accrued stated beside it; no edition-over-edition movement is claimed for it until its own series is long enough to support one. Measuring a site twice a week from September and telling that site what was found in October is not a defensible posture toward a measured party, and hiding a level that is already precise buys nothing.

The five, named in full, because “several identities” does not tell a site operator what knocked on their door — one request per identity per domain per edition:

  • our own CrawlPriceIndexBot/1.0, signed as above — the honest-identity control;
  • a current Chrome user-agent string — a string, not a browser;
  • GPTBot’s published user-agent string;
  • ClaudeBot’s published user-agent string;
  • ClaudeBot’s published user-agent string carrying the header crawler-max-price: 0.001.

The fifth identity states a price a crawler would be prepared to pay, in the units that header defines. It is sent to observe whether a door that refuses a named crawler answers the same request differently when it carries that header; where the two answers differ, the difference is the measurement, and it is published in the Terminal as the max-price probe. No payment is offered in any binding sense and none has ever been made. Nothing in this pipeline can settle a payment: there is no wallet, no credential and no code path that could complete one. The header is a declaration a door may answer or ignore.

Two things follow that we would rather state than be asked. Presenting another operator’s user-agent string means the response we record is the response that string received, not one that operator received — we are not those crawlers and we do not claim their traffic. And the request originates from an ordinary consumer connection, not from any published crawler address range, so a door that verifies its callers by address will treat these knocks as unverified, which is itself part of what the matrix measures. Named on this page 10 September 2026; the matrix itself is older, and the disclosure should have arrived with it.

Crawl etiquette

  • We request robots.txt and the homepage only. We do not crawl article pages and we store no page content.
  • Requests are throttled per host and per 2,500-domain chunk, so no host is hit in a burst; when a host signals pressure (429/403 rates above threshold) the throttle tightens automatically — lower concurrency, wider spacing.
  • A named crawler's user-agent string is presented only in the disclosed wide probe and the identity matrix, one request per identity per domain per edition, to observe identity-conditional responses — never to obtain content, and never retried to get past a refusal.
  • A domain cannot leave the frame — the census would be worthless if it dropped the rows that asked — but a site can ask, from a domain-verifiable address at hello@crawlpriceindex.com, not to be named in the examples and named tables on our public pages and in the newsletter. It then stays in every count and every rate, in the licensed per-domain data, and in Check a domain, which answers for any domain in the frame. To date no domain has asked.
Two probes, and how the panel is chosen

Two probes, and how the panel is chosen

We measure crawler policy two ways, on purpose. The wide probe visits the top 2,000 domains by rank plus every domain that blocks any tracked crawler in robots.txt — it asked 8,002 domains in the current edition and reached 7,491 of them, meaning in the frame and answering; a timeout or dropped socket on either leg is recorded as its own outcome. Asked and reached are the two words this site uses for those two quantities, on every page and beside every feed field that carries one; every wire count below is over the reached set. Each target receives two homepage requests in one sweep: one presenting the published user-agent string of a named AI crawler (GPTBot in this edition), and one as our own self-identified crawler (the honest-identity control). It records the HTTP status of each, payment or licensing headers, and Cloudflare fronting. It retains no content. Since it sends another crawler's user-agent string it is a disclosed measurement study: one request per identity per domain, from one residential network position, once per edition, never repeated to obtain access. The census sends its knock once per door per edition, redirects followed, whether or not the door disallows the crawler it presents, and never repeats it; a second instrument, the 331-domain identity matrix below, presents the same string once more at the doors it shares with the census. What it yields is a pair of answers per domain, never a cause — a firewall, a rate limiter, a missing browser signature and a deliberate decision all produce the same pair, and the product says so wherever the numbers appear.

The control leg, dated. Since edition 2026-09-02 each domain the probe asks receives two requests: one presenting GPTBot's published user-agent string, and one as CrawlPriceIndexBot/1.0 — our own self-identified crawler, the honest-identity control. On this instrument that control request is unsigned: it carries the truthful user-agent string and no RFC 9421 signature (the census fetcher and the reachability sweep are the signed ones, see how we identify ourselves). Until 4 September 2026 this page, the home page, Explore and the Terminal described that control as “an ordinary browser”. It was not one, and it never had been; the count of domains that refused the crawler while serving the control was always computed against the identified-crawler request, so no published count changed. The correction is logged in the changelog and in the machine-readable corrections array at /corrections.json. A third request per domain carrying a current Chrome user-agent string — not a real browser: no JavaScript, no browser TLS fingerprint — has run since the 2026-09-06 edition, the first edition whose archived probe records a browser identity. It runs where the first knock was answered, and its count is printed as its own line, never substituted into the pair above.

The identity matrix is the older, smaller instrument: a capped panel of 331 domains asked under several identities — a request carrying a current Chrome user-agent string (not a real browser: no JavaScript, no browser TLS fingerprint), our own identified crawler, and the published user-agent strings of several AI crawlers — to observe whether a site answers different crawlers differently. It remains the source for the per-crawler exhibits (posted prices, token walls, payment headers) and is reported with its n every time.

The panel is assembled, not hand-picked. It has three parts: a fixed spine carried unchanged for continuity; a signal tier, where any domain the wide probe flags as showing payment or blocking behaviour is promoted automatically the following edition and dropped after eight silent editions; and a rotating audit, a small random sample from the full scan each edition, so that a wall which fires only at named AI crawlers is measured on a set that was not selected for it. (Until the 2026-09-02 edition the audit tier was the only instrument that could see such a wall at all, because the wide probe then ran under our own identity only; the wide probe now meets those walls itself, and the audit tier's job is the unselected denominator.) The panel's full composition is published at /panel.json, which names the identities each instrument presents.

Coverage and freshness

Coverage and freshness

  • Frame — CPI-50K v1: the top 50,000 domains of a custom Tranco list (tranco-list.eu/list/Y8V2G, generated 21 August 2026; 30-day window, harmonic/Dowdall combination, pay-level domains). It is built from Cisco Umbrella and Majestic only. We deliberately exclude two providers the default Tranco list includes: Cloudflare Radar (CC BY-NC — a non-commercial licence, and this is a paid dataset) and the Chrome User Experience Report (CC BY-SA — a share-alike licence that could attach to data we redistribute). Excluding them is a licensing decision, and it also measurably improved the frame: non-website entries in the top 100 fell from 18% to 2%, because Radar ranks by DNS lookups and machines resolve names constantly without anyone visiting a site. We remove reverse-DNS zones (*.in-addr.arpa, 167 rows) and nothing else — CDN, cloud and parked domains stay in, because how much of a popularity ranking is not a website is a finding, not a defect to hide. Full provenance, including every removed row, is published at frame-cpi50k-v1.json. Alongside the frame we run two probes: the wide probe, which this edition paired the 7,491 domains it reached with our own self-identified crawler (the honest-identity control) under one presented identity, and the identity-matrix panel of 331 domains asked under several (see above).
  • Reached vs parsed: a popularity ranking lists registrable domains, not working websites. 31,469 of the 50,000-domain frame serve a readable robots.txt; that parsed count is the denominator behind every rate we publish, and it is the same figure the dashboard uses. We never quote a rate as a share of “the web”. The remainder is not a rounding error and we census it explicitly — see Frame reachability below.
  • Cadence: twice-weekly full sweeps (Sunday and Wednesday), run automatically. The newsletter mails the Sunday edition; the Wednesday edition is published on the site, in the feed and in the Terminal but is not mailed.
  • History: the published series begins with the 23 August 2026 edition, the first taken on the CPI-50K v1 frame. Editions before it were measured on a different frame and are retained but not published. Nothing in the series can be backfilled — by us or by anyone.

Editions, and what counts as one

The census runs twice a week — the run starts at 01:00 Europe/Luxembourg on Sunday and Wednesday (23:00 UTC the evening before) and finishes around 03:00 UTC; the finish time is stamped on each edition and printed on status. Only scheduled census runs are published as editions. A measurement can be real and still not be an edition: on 24 August 2026 a full scan was taken at 21:29 UTC on a Monday to validate the pipeline’s move onto its new census machine (31,562 domains parsed). The data is sound and the file and its timestamp anchor are retained, but publishing it alongside the scheduled editions would imply a Monday census that does not exist — so it is excluded from the published series, from the trend chart, from the comparison baselines and from every change set. The exclusion is recorded in series.json under unscheduled, with its reason, rather than being applied silently.

Frame reachability

Frame reachability — and declared versus enforced

A ranked list keeps domains long after the website behind them stops answering. Because every rate we publish carries a denominator, we measure that directly rather than assume it. Every edition we attempt robots.txt and the homepage for all 50,000 domains, trying the apex over HTTPS, then www, then HTTP, and record the outcome by reason. Measured on edition 2026-09-02 across the full frame:

  • 44,150 (88.3%) alive — answered an identified crawler.
  • 3,213 (6.4%) dead — the name does not resolve at all.
  • 2,418 (4.8%) no response within our window. We re-probed a random sample of 337 of these (diagnostic run 2026-08-20, before the published series began on 23 Aug — it characterises the timeout bucket, not an edition) with the window extended from 8 to 25 seconds plus a retry after a cool-down: 93.8% stayed silent, so this bucket is overwhelmingly genuinely unreachable rather than an artefact of an impatient crawler. 3.0% turned out to be servers that silently drop a first request and return 403/429 on a second; they are reclassified as refused rather than dead.
  • 260 refused connections, connection resets or TLS failures.

Anatomy of the frame breaks the domains that served no readable robots.txt into a different set of reasons (unresolved, TLS, timed out, refused, no file, not a robots file). That decomposition comes from the robots.txt fetch itself; the census above comes from the reachability sweep, which also tries the homepage and the www host. The two are different sweeps with different failure classes, so their buckets are not meant to match one another; each sums to its own stated total.

Declared policy and enforced access are different measurements, and we keep them apart. 4,993 domains (10.0% of the frame) answered and then returned 403 or 429 to the same identified crawler at the homepage. That is a divergence between what a site declares to crawlers and what its edge actually does. It is not a robots.txt policy, it is not evidence of intent, and it is never folded into a block rate. A further 1,041 domains disallow our crawler in robots.txt. On the reachability sweep we obey that: the sweep reads robots.txt first, and where it disallows us the homepage is not fetched and the domain is recorded as excluded by its own instruction — a publisher of a compliance index does not get to make exceptions for itself.

Correction, 4 September 2026 — the wide probe does not apply that exclusion. Until today this page described the exclusion as if it held across the product. It does not. The wide probe builds its target list from the census as “the top 2,000 by rank, plus every domain that blocks a tracked crawler in robots.txt”, and that rule contains no robots.txt check of its own: a domain that disallows our crawler can be a probe target, and its homepage is requested once on each leg. So the wide-probe figures on this site — the reached set, the refusals, and the 402s — are computed over a target list from which those domains were not removed in advance. The reachability sweep and the wide probe are different instruments with different politeness rules, and this page now says which is which. Logged in corrections.json.

Timeout is defined as no response within 8 seconds, with a 22-second absolute ceiling per domain. Thresholds are stated because the choice changes the answer.

Site-evidence signals

Site-evidence signals — observations, not classifications

Alongside robots.txt we record a small set of self-declared signals a domain serves publicly on its own homepage. These are facts about observable artefacts, dated and attributable, in the same spirit as reading a robots.txt. Measured on each reachability sweep across the full 50,000-domain frame (the sweep can lag the robots edition by one run); the figures below are the latest sweep’s, read from the public feed (first measured 20 August 2026, before the published series began):

  • 12,475 serve schema.org JSON-LD type declarations.
  • 9,970 publish an ads.txt file — an IAB standard declaring authorised digital sellers.
  • 9,959 carry an identifiable platform or CMS fingerprint.
  • 6,581 advertise an RSS or Atom feed.

What we do not do with them. We publish what a domain declared and when we observed it — never an inferred label about what kind of organisation it is. We do not publish machine-generated category guesses. We do not publish inferred labels in sensitive categories. Where a site declares an adult content rating (RTA or an equivalent meta tag), that is reported only in aggregate, never as a per-domain field. Absence of a signal means we did not observe one; it is not evidence that the thing is absent.

Reader-defined cohorts

Reader-defined cohorts

Every rate elsewhere on this site is stated over a population we defined and can defend. A cohort is the one exception: a subscriber picks the domains, and from the Terminal a cohort can be turned into an anonymous link anyone can open. Three rules apply to a cohort’s figures that the rest of the product does not need, and they are enforced in one place rather than per surface.

  • Membership is frozen, and computation is over constant membership. The list is fixed when the link is made. Every figure is then computed only over the members that were in the frame on every edition of the window — a domain that entered or left the frame during it is dropped from the arithmetic entirely and named in the answer. Counting it on the editions it happens to appear in would turn a change in the frame into a change in policy.
  • No rate, share or movement under twenty. Below twenty constant members, counts are shown and every percentage and every delta is withheld, with the rule that withheld it printed in its place. One domain out of nineteen is 5.3 percentage points; at that size a share is an observation and a watchlist, not a rate.
  • A movement is called significant only against the cohort’s own floor. The floor is the standard deviation of that cohort’s own movements between consecutive editions, and it is used only once the cohort has eight movements across nine of its own editions. Until then the movement is shown and is not called significant. Between eight and twelve movements the floor is stated as an interval rather than a point, because a floor estimated from few movements still carries about a quarter of its own size in error.

The arithmetic runs on the census machine, against the same per-edition archive the rest of this page describes, and the API serves what it computed — so a cohort created between editions has no reading until the next census, and says so rather than showing a number computed a different way.

Known limitations

Known limitations

  • Declaration is not compliance. Our block rates measure what sites declare in robots.txt — a request to crawlers, not an access control. On the wide probe we also record what a request presenting a named crawler is served, published as counts, never as an “enforcement rate”: robots.txt is advisory and we have no crawler-side logs to see what any other crawler does.
  • robots.txt is not the whole story. Sites also gate crawlers at the edge, by ASN, by fingerprint or by CAPTCHA. We see only what our own request identities are served — the identified crawler in the census, and on the wide probe the three identities described above — from one vantage point; the identity matrix adds several more identities on a 331-domain panel. None of that says what any other crawler was served.
  • Prices are sparse. Very few sites currently quote a machine-readable price. That sparsity is itself the finding, and we report the count rather than smoothing it.
  • The index does not remove itself from the frame. crawlpriceindex.com is measured under exactly the same rules as every other domain, and so is any customer, partner or competitor that appears in the frame. Our own robots.txt carries a hand-written Content-Signal line and a License: directive, which places us inside the small group of domains that declare terms about AI use — a group we also count. We disclose that rather than exempting ourselves, because a measurer who removes inconvenient observations has already conceded the point. No domain is ever removed from the frame or the counts on request; a domain can ask not to be named publicly (see crawl etiquette above).
  • ccTLD is a domain suffix, not a country. A .io domain is rarely British Indian Ocean Territory, and .com/.org/.io carry no geography at all. Every published group, with the reasons a group’s rate moves set out before the numbers: suffix groups.
  • Probe sizes. Wire figures come from the wide probe (7,491 reachable domains this edition, a purposive set); per-crawler payment-signal exhibits come from the identity matrix (331 domains). We report n every time, and neither is a sample of the web.
  • One vantage point — one residential connection, dual-stack. Every edition is crawled from a single residential connection, with no VPN and no proxy. It is dual-stack: its IPv4 address geolocates to Luxembourg and its IPv6 address to Belgium (the network is registered to a Belgian operator), and the address family used per request is neither pinned nor recorded — so which of the two a given request went out on is unknown, and this site states no per-request location. The connection is a declared constant of the method, not an accident of which machine ran: sites that vary responses by geography or ASN may present differently elsewhere, and a measurement taken from a datacentre exit is not comparable with one taken from here. The two families as last recorded are in vantage.json, which the pre-flight check asserts before every edition.
  • The published series begins 2026-08-23. Editions before that date were measured on a different sampling frame and are excluded from the trend series and the dataset — see the changelog entry for 2026-08-23. They are retained, unaltered, but not published: the licences on two of the old frame’s inputs restrict commercial use, not merely redistribution.
  • The wide probe presents one named crawler. Since edition 2026-09-02 every domain the probe asks is knocked on as our own self-identified crawler (the honest-identity control; unsigned on this instrument — see the control leg, dated) and, where that knock was answered, presenting GPTBot's published user-agent string; since edition 2026-09-06 a third knock carries a current Chrome user-agent string. That makes identity-conditional refusal visible, but only for the one named crawler presented; a wall that fires at ClaudeBot and not at GPTBot is invisible to it. The browser-string knock is a string and not a browser — no JavaScript, no browser TLS fingerprint — so it does not say what a person's browser would have been served either. Earlier editions used a single identified identity and could not see identity-conditional walls at all; the changelog records the change and the methodology version moved with it.
Corrections

Corrections

If we get something wrong, we fix it in the next edition and record it in the machine-readable corrections array with the date, what changed and why. Three renderings of one file: the table on /status, the JSON at /corrections.json, and the corrections key in the free feed at /index.json and in the licensed dataset. We do not silently amend past editions. Report an error to hello@crawlpriceindex.com and it will be acknowledged in the next edition.

Reproduce our work

Reproduce our work

Every figure we publish is regenerated from a full sweep, every edition. To check any headline number yourself:

# the aggregates behind the homepage
curl -s https://crawlpriceindex.com/index.json

# how we measure, machine-readable
curl -s https://api.crawlpriceindex.com/v1/methodology

# any in-frame domain's stance, free
curl -s "https://api.crawlpriceindex.com/v1/check?domain=example.com"

# and the site's own robots.txt, to check us against the source
curl -s https://example.com/robots.txt

If our stance for a domain disagrees with that site’s live robots.txt, that is a bug and we want to hear about it. Subscribers get the full per-domain dataset as JSON or CSV, with a per-customer watermark.

Independence

Independence

The Crawl Price Index is funded by subscriptions. We take no payment from AI companies, publishers, CDNs or licensing platforms in exchange for coverage, ranking or inclusion. We link to Cloudflare, TollBit and RSL as setup routes for site owners with no commercial relationship to any of them. Our own site publishes machine-readable licensing terms and names a price for AI training crawlers in rsl.xml. That figure is our own commercial choice for our own pages; it is not modelled from the index, and the index never quotes it.

An estimate, clearly marked

Estimating what share of automated traffic is crawler activity

Every other figure on this site is measured. This one is not. It is the one link in a chain we quote on Why it mattersFutures that no source publishes, so we estimate it — and the workings are here so they can be attacked. They already have been: see the correction at the bottom.

Estimate: crawler activity is roughly half of automated traffic. 45–60% depending on definition, 52% as the central case.

How it is constructed

“Crawler activity” has no agreed definition, so the answer depends where the line is drawn. Three readings, mapped onto Cloudflare’s bot categories:

ReadingWhat counts as crawlingShare of bot traffic
Strictsearch-engine crawlers + dedicated AI crawlers~45%
Central+ AI-search fetching, which retrieves pages to build an index~52%
Broad+ AI assistants, which fetch on a person’s behalf~60%

We take the central case because it captures systematic machine acquisition of content — discovery, indexing, retrieval, model consumption — while excluding fetches a person triggered. That is the activity this index is about.

The 45–60% spread is a definition range, not a confidence interval. It reflects classification choices, not measurement error, and will not narrow with better data. Applied to Thales/Imperva’s 53% automated share (FY2025) it implies crawler activity at roughly 28% of all web traffic, sensitivity 24–32%.

Why we stop there

The obvious next step is to multiply by Cloudflare’s training share and publish a single headline share of all web traffic for AI-training crawling. We do not, and will not. The three layers come from different companies measuring different baskets along different dimensions — Imperva’s all-traffic automated share, our derived crawler layer, and Cloudflare’s purpose split of crawler requests. Compounding them produces a number with no honest denominator.

How good the inputs are

  • The category shares are secondary. The precise figures circulating for 2026 (search-engine ~26%, AI crawlers ~19%, AI assistants ~8%, AI search ~7%) come from write-ups of Cloudflare Radar, not a primary Cloudflare publication — and different write-ups, and even different sections of the same write-up, give different values. What is primary is Cloudflare’s Radar 2025 Year in Review: search-engine crawlers 40%, AI crawlers 20%, SEO bots 13% of verified bot traffic. The estimate should be read as resting on that magnitude, not on the decimals.
  • Verified bots are not all bots. Cloudflare’s category shares describe traffic it has verified; Imperva’s 53% includes unverified and malicious automation, much of which also crawls. The two populations do not line up, which is the main reason the range is wide.
  • One network is not the web. Cloudflare fronts a large but non-random slice of it.
  • Both vendors sell bot mitigation. Every input comes from a company whose product is stopping bots.
  • The taxonomy moved. Cloudflare introduced and revised its AI bot categories across 2025–26; a 2025 figure and a 2026 figure may not count the same thing.
  • Almost nothing independent exists. The one non-vendor measurement found is a server-log study of a single e-commerce site, which put bots at 22.3% of requests — far below both vendors, and far too narrow to generalise from.

Correction · 22 August 2026

An earlier version of this page argued that Cloudflare’s “52% of crawler requests are now for AI training” must use AI crawlers as its denominator, on the grounds that the literal reading would make AI training larger than the entire AI-crawler category and was therefore impossible. We relabelled the chart on Why it matters accordingly.

That was wrong, and the chart has been changed back. The argument confused two different dimensions. “Training” is a purpose; “AI Crawler” is a bot category. Cloudflare classifies Googlebot as a search-engine crawler while stating that it “crawls for both search engine indexing and AI training”, and that multi-purpose crawlers including Googlebot, Applebot and Bingbot are caught when a customer blocks Training. Training traffic therefore spans categories, and can exceed any single one of them without contradiction.

The full sentence also settles the denominator on its own: “52% … up from 22% in Spring 2025.” Cloudflare’s August 2025 figure for training as a share of AI crawling was 72–79%. A fall to 52% could not be described as a rise from 22%. Read against all crawler requests, the trajectory is coherent.

Nothing measured changed. The 22% → 52% movement and the two-speeds argument were never affected — only what the figure is a share of, and we had that right before we changed it. The estimate above also survived review, but its framing did not: three reviewers independently pointed out that the layers are not a nested hierarchy and that the range is definitional rather than statistical. Both corrections are reflected above.

This estimate is never folded into the edition record, never quoted as a finding, and never appears in the newsletter. Wherever it appears on the site it is labelled as an estimate.