On-page SEO audit, 15 August 2026

All 58 published URLs measured against the live HTML, not against the last recorded score. Four defects found and fixed the same day; everything else already passed.

What it is

The current, measured on-page SEO state of astrarad.com, replacing a figure that had drifted badly out of date. Scenario: Rafael reads "on-page audit 48% to 77%, 65 of 84 checks" in the wiki, assumes a third of the site is broken, and asks for the gaps to be fixed. This page shows what a fresh measurement actually returns, what was genuinely wrong, and which two remaining flags are not worth chasing. Companion to agent-readiness-scan-2026-08-15.html.

1,797 of 1,798 page-level checks pass 31 checks across 58 URLs, measured on production after the fix. The single remaining failure is a thin hub page that needs more published children, not more markup.

What the stale number hid

What the wiki said
77%
  • 65 of 84 checks
  • Recorded against an older instrument
  • Predates the 9 Aug fix round that took the content score 70 to 88
What measurement returned
99.9%
  • 1,797 of 1,798 checks, 58 URLs
  • Zero duplicate titles, zero duplicate descriptions
  • Four real defects, all fixed and live

The lesson is the same one the agent-readiness report records: measure before believing a stored score. Both numbers in the wiki were true when written and neither was true today.

Already passing on all 58 pages, before any change

Worth stating explicitly, because it is the bulk of the surface and none of it needed work: title and description present and unique, description within 100 to 160 characters, charset, viewport, absolute HTTPS canonical, html lang, all six Open Graph properties including image dimensions, all four Twitter Card properties, valid JSON-LD, exactly one h1, no empty headings, alt text on every image, no generic anchor text, semantic landmarks, a skip link, GA4 present exactly once, and no deprecated tags.

The four defects, fixed

PageDefectBeforeAfter
/servicesTitle below snippet budget33 chars
"Teleradiology Services ยท AstraRad"
58
names the modalities covered
/locationsTitle below budget38 chars54
/privacyTitle below budget25 chars57
/termsTitle below budget27 chars59
Every hub except /use-casesHeading level skipped, H1 straight to H3failH1 to H2 to H3
/Lazy client logo with no dimensions, layout shiftno width/height318x78
The heading bug was wider than one page

The All coverage scenarios H2 in section-index.component.ts sat behind @if (scenarios.length), and only /use-cases has scenarios. Every other hub therefore stepped H1 straight to the card H3 and then back to the FAQ H2. The comment directly above the block claimed the outline "steps H1 to H2 to H3 with no skip", which was true only on the single section that happened to have scenarios.

The block now always renders, with listingHeading and listingIntro overridable per route and defaults that reproduce the previous /use-cases copy verbatim, so that page is unchanged. /locations sets "All metro markets".

One trap worth recording: the route data map in app.routes.ts picks keys explicitly rather than spreading, so the first attempt silently dropped both new fields and rendered the generic default. A new field on SECTION_HUBS does nothing until it is also listed there.

Two flags deliberately not chased

Text-to-code ratio under 25% on 47 of 58 pages

Not a real defect, and chasing it would cause damage. Median is 19.3%. This is a prerendered Angular site: every page carries inlined critical CSS, Angular hydration markers, and JSON-LD blocks. The ratio heuristic penalises exactly that architecture. Getting it above 25% would mean stripping structured data and critical CSS, which would cost rich results and make Core Web Vitals worse. Google does not use this metric. It stays flagged and unactioned.

Where a low ratio does point at something real, it is thin content rather than heavy markup, which is the next item.

/locations is 295 words, under the 300 floor

This one is real, and it is not fixable with markup. The page is a hub and it has exactly one published child, Austin. It is thin because the section is nearly empty, so the honest fix is publishing more metro market pages, not padding the hub with filler to clear a word count. Left open deliberately.

And one false alarm

A generic checklist flags "no Google Search Console verification meta tag" on the homepage. Search Console is verified, by DNS TXT record (google-site-verification=6XJWVOqHL_73...), which is the stronger method because it covers every subdomain and protocol. No change needed.

How to re-measure

Do not trust a stored score. Fetch every URL in the sitemap and check the delivered HTML:

curl -s https://astrarad.com/sitemap.xml | grep -oP '(?<=<loc>)[^<]+' > urls.txt
# then parse each page for title length, description, canonical, OG, Twitter,
# JSON-LD validity, heading sequence, img alt and dimensions

The build already enforces the parts that can be enforced: postbuild-seo.mjs runs a rendered-title budget of 60 characters over every indexable route, plus integrity, freshness, inbound-link, hub-completeness, ask-intent and calendar-ordering gates, and build-content.mjs gates markdown titles to sentence case against seo/context/style-guide.md. That last gate rejected the first version of the two legal-page titles here, which is the gate working.

Measured against production on 15 August 2026, after deploy 6a80bffa. Fixes in commit d2c3a49. Route titles stay title case, matching their neighbours; markdown titles are sentence case, as the style guide requires.