How the Inspector is tested, in public.
This page used to show websites as proof. Now the proof is the instrument: how the Inspector reads a page, and how we check that it tells the truth.
What one inspection does.
The Inspector reads one page, the front page, from the outside, the way a stranger's first visit receives it, without running its scripts. It makes at most 9 requests: the page, and a few small files like robots.txt, the file where a site says which automated readers are welcome. It stops after 12 seconds or 3 megabytes.
It can run 40 checks. Every one of them is listed below with what it is worth, because a score you cannot take apart is a score you have to take on trust.
The score is a weighted average. Each check that applied earns a share of its weight: all of it for a pass, part of it for a warning, none for a fail. Add up what was earned, divide by the weight of every check that applied, and that is your number out of 100.
When it cannot measure a check, the report says so and leaves that check out of both totals. A site is never marked down for what we could not see, and the engine never guesses.
Every report ends with a table of evidence for every request it made: what was asked for, where, the answer, the time and the size.
What it cannot see is written down on its own page.
All 40 checks, and what each one is worth
Weights are read from the engine when this page is built, so this table cannot drift from the code it describes. A check marked for one trade only runs when the page reads as that trade.
| Check | Worth |
|---|---|
| A way to get in touch | 3 |
| Built for phones | 3 |
| Content arrives with the page | 3 |
| Missing pages behave | 3 |
| Page title | 3 |
| Secure address (HTTPS) | 3 |
| Tappable phone number | 3 |
| Visible to Google Search | 3 |
| Business information for Google | 2 |
| Image descriptions | 2 |
| Keyboard navigation shortcut | 2 |
| License number shown | 2 |
| Menu on the site | 2 |
| Menu readable on phones | 2 |
| No insecure resources | 2 |
| One clear headline | 2 |
| Online booking | 2 |
| Page language declared | 2 |
| Page size | 2 |
| Return and shipping policy | 2 |
| Search description | 2 |
| Security headers | 2 |
| Server response time | 2 |
| Stylesheet adapts to screens | 2 |
| Assistants can read the site | 1 |
| Hours where Google reads them | 1 |
| Images hold their place | 1 |
| Images load when needed | 1 |
| Link preview tags | 1 |
| Looks current | 1 |
| One official address | 1 |
| Outside dependencies | 1 |
| Preview image actually loads | 1 |
| Script load | 1 |
| Search engine instructions | 1 |
| Service area written out | 1 |
| Site icon | 1 |
| Sitemap | 1 |
| Spanish version | 1 |
| Written to be understood | 1 |
Two known weights on the scale.
A kitchen scale is checked with a weight you already know. So is the engine: 5 live websites every test session, two of them reference weights.
A known-excellent site
It must score at least 87, with at most 1 failed check, on the middle of 3 reads, because response time moves with the network.
A near-empty page
It must score no more than 70. A page with almost nothing on it must never look good.
If either weight drifts, we suspect the instrument first. The floor and the ceiling move only with a written reason.
What else the session checks, on every site it reads
It asserts 9 things each time, the reference weights among them. The grade must match the score on the engine's own ladder. Every quote the report puts in a site's mouth must really be on the page. Every request the engine made must show in the evidence table. Every skipped check must say why. And the partial credit a page earned on each check stays inside the engine, while every check in the report must carry its published weight.
113 saved pages with known answers.
A fixture is a saved web page whose right answer was decided before the engine saw it. A security challenge page must be refused, not graded. A restaurant inside a casino must still be graded.
Our test suite runs 177 cases on those 113 saved pages and on test pages written into the suite itself. We run it when the engine changes. A wrong answer on any case is a reason to stop, though no automatic step blocks the change. Some cases were written after a real mistake.
The 177 cases, and what each one must do
Each row names a test page and the answer the engine must give on it. The answers are in the suite's own words, except the skip-link rows, which we put in plain words.
"Schema" here is the business information a page hands to Google, the check listed above as Business information for Google.
A skip link lets someone using a keyboard jump past the menu to the content. Its check is listed above as Keyboard navigation shortcut.
| Case | What the engine must do |
|---|---|
skiplink/a-span-in-link-div-target | the skip-link check must pass |
skiplink/a-span-in-link-main-target | the skip-link check must pass |
skiplink/a-aria-label-emoji | the skip-link check must pass |
skiplink/a-img-alt-in-link | the skip-link check must pass |
skiplink/b-unquoted-href | the skip-link check must pass |
skiplink/b-unquoted-role-main | the skip-link check must come back with a warning |
skiplink/b-single-quoted-href | the skip-link check must pass |
skiplink/c-meet-the-skipper | the skip-link check must fail |
skiplink/c-skipping-the-queue-in-main | the skip-link check must come back with a warning |
skiplink/c-anchor-menu-services | the skip-link check must come back with a warning |
skiplink/c-cta-before-nav | the skip-link check must come back with a warning |
skiplink/d-missing-target-no-main | the skip-link check must fail |
skiplink/d-missing-target-with-main | the skip-link check must come back with a warning |
skiplink/d-target-in-template | the skip-link check must fail |
skiplink/d-hash-top-no-id | the skip-link check must fail |
skiplink/d-hash-top-main-id-top | the skip-link check must pass |
skiplink/d-base-href-other-path | the skip-link check must fail |
skiplink/d-root-slash-hash | the skip-link check must pass |
skiplink/d-target-before-nav | the skip-link check must fail |
skiplink/d-target-wraps-header | the skip-link check must come back with a warning |
skiplink/d-target-anchor-end-of-nav | the skip-link check must pass |
skiplink/d-script-hook-missing-target | the skip-link check must be skipped as not verified |
skiplink/e-data-role-main | the skip-link check must fail |
skiplink/e-main-aria-hidden | the skip-link check must fail |
skiplink/e-main-hidden | the skip-link check must fail |
skiplink/e-role-foo-main | the skip-link check must come back with a warning |
skiplink/e-main-wraps-header | the skip-link check must fail |
skiplink/f-skip-link-in-footer | the skip-link check must fail |
skiplink/f-logo-nav-then-skip | the skip-link check must fail |
skiplink/f-logo-skip-div-menu | the skip-link check must pass |
skiplink/f-tabindex-minus-one | the skip-link check must fail |
skiplink/f-inline-display-none | the skip-link check must fail |
skiplink/f-hidden-by-class | the skip-link check must pass |
skiplink/f-link-aria-hidden | the skip-link check must come back with a warning |
skiplink/g-link-in-script-string | the skip-link check must fail |
skiplink/g-link-in-template | the skip-link check must come back with a warning |
skiplink/g-link-in-noscript | the skip-link check must come back with a warning |
skiplink/g-wp-block-theme-script | the skip-link check must be skipped as not verified |
skiplink/g-wp7-server-side | the skip-link check must pass |
skiplink/h-no-links-h1-prose | the skip-link check must be skipped |
skiplink/h-no-links-main | the skip-link check must be skipped |
skiplink/h-content-then-footer-link | the skip-link check must be skipped |
skiplink/h-menu-at-bottom | the skip-link check must be skipped |
skiplink/h-wp-plain-permalinks | the skip-link check must come back with a warning |
skiplink/i-plain-skip-link | the skip-link check must pass |
skiplink/i-spanish-saltar | the skip-link check must pass |
skiplink/i-jump-to-main-content | the skip-link check must pass |
skiplink/i-breadcrumb-nav-inside-target | the skip-link check must pass |
skiplink/i-article-header-inside-target | the skip-link check must pass |
skiplink/i-target-hero-inside-header | the skip-link check must pass |
skiplink/i-two-skip-links-g124 | the skip-link check must pass |
skiplink/i-skip-link-first-inside-header | the skip-link check must pass |
skiplink/j-nav-then-headings-no-main | the skip-link check must come back with a warning |
skiplink/j-headings-only-in-div-footer | the skip-link check must fail |
skiplink/j-heading-inside-div-mega-menu | the skip-link check must fail |
skiplink/x-T1-div-header-skip-wraps-main-article-header | the skip-link check must pass |
skiplink/x-T1b-breadcrumb-home-only-inside-target | the skip-link check must pass |
skiplink/x-T1c-breadcrumb-two-links-inside-target | the skip-link check must pass |
skiplink/x-T15-target-hero-inside-header | the skip-link check must pass |
skiplink/x-T2c-logo-skip-div-menu | the skip-link check must pass |
skiplink/x-T3-div-nav-div-footer-h4-only | the skip-link check must come back with a warning |
skiplink/x-T3b-div-mega-menu-h3-only | the skip-link check must fail |
skiplink/x-T5-wp-plain-permalinks | the skip-link check must fail |
skiplink/x-T6-anchor-menu-services-in-main | the skip-link check must come back with a warning |
skiplink/x-T7-cta-before-nav | the skip-link check must come back with a warning |
skiplink/x-T8-noscript-link-before-skip | the skip-link check must pass |
skiplink/x-T19-content-then-footer-element | the skip-link check must be skipped |
skiplink/x-T19b-content-then-footer-div | the skip-link check must be skipped |
skiplink/x-N1-minified-no-whitespace | the skip-link check must pass |
skiplink/x-N2-name-split-across-inline-and-comment | the skip-link check must pass |
skiplink/x-N3-id-twice-first-hidden | the skip-link check must come back with a warning |
skiplink/x-N4-target-inside-svg | the skip-link check must pass |
skiplink/x-N4b-target-inside-math | the skip-link check must pass |
skiplink/x-N5-uppercase-tags-and-attributes | the skip-link check must pass |
skiplink/x-N6-percent-encoded-fragment-utf8 | the skip-link check must pass |
skiplink/x-N7-title-only-name-img-empty-alt | the skip-link check must pass |
skiplink/x-N8-button-before-skip-outside-block | the skip-link check must pass |
skiplink/x-N8b-button-then-skip-inside-header-block | the skip-link check must pass |
skiplink/x-N9-article-header-before-target | the skip-link check must pass |
skiplink/x-N10-target-wraps-the-link-itself | the skip-link check must fail |
skiplink/x-N11-js-shell-only | the skip-link check must be skipped as not verified |
skiplink/x-N12-a-inside-a-adoption | the skip-link check must pass |
skiplink/x-N13-link-in-table-cell | the skip-link check must pass |
skiplink/x-N13b-link-foster-parented-out-of-table | the skip-link check must pass |
skiplink/x-N14-adoption-agency-b-a-skip | the skip-link check must pass |
skiplink/x-N15-unclosed-p-before-link | the skip-link check must pass |
skiplink/x-N16-percent-encoded-id-literal | the skip-link check must pass |
skiplink/x-N17-role-navigation-uppercase-hidden-drawer | the skip-link check must pass |
skiplink/x-N18-inline-script-builds-skip-link | the skip-link check must come back with a warning |
skiplink/x-N19-target-in-closed-details | the skip-link check must pass |
skiplink/x-N20-area-skip-link | the skip-link check must pass |
skiplink/x-Z1-one-megabyte-page | the skip-link check must pass |
skiplink/x-S1-plain-skip-link-with-stylesheet | the skip-link check must pass |
skiplink/x-S2-classless-skip-link-with-stylesheet | the skip-link check must pass |
skiplink/x-S3-wp7-server-side-with-stylesheet | the skip-link check must pass |
honesty-challenge | engine returns an error, not a grade |
redirect-hijack | engine returns an error, not a grade |
shell-vite | rendering check fails on a shell page (shell was detected) |
schema-jsonld | schema check is not a fail |
schema-microdata | schema check is not a fail on a Microdata page |
spanish-element | spanish check is not a flat fail on element-level lang=es |
spanish-full-page | spanish check is not a fail on a full-page lang=es |
spanish-none-florida | spanish check runs (not skipped) on a Florida business page |
viewport-tag-only | viewport check passes when the tag is present (regardless of layout) |
same-domain-redirect | engine grades the page (no error) on a same-domain redirect |
promise-third-party-licensed | engine does not fire promise check on third-party "licensed" advice |
promise-self-licensed | engine fires promise check on first-person "We are licensed" |
fresh-license-comment | a year inside <style>, <script> or a comment does not fail "Looks current" |
fresh-template-year | a copyright year ahead of today fails "Looks current" |
gate-hijacked | engine returns an error, not a grade |
gate-parked | engine returns an error, not a grade |
gate-placeholder | engine returns an error, not a grade |
gate-casino-resort | a restaurant in a casino hotel is graded, not refused |
redirect-labelled | redirect refusal is labelled elsewhere |
sitemap-fallback-on-ledger | the sitemap robots.txt names is on the ledger |
unreachable-name | field says name |
unreachable-refused | field says refused |
unreachable-certificate | field says certificate |
unreachable-timeout | field says timeout |
unreachable-other | no field when the cause is not one we can name |
noindex-meta-none | noindex state is fail |
noindex-meta-googlebot | noindex state is fail |
noindex-meta-crawler-prefix-kept | noindex state is fail |
noindex-text-is-not-a-tag | noindex state is pass |
noindex-comment-inside-script | noindex state is fail |
noindex-custom-elements-are-not-raw-text | noindex state is fail |
noindex-shapes-that-must-not-count | noindex state is pass |
noindex-meta-googlebot-news | noindex state is pass |
noindex-header-other-crawler | noindex state is pass |
noindex-header-none | noindex state is fail |
noindex-header-googlebot-news | noindex state is pass |
noindex-header-googlebot-inherits | noindex state is fail |
noindex-header-joined-lines-are-ambiguous | noindex state is skip |
noindex-header-robots-prefix-kept | noindex state is fail |
noindex-header-values-are-not-rules | noindex state is pass |
noindex-google-two-line-example | noindex state is pass |
noindex-meta-and-header | noindex state is fail |
noindex-google-kept-out-by-robots | noindex state is fail |
noindex-google-allowed-in-by-longest-match | noindex state is fail |
noindex-landed-page-not-root | noindex state is fail |
schema-phone-under-contactpoint | schema passes: a phone under contactPoint is a phone |
schema-business-beside-website-block | schema passes: one real business block is enough; a WebSite block beside it is not a defect |
schema-empty-address-stub | schema warns: an address object carrying only a type is not an address |
schema-one-block-broken-beside-a-real-one | schema passes on the real block |
imgweight-unquoted-lazy-is-lazy | imgweight state is pass |
imgweight-three-eager-warns | imgweight state is warn |
imgweight-shapes-that-stay-eager | imgweight state is warn |
imgweight-shapes-that-stay-lazy | imgweight state is pass |
imgweight-noscript-pixel-is-not-an-image | imgweight state is pass |
imgweight-data-src-waits-for-a-script | imgweight state is pass |
imgweight-lazysizes-transparent-srcset | imgweight state is pass |
imgweight-data-uri-src-is-inline | imgweight state is pass |
imgweight-whitespace-src-is-no-address | imgweight state is pass |
imgweight-picture-and-srcset | imgweight state is warn |
imgweight-svg-image-is-not-img | imgweight state is skip |
imgweight-picture-source-is-taken-as-used | imgweight state is warn |
imgweight-svg-style-and-title-are-not-raw-text | imgweight state is warn |
imgweight-img-inside-svg-breaks-out | imgweight state is warn |
imgweight-script-end-tag-in-a-string-ends-the-script | imgweight state is warn |
image-list-feeds-alt-and-dims | dims reads the size after a quoted ">" and rejects width="" |
comment-strip-reads-comments-the-way-a-browser-does | the tap-to-call link after the script string is real |
readinglevel-menus-do-not-merge-into-sentences | readinglevel passes on the two paragraphs alone |
readinglevel-spanish-page-is-not-scored | readinglevel skips |
readinglevel-spanish-section-is-left-out | the English paragraphs alone are scored |
readinglevel-not-enough-running-text | readinglevel skips |
readinglevel-form-wrapped-page-is-scored | readinglevel is warn on the warm paragraph, not skip |
readinglevel-table-layout-page-is-scored | readinglevel is warn on the warm paragraph, not skip |
readinglevel-hero-header-inside-main-is-scored | readinglevel is warn on the warm paragraph, not skip |
readinglevel-mismatched-heading-close-is-scored | readinglevel is warn on the warm paragraph, not skip |
readinglevel-class-named-hidden-is-scored | readinglevel is warn on the warm paragraph, not skip |
readinglevel-two-mains-use-both | with two mains, both are read (the standard names one main as the dominant content; two is not that page) |
readinglevel-hidden-dialog-and-data-table-are-left-out | only the warm paragraph is scored |
walkaway-1.7.0-retired | no walkaway block in the response |
platform-ordering-page-is-refused | a Menufy page is refused, not graded |
builder-domain-site-is-still-graded | a site on a builder's domain is the business's own site and is graded |
phone-and-licence-values-are-kept | the tel check keeps one business line and the tap-to-call numbers, ten digits each, the country code dropped |
a-number-with-no-phone-cue-is-not-kept-as-the-line | the line is the number beside the phone cue, not the invoice reference |
A version, and a seal on it.
The engine is version 1.8.1. On September 23, 2026 it read 164 pages written for the purpose, offline, and everything it produced was hashed into one fingerprint: 0ff07078bb262f37.
The fingerprint covers the grade, the score, the recognized trade and every check's state. It leaves out wording and timings on purpose: a better sentence never costs a version. A moved line in a check costs one only when a locked page sits on that line, and not every line has one yet.
Before a change can ship, the engine reads those pages again. If the fingerprint moves and the version has not, the build stops, and so does the crawler.
The census does not meet that standard yet. Of its 78,807 sites, 361 were read before the engine had a version, and 48 by code that was never saved. It will be read again under one sealed version, and the figures switch to that version only when every address has been tried under it.
The same websites, every few days.
Nobody at those businesses asked to be graded. The engine has read the same 100 websites 2 times since October 12, 2026. On October 15, 2026 it graded 87 of them; the middle score was 82 out of 100.
A refusal is a refusal, never a grade. The benchmark page holds the whole record.
Our own pages, held to a standard first.
Strangers are graded by the engine. Our own pages are held to our house rules before every deploy: every standing rule, one runner, one verdict. If one fails, the site does not deploy.
Below is part of a real run of the program that checks our own pages. On October 12, 2026, that run held 53 rule sections. Shown are 3 of its passing lines, shortened where they ran long, and its verdict. An exit code of 0 means it finished with no failure.
PASS zero em dashes across all pages and 3 download(s), entities...
PASS 1 files post to web3forms, every one of them carries a key ...
PASS R67: git tracks only register/SUMMARY.json under register/;...
VERDICT: all rules hold. 4 WARNs (prompts, not drift).
Exit code 0. Any warnings the verdict counts are prompts to look again, not failures; their lines are not shown here.
Before a deploy, 131 mistakes are planted on purpose in a built page or our own files. Each of 39 hard rules gets at least one, and has to catch its own. A rule that cannot fail is decoration.
What we will not show, and will not claim.
The weights are published, above. What stays home is where each check draws its lines, and the fractional credit a page earned against them.
We will not pretend that makes the lines a secret. Anyone who tests their own page against the inspection can find roughly where one sits, because we tell you what we measured. What we will not do is hand over the curve ready made, or spend our time defending a number instead of improving it.
We will not claim a better score earns more money. We hold scores, not sales. A score describes a front page, not a business. The Three Rings lists every refusal.
Read your own site the same way.
The free inspection runs the same 40 checks on your site in a few seconds and shows what it looked at. If the site is good, it says so.
If it read your site wrong, write to hello@truemeasurewebdesign.com. True Measure Inspector corrects its own work in public.