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.
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.
What the stale number hid
- 65 of 84 checks
- Recorded against an older instrument
- Predates the 9 Aug fix round that took the content score 70 to 88
- 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
| Page | Defect | Before | After |
|---|---|---|---|
/services | Title below snippet budget | 33 chars "Teleradiology Services ยท AstraRad" | 58 names the modalities covered |
/locations | Title below budget | 38 chars | 54 |
/privacy | Title below budget | 25 chars | 57 |
/terms | Title below budget | 27 chars | 59 |
Every hub except /use-cases | Heading level skipped, H1 straight to H3 | fail | H1 to H2 to H3 |
/ | Lazy client logo with no dimensions, layout shift | no width/height | 318x78 |
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
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.
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.
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.