Scoring v1.2
What we check
21 checks across 6 categories. The weights are below because publishing them is the only way the score can be argued with, and a score nobody can argue with is a horoscope.
The arithmetic
The weights
A category’s score is the share of its available points earned. A pass earns all of them, a warn earns half, a fail and an error earn none, and a skipped check leaves the denominator rather than counting as a zero. Changing any number here is a versioned event, not a tweak: every score row records the version that produced it, so history can be re-scored instead of overwritten.
| Category | Weight | Checks | Points |
|---|---|---|---|
| Retrievability | 25% | 4 | 35 |
| Discovery | 20% | 4 | 21 |
| Representation | 20% | 4 | 20 |
| Structure | 15% | 3 | 15 |
| Actionability | 15% | 4 | 15 |
| Freshness | 5% | 2 | 5 |
| Total | 100% | 21 | 111 |
Pass A
The clients
We request your page once as each of these, sequentially, one second apart. The Chrome request is the control and everything else is compared against it.
- chromeUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36control
- claudebotUser-Agent: ClaudeBot/1.0agent
- gptbotUser-Agent: GPTBot/1.2agent
- perplexityUser-Agent: PerplexityBot/1.0agent
- googleextUser-Agent: Google-Extendedagent
weight 25% · 35 points
Retrievability
- Every client gets the same answer18 points
agent_status_parity
fails when any agent client receives a different status class than the Chrome control
- Page text survives without JavaScript11 points
js_dependency_ratio
fails when ratio above 0.7
warns when ratio between 0.4 and 0.7
- First byte arrives quickly3 points
raw_fetch_latency
fails when ttfb above 2500 ms
- No long redirect chains3 points
redirect_depth
fails when more than 3 hops
weight 20% · 21 points
Discovery
- robots.txt exists and parses4 points
robots_present
- robots.txt does not silently block reading agents8 points
robots_agent_rules
fails when an agent user agent is disallowed while search crawlers are allowed
- Sitemap exists and is not empty4 points
sitemap_present
- llms.txt tells agents which pages matter5 points
llms_txt_present
weight 20% · 20 points
Representation
- A markdown representation is advertised7 points
markdown_alternate
fails when no link rel=alternate type=text/markdown and no Link header equivalent
- One h1, a sane heading order, a main landmark6 points
semantic_landmarks
- Each page has its own title and description4 points
title_meta_distinct
- Server honours Accept: text/markdown3 points
content_negotiation
weight 15% · 15 points
Structure
- JSON-LD describes what this is6 points
jsonld_present
- Pricing is machine readable5 points
pricing_structured
fails when prices appear only in images or JS-rendered tables
- Canonical URL and OpenGraph are complete4 points
canonical_og
weight 15% · 15 points
Actionability
- An agent manifest or WebMCP endpoint exists5 points
agent_manifest
- API docs are two hops from the homepage4 points
api_docs_reachable
- Primary forms have labels, names and autocomplete tokens4 points
form_semantics
- Docs and pricing are not behind auth or a captcha2 points
no_wall_on_docs
weight 5% · 5 points
Freshness
- Last-Modified or ETag is sent3 points
cache_headers
- Sitemap lastmod values are maintained2 points
sitemap_lastmod_real
fails when every lastmod is identical or in the future
Letters
The grade bands
- A 85–100
- B 70–84
- C 55–69
- D 35–54
- F 0–34
Limits, stated here rather than in a footer
What we will not do
- We never work around a block. If your site refuses BotreadyBot/1.0, we record it as refused and display it as refused. No second request under another user agent, no residential proxies, no captcha solving.
- We read at most 6 pages. Sequentially, 1 second apart. We are a diagnostic tool, not a load generator.
- We obey your robots.txt. Including when it is the thing being measured, and CI asserts it.
- We do not scan behind auth. A URL with credentials in it is refused rather than followed.
The catalog above is data, not code: adding, retiring or reweighting a check is an edit to one JSON file, which is why the numbers on this page cannot disagree with the scores on the result pages.