Contents
- 1. Why this study
- 2. The sample: 150 popular websites
- 3. Part 1 — reading the policies
- 4. Part 2 — measuring the edge
- 5. How responses were classified
- 6. Results — are honest agents treated differently? (RQ2)
- 7. Results — what robots.txt says about AI agents (RQ1)
- 8. Results — does the edge honour what the policy allows? (RQ3)
- 9. Results — where blocking happens (RQ4)
- 10. Notable edge cases
- 11. How the study actually ran
- 12. Validation
- 13. Pre-registration deviations
- 14. Limitations
- 15. Ethics
- 16. Reproducing the study
- → Data, code & links
1. Why this study
Agents that act for people — research assistants, shopping agents, coding agents reading documentation — fetch ordinary web pages. Two layers decide whether they get them. The first is policy: robots.txt, where site owners say which crawlers may visit which paths. The second is enforcement at the network edge: CDNs and bot-management products such as Cloudflare, Akamai, DataDome or AWS WAF that challenge or block traffic they judge to be automated.
There is a widespread assumption that being honest is costly — that an agent which announces itself as an AI and respects robots.txt will be turned away more often than one that hides. We tested that directly, and recorded what popular sites' policies actually say about the different kinds of AI crawler.
Research questions (descriptive)
| # | Question |
|---|---|
| RQ1 — policy | What do popular sites' robots.txt files say about vendor-documented AI agents, split by purpose: training, search, user-initiated? |
| RQ2 — behaviour | How often is a self-declared, unverified research agent challenged or blocked at the edge, compared with an unlabelled HTTP client and a headless browser fetching the same public pages from the same IP? |
| RQ3 — disagreement | Among sites whose robots.txt permits our agent, how often does the edge still challenge or block it? |
| RQ4 — variation | How do these vary by sector and by CDN / bot-management vendor? (Descriptive only; cells are small.) |
We measure how sites treat a declared but unverified agent — what most independent and personal agents look like. We do not measure how sites treat OpenAI's, Anthropic's or other vendors' verified crawlers: edges verify those by IP range, reverse DNS or Web Bot Auth signatures, which we cannot and should not imitate. We never spoofed another company's crawler.
2. The sample: 150 popular websites
Source. The Tranco top-sites ranking, list `4672X` (retrieved 2026-10-12) — a research-grade ranking that averages several popularity lists and resists manipulation.
Rule. Walk Tranco from rank 1 and assign each registrable domain to one of five sectors by the primary purpose of its public homepage, until each sector has 30 domains. Only the first-ranked domain of a brand is kept (e.g. amazon.com, not amazon.de).
| Sector | Definition | Tranco ranks covered |
|---|---|---|
| SaaS / B2B | Business software sold as a service | 63–687 |
| E-commerce | Retail, marketplaces and travel booking | 27–975 |
| Finance | Regulated financial-services and payments firms: banks, payment networks and processors, brokerages, exchanges, buy-now-pay-later — plus tradingview.com and intuit.com | 131–3,158 |
| Media | News, publishing and weather | 156–705 |
| Developer tools | Developer platforms and infrastructure | 2–1,975 |
Excluded from all sectors: CDNs, ad-tech and analytics, DNS / registrar / hosting endpoints, app-instance hosts (such as *.force.com), government, education, non-profits and open-source foundations, adult, gambling, gaming, search engines, portals and social networks, hardware and telecom, conglomerates' generic portals, classifieds, and AI chat products.
- One labeller (Claude, under the researcher's direction) assigned all sectors.
- Finance and developer-tool domains are sparse in the top ranks. Beyond rank 1,500 candidates were found with a keyword screen and then labelled by hand, so sector members with uninformative names may be missed.
3. Part 1 — reading the policies
Each site's robots.txt was fetched once with the research identity (≤ 5 redirects, concurrency 2, one retry after 10 s on a network failure). An HTML response or any non-200 status counts as "no robots.txt", which under RFC 9309 means everything is allowed. Files were parsed with Protego 0.7.0, an RFC 9309-compliant parser.
For each of 14 tokens documented by their vendors we recorded whether the file names the token explicitly and whether `/` is allowed for it:
| Vendor | Training | AI search | User-initiated |
|---|---|---|---|
| OpenAI | GPTBot | OAI-SearchBot | ChatGPT-User |
| Anthropic | ClaudeBot | Claude-SearchBot | Claude-User |
| Perplexity | — | PerplexityBot | Perplexity-User |
Google-Extended | Googlebot (control) | — | |
| Apple, Common Crawl, Meta, ByteDance | Applebot-Extended, CCBot, Meta-ExternalAgent, Bytespider | — | — |
OpenAI and Anthropic state that their user-initiated agents may not follow robots.txt, because a person asked for the page. Results here describe what the policies say, not how they are enforced.
Page list for Part 2. The same census also fixed which pages would be fetched: the homepage plus up to 3 same-host URLs taken in order from the site's first sitemap (the Sitemap: line in robots.txt, else /sitemap.xml, following one level of sitemap index), skipping login, cart, checkout, account and auth URLs. 83 sites had 4 pages, 2 had 3, 4 had 2, and 61 had no usable sitemap and were tested on the homepage only. Our agent's own robots.txt rules excluded 4 of those pages before any request was made.
4. Part 2 — measuring the edge
Every page was requested by three clients, from the same residential connection, so any difference between them comes from how the site treats the client, not from the network path:
| Client | Software | Identifies itself as | Behaviour |
|---|---|---|---|
| agent | httpx 0.28.1 | GlintbaseResearch/1.0 (+https://glintbase.dev/research/bot; research@glintbase.dev) | Obeys robots.txt for its own name; disallowed pages are recorded as self_excluded and never fetched |
| script | httpx 0.28.1 | library default, python-httpx/0.28.1 | A generic unlabelled script |
| browser | Chromium 148, headless, via Playwright 1.63 | its default, which contains HeadlessChrome | Runs JavaScript; waits 5 s after the page loads so automatic challenges can resolve, then records the final state |
- Order: the order of the three clients is randomised per site and round (seeded by SHA-256 of
domain|round). - Pacing: at most 1 request per second per client, at least 30 seconds between clients on the same site, fresh cookies for every client, up to 4 sites in parallel, and never alongside another study's traffic.
- Timeouts: 20 s for the HTTP clients, 45 s for full browser page loads.
- Stored: status code, selected headers, cookie *names*, visible-text length, page title and challenge-marker hits. Page bodies were never stored.
- Rounds: two complete rounds over all 150 sites.
- Vantage point: one residential connection (AS36873, Airtel Networks, Nigeria).
5. How responses were classified
Each request receives one outcome, by the first matching rule:
| Outcome | Rule |
|---|---|
self_excluded | agent only — robots.txt disallows the page for GlintbaseResearch |
error | timeout, TLS or connection failure, or a 5xx status |
challenge | header cf-mitigated: challenge, x-amzn-waf-action: challenge/captcha or x-vercel-mitigated: challenge; or a challenge marker (Cloudflare interstitial, Akamai sec-if-cpt / bm-verify, DataDome captcha-delivery, HUMAN px-captcha, Imperva _Incapsula_Resource, AWS WAF, Kasada, CAPTCHA widget) on a non-2xx response or a page with fewer than 2,000 visible characters |
block | 401 / 403 / 406 / 451 without challenge markers, or a 2xx page that is only a vendor block page |
rate_limited | 429 |
ok | 2xx with at least 200 visible characters |
thin | 2xx with fewer than 200 visible characters (e.g. a JavaScript-only shell seen by a non-browser client) |
other | anything else (e.g. 404 on a sitemap URL, non-standard codes) |
Per site, the primary outcome for each client is its homepage outcome; a secondary measure takes the worst outcome across all fetched pages (block > challenge > rate-limited > error > thin > other > ok).
| Vendor | Signal |
|---|---|
| Cloudflare | cf-ray or server: cloudflare |
| Akamai | akamai-grn, server: AkamaiGHost or x-akamai-transformed |
| CloudFront (AWS) | x-amz-cf-id |
| Fastly | x-served-by: cache-… or via: … fastly |
| Vercel | x-vercel-id or server: Vercel |
| DataDome | x-datadome |
| Imperva / Azure | x-iinfo or x-cdn: Imperva; x-azure-ref |
Statistics. Wilson 95% intervals for proportions; McNemar's exact test for the paired comparison between clients (the same site seen by two clients); Cohen's κ for agreement between rounds.
6. Results — are honest agents treated differently? (RQ2)
Full size| Outcome | agent | script | browser |
|---|---|---|---|
| Challenged or blocked | 16.0% (11.0–22.7) | 18.7% (13.2–25.7) | 18.7% (13.2–25.7) |
… of which block | 8.7% | 11.3% | 11.3% |
… of which challenge | 7.3% | 7.3% | 7.3% |
ok | 69.3% | 64.7% | 70.0% |
thin (little visible text) | 4.0% | 4.7% | 0.7% |
rate_limited | 1.3% | 1.3% | 1.3% |
error (incl. unreachable) | 7.3% | 8.7% | 6.7% |
other | 1.3% | 2.0% | 2.7% |
self_excluded (obeyed robots.txt) | 0.7% | — | — |
| Comparison | Sites | Only first blocked | Only second blocked | McNemar p |
|---|---|---|---|---|
| agent vs browser | 137 | 2 | 5 | 0.45 |
| agent vs script | 135 | 2 | 6 | 0.29 |
| script vs browser | 137 | 5 | 4 | 1.00 |
The declared agent was stopped slightly *less* often than the anonymous clients, and none of the differences is statistically significant. Sites that block, block everyone automated; sites that allow, allow everyone.
- Across all fetched pages (not just the homepage), at least one page was challenged or blocked for the agent on 19.3% of sites, for the script on 22.7% and for the browser on 23.3%.
- The browser sees more content where the HTTP clients see a JavaScript shell:
thinfalls from 4–5% to 0.7%.
| Client | Same outcome in both rounds | Cohen's κ |
|---|---|---|
| agent | 97.3% (93.3–99.0) | 0.947 |
| script | 98.0% (94.3–99.3) | 0.964 |
| browser | 96.7% (92.4–98.6) | 0.932 |
Round 2 reproduced the headline exactly: 16.0% / 18.7% / 18.7%.
7. Results — what robots.txt says about AI agents (RQ1)
Of the 150 sites, 125 served a robots.txt, 12 refused our agent even that file with HTTP 403, 10 could not be reached from our location, and 3 returned other codes (498, 429, 404). Policies could therefore be read for 140 sites, 121 of which had a non-empty file.
Full size/, coloured by purpose. Base: 140 sites with a fetchable robots.txt.| Token | Vendor | Purpose | Named explicitly | Disallows `/` |
|---|---|---|---|---|
Bytespider | ByteDance | training | 22.9% | 19.3% |
CCBot | Common Crawl | training | 22.1% | 18.6% |
ClaudeBot | Anthropic | training | 25.0% | 17.1% |
GPTBot | OpenAI | training | 22.9% | 14.3% |
Applebot-Extended | Apple | training | 19.3% | 14.3% |
Meta-ExternalAgent | Meta | training | 18.6% | 13.6% |
Google-Extended | training | 18.6% | 11.4% | |
PerplexityBot | Perplexity | search | 22.9% | 12.9% |
Claude-SearchBot | Anthropic | search | 12.1% | 7.9% |
OAI-SearchBot | OpenAI | search | 16.4% | 5.7% |
Claude-User | Anthropic | user-initiated | 13.6% | 9.3% |
Perplexity-User | Perplexity | user-initiated | 14.3% | 8.6% |
ChatGPT-User | OpenAI | user-initiated | 17.9% | 7.9% |
Googlebot | search (control) | 14.3% | 0.0% |
Sites are roughly twice as likely to shut out crawlers that collect training data as agents fetching a page for a person. Many files name AI tokens explicitly (a quarter name ClaudeBot) without disallowing them — the rules are often more nuanced than a blanket "no AI".
8. Results — does the edge honour what the policy allows? (RQ3)
137 reachable sites have a robots.txt that allows our agent at / (or no robots.txt at all, which allows everything). On 16.8% (11.5–23.9) of them, the edge still challenged or blocked the agent's homepage request.
That looks like a contradiction between policy and enforcement — until the other clients are checked. In almost all of those cases the headless browser was stopped too; it got the page on only 2 sites (1.5%) where the agent was turned away.
The gap between written policy and edge behaviour is real, but it is mostly not aimed at AI. These edges stop automated clients in general, whatever robots.txt says. A site's robots.txt is therefore a poor guide to whether an agent will actually get through.
9. Results — where blocking happens (RQ4)
Full size| Sector | agent | script | browser |
|---|---|---|---|
| E-commerce | 30.0% | 30.0% | 30.0% |
| Media | 23.3% | 33.3% | 33.3% |
| SaaS / B2B | 13.3% | 13.3% | 20.0% |
| Finance | 6.7% | 6.7% | 6.7% |
| Developer tools | 6.7% | 10.0% | 3.3% |
| Vendor | Sites | agent | script | browser |
|---|---|---|---|---|
| Akamai | 27 | 33.3% | 40.7% | 44.4% |
| DataDome | 3 | 66.7% | 66.7% | 66.7% |
| Cloudflare | 34 | 17.6% | 20.6% | 17.6% |
| Fastly | 11 | 18.2% | 18.2% | 18.2% |
| CloudFront | 22 | 13.6% | 13.6% | 13.6% |
| Vercel | 7 | 0.0% | 0.0% | 0.0% |
| other / unknown | 46 | 4.3% | 6.5% | 6.5% |
Cells are small (3–46 sites), so read them as descriptive. DataDome appears on only 3 sites and is left out of Figure 3.
Retail and news sites, and sites fronted by Akamai or DataDome, stop automated visitors most; developer tools, finance sites and Vercel-hosted sites least. Within every group, the honest agent fares about the same as — or better than — the anonymous clients.
10. Notable edge cases
- robots.txt refused. 12 sites answered HTTP 403 when our labelled agent asked for
robots.txtitself — the one file meant to tell crawlers the rules. - Pay to crawl. One major publisher answered our declared agent's homepage request with 402 Payment Required — consistent with a paid-crawling gate — while the unlabelled script and the headless browser were simply blocked with 403. Declaring itself got the agent an offer rather than a wall.
- Vendor-specific block codes. One large retailer's own anti-bot system answered all three clients with a non-standard 498; under the frozen rules this counts as
other, although it is effectively a block. - Login walls. One marketplace showed the headless browser a login page with enough text to count as
okunder the rules. - Unreachable from our location. Nine sites — mostly Russian banks and crypto exchanges — could not be reached by any client, including the browser, consistent with geographic blocking of our vantage point.
11. How the study actually ran
The complete record, including every problem. Times are UTC, 12–13 October 2026.
- Oct 12 · ≈16:45Sample built
Tranco list
4672Xwalked from rank 1 under the written rule; 150 domains fixed indata/sample/domains.csv. - ≈16:50Bot page updated
The public research-bot page was updated to describe this study, including the plain script and headless browser, before any request.
- ≈16:52–17:00First robots.txt census — too aggressive
Run at concurrency 8, it produced 83 fetch failures out of 150; 58 of those succeeded when fetched one at a time. The failures were self-inflicted load on the home connection. Deviation 1.
- ≈17:00–17:22Census re-run
Concurrency 2 with one retry: 140 readable, 10 unreachable (consistent with geo-blocking).
- ≈17:26Pre-registration frozen
Commit
7113eda— after the census, before any Part 2 request. - 18:16–19:42Edge round 1 (first attempt)
Probing never overlapped the other study's traffic.
- 19:09 → after 20:10First connection outage
From 19:09 every request from every client failed, including sites that had loaded moments earlier. All of round 2 (19:42–20:10) and 18 round-1 sites were discarded. Deviation 2.
- Oct 13 · 00:51–00:57Connection restored; 18 sites re-probed
Unchanged harness; a per-minute connectivity log was started.
- ≈00:58Browser-measurement defects found
A first look at round 1 showed a 22% error rate for the browser against 9–10% for the others. Cause: page loads timing out when 6 sites loaded in parallel, and Chromium hiding empty-body error responses. Fixed and tested. Deviation 3.
- 01:00–02:01Round 1 re-run in full
All three clients, all 150 sites, 4 sites in parallel. Browser error rate fell to 6.7%.
- 02:01–04:04Round 2 — second outage
The connectivity log shows the line down from 02:44 (44 of 54 checks failed). 71 affected sites discarded. Deviation 4.
- 07:12–07:4471 sites re-probed
No connection drops; round 2 reproduced the headline exactly.
- after 07:44Analysis, validation, report
Statistics computed by
harness/analyze.py; 20 results validated by hand; report and figures written.
12. Validation
The pre-registration required ≥ 90% agreement on 20 stratified site × client results, checked by hand against the stored evidence: status, headers, cookie names, challenge markers, page title and text length.
Typical evidence: an Akamai "Access Denied" page behind a 403, Cloudflare's cf-mitigated: challenge header, DataDome markers behind a 401 or 403, 429 responses. Three results were correct under the frozen rules but understate what happened — the 498 vendor block and the 402 payment gate (both other) and a login wall (ok). They are reported as rule limitations, not reclassified.
The reviewer is also the harness author, so this is a documented self-check. An outside reviewer is recommended before the report is finalised.
13. Pre-registration deviations
The protocol was frozen in commit 7113eda after the policy census and before any edge request. Four deviations followed, each logged before the affected data was analysed.
Deviation 1 — census re-run at lower concurrency
- What happened: the first census (concurrency 8, no retry) produced 83/150 fetch failures; 58 succeeded when fetched sequentially, so the failures were self-inflicted.
- Action: re-run in full with concurrency 2 and one retry; that run is the one reported. Before freezing, only fetch-status counts and one token count were looked at.
- Result: 10 domains remained unreachable for every client, including a headless browser.
Deviation 2 — first connection outage
- What happened: the connection failed from about 19:09 UTC on 12 October until at least 20:10.
- Discarded: all of round 2 and the 18 round-1 sites where any client started at or after 19:09.
- Action: after connectivity was restored (00:51 UTC), those sites were re-probed with the unchanged harness.
Deviation 3 — browser-measurement defects fixed, both rounds re-run
- How it was found: round 1 showed a 22% homepage error rate for the browser against 9–10% for the HTTP clients.
- Defects: full page loads exceeded the 20 s limit with 6 sites in parallel (the same pages load in 5–8 s alone), and Chromium raises
net::ERR_HTTP_RESPONSE_CODE_FAILUREinstead of returning empty-body error responses, so blocks were recorded as errors. - Fix: capture the main-document response even when navigation raises; 45 s browser timeout; 4 sites in parallel; store the first line of each error.
- Action: both rounds re-run in full for all three clients so conditions are identical.
- Disclosure: decided after round-1 outcome tables had been seen; classification rules and analysis unchanged.
Deviation 4 — second connection outage
- What happened: the per-minute connectivity log shows the line down from 02:44 UTC on 13 October until the round ended at 04:04.
- Discarded: the 71 round-2 sites where any client started at or after 02:44.
- Action: re-probed at 07:12–07:44 UTC with the unchanged harness; round 1 had finished before the outage.
14. Limitations
- One vantage point. A residential connection in Nigeria. Edge decisions depend on IP reputation and geography; because all three clients share the IP, comparisons *between clients* are controlled, but absolute rates may differ from elsewhere.
- Declared, not verified. The study does not measure how sites treat vendors' verified crawlers.
- 150 sites, one labeller, and a keyword screen for finance and developer-tool candidates beyond rank 1,500.
- Headless means headless. The browser announces itself as headless Chrome, so its results are not those of a human visitor.
- Policy as written.
robots.txtis recorded as written; user-initiated agents may not follow it. - Rule limitations. Vendor-specific block codes and payment gates count as
other, and a login wall can count asok. - Interrupted runs. Two outages and a browser-measurement fix meant parts of each round ran hours apart; every affected result was re-probed and the two rounds agree on 97–98% of results.
15. Ethics
- Honest identities only; no client impersonated another company's crawler or a human visitor.
- No CAPTCHA was solved or bypassed — a challenge was recorded, never evaded.
- Public pages only; nothing behind a login.
- About 12 requests per site per round, at most 1 per second, with 30-second pauses between clients.
- A public bot page describing the study, with an opt-out address honoured within 24 hours.
- No page bodies stored. Sites are named only for public
robots.txtfacts, never for edge behaviour.
16. Reproducing the study
The harness, sample, page list, raw robots.txt files and per-site results are in the public repository:
python -m venv .venv && .venv/Scripts/pip install protego httpx playwright tranco python census.py # Part 1: robots.txt census + page list python edge_probe.py --round 1 # Part 2: three clients, randomised order python edge_probe.py --round 2 python analyze.py --round 1 --retest 2 # classification + every number on this page python figures.py # the three figures on this page
Edge behaviour changes over time and by location, so a re-run from another network is expected to give different absolute rates; the comparison between clients is the robust part of the design.
Data, code & links
Everything above is in this page. For readers who want the source material, the files below are the frozen pre-registration, the full report as plain text, the computed statistics and the open repository with the harness and per-endpoint data.
- Pre-registration and deviations The frozen protocol and all four logged deviations
- Full report (Markdown) The report this page is built from
- Summary statistics Every number with its denominator and 95% interval
- Validation results The 20 hand-checked results and notes
- Harness, sample and data (GitHub) Census, edge probe, analysis, robots.txt files, per-site results
- About the research bot What GlintbaseResearch requests and how to opt out
@techreport{glintbase2026silentwall,
title = {The Silent Wall (2026): How Popular Websites' Bot Policies and Edge Defences Treat a Self-Declared AI Agent},
author = {{Glintbase Research}},
institution = {Glintbase},
year = {2026},
month = {October},
type = {Draft Research Report},
url = {https://glintbase.dev/research/the-silent-wall}
}Agent-readable version of this report: /research/the-silent-wall.md