AstraRad SEO Audit · After 2026-07-31

In-Page SEO Audit

AstraRad · astrarad.com — re-scored against the identical 84-check, 18-category checklist used for the 2026-07-31 baseline, so the percentages are directly comparable. Every check below was measured against the live production deployment by curl, DNS lookup, and headless browser.

After — 2026-07-31 Angular 19 prerendered (SSG) 34 URLs in sitemap Real HTML, no JS required Netlify · HTTP/2
77%
Good
65 / 84 checks pass
was 40 / 84 (48%)
+25 checks · +29 pts

Before / After at a glance

Same checklist, same denominators, same N/A treatments as the baseline run.

Overall score
48%77%
Poor → Good. 40/84 → 65/84 checks.
Indexable pages
034
Pages a non-JS crawler can read. Was 0 of 8.
Words served in HTML
047k
Across 34 routes, 216 to 2,384 per page.
JSON-LD blocks
0119
34 MedicalOrganization, 33 BreadcrumbList, 26 FAQPage, 15 WebPage, 5 Service, 5 Article, 1 ItemList.
Categories at 100%
15
Twitter, Internal Linking, Technical SEO, Performance, LLM Readability.
Categories at 0%
62
Only Social Presence and Local Business remain at zero.

Per-Page Results

The 11 sampled routes, scored over the 12 page-scoped categories. Site-wide checks (robots, sitemap, analytics, social, DNS, llms.txt) are scored once in the panel below. Baseline pages scored 51–55%; every sampled page is now 85% or better.

RouteScoreWasStatus MetaOGTwitterJSON-LD HeadingsImagesWordsText ratio
/85%55%Good 1,17310.0%
/services87%53%Good 8549.8%
/pricing87%51%Good 1,0069.3%
/contact88%52%Good 2163.1%
/compliance89%Good 1,83218.6%
/sla89%Good 1,64516.9%
/privacy89%Good 1,72318.0%
/resources87%Good 1,15113.7%
/services/stat-ct-reads89%Good 1,73816.8%
/licensing/texas89%Good 1,44816.0%
/resources/teleradiology-cost87%Good 2,07220.1%
Pass Partial Fail Not applicable Word counts are from the raw HTML response — no JavaScript executed. Baseline counts required JS; a non-JS crawler saw 0.

Site-Wide Configuration

Infrastructure and domain-level signals, checked once against the live deployment and DNS.

Canonical domain
https://astrarad.com
All 34 pages declare an absolute HTTPS canonical matching their own URL.
Was: no page declared a canonical at all
robots.txt
Valid · text/plain
Serves a real robots file with a Content-Signal line (search=yes, ai-train=yes, ai-input=yes), 8 Disallow rules for app areas, and a Sitemap: directive.
Was: HTTP 200 returning the HTML shell
sitemap.xml
Valid · 34 of 34 pages
4,152 bytes of application/xml. Every listed URL was fetched and all 34 returned HTTP 200. No public marketing route is missing.
Was: missing — 0 of 8 pages listed
llms.txt
Present · text/plain
Company name, positioning summary, key facts (modalities, turnaround tiers, capacity, SLA) and a linked page index. Also advertised via an RFC 8288 Link: rel="describedby" response header.
Was: missing (returned HTML)
404 handling
Real 404
An unknown path returns a genuine HTTP 404 instead of a 200 shell, so crawlers no longer index infinite phantom URLs.
Was: every path returned HTTP 200
Default OG image
Present, but wrong aspect
/brand/astrarad-logo-dark.png returns 200 (41 KB PNG) but is 1857×576 — a wide logo, not the 1200×630 share card social platforms crop to. No og:image:width/height is declared on any page.
Was: no OG image existed at all
Structured data
119 blocks · 0 parse errors
MedicalOrganization sitewide plus BreadcrumbList, FAQPage, WebPage, Service, Article and ItemList. All parse as valid JSON with a correct @context.
Was: zero ld+json blocks sitewide
HTTPS & protocol
HTTP/2 · 301 redirect · HSTS
HTTP 301s to HTTPS. HSTS max-age=31536000; includeSubDomains, plus x-frame-options: DENY, x-content-type-options: nosniff, referrer-policy and permissions-policy.
Was: working, but without the security header set
Search Console
Verified via DNS
TXT google-site-verification=6XJWVOqHL_73fhFX… is live. The property is verified and there is now a real sitemap to submit — submit it.
Was: verified, but nothing to submit
Analytics
None installed
No GA4, no GTM, no Meta Pixel on any of the 34 pages. There is still no way to measure whether this rebuild moves traffic.
Was: none installed — unchanged
Email DNS
SPF + DMARC present
SPF v=spf1 include:_spf.google.com ~all; DMARC p=quarantine with an rua address.
Was: SPF + DMARC present — unchanged
Social profiles
0 linked
No LinkedIn, X or Facebook link in the footer or anywhere across all 34 pages. The only outbound links are 34 citations to regulator and government sources.
Was: 0 linked — unchanged
Agent-ready layer
Live (bonus, not scored)
All of /.well-known/agent-card.json, /.well-known/mcp/server-card.json, /.well-known/api-catalog, /.well-known/agent-skills/index.json and /auth.md return 200 with correct content types. Accept: text/markdown on /pricing returns real markdown.
Was: nothing existed
Local Business signals
No address, no phone
No physical address and no phone number appear anywhere. The only phone-shaped string on the site is the placeholder="+1 555 010 0100" attribute of the contact form input, which is not published contact information.
Was: no address, no phone — unchanged

Category Score Breakdown

A category check passes only when it passes on every applicable page — the same rule the baseline used. The faint grey bar behind each fill is the baseline score. 65 of 84 applicable checks pass.

Twitter Cards4/4 · 100% +100
Internal Linking3/3 · 100% 0
Technical SEO7/7 · 100% +43
Performance / CWV9/9 · 100% +11
LLM Readability3/3 · 100% +100
Open Graph5/6 · 83% +83
Structured Data4/5 · 80% +80
Heading Hierarchy4/5 · 80% +20
Meta Tags6/8 · 75% +25
Content Quality3/4 · 75% +25
Accessibility-SEO3/4 · 75% 0
Email & Security3/4 · 75% 0
Mobile Friendliness3/4 · 75% 0
Content Analysis3/4 · 75% +25
Image SEO3/5 · 60% 0
Monitoring & Analytics2/4 · 50% 0
Social Presence0/3 · 0% 0
Local Business0/2 · 0% 0

Remaining Issues by Priority

19 failing checks folded into 16 distinct findings. Every Critical finding from the baseline is resolved; what remains is one Critical measurement gap and a set of mechanical template defects.

Critical

2 checks
No analytics installed — the rebuild cannot be measured
No GA4 tag, no GTM container and no Meta Pixel appear on any of the 34 pages. 34 new pages have just been published with no instrumentation, so there is no way to tell which of them earn impressions, clicks or conversions. This is the single highest-value remaining fix and it needs a credential from you, not a code change. Fix: create a GA4 property, then add the gtag.js snippet to the Angular index.html head so it lands on every prerendered page.
Monitoring & Analytics

High

5 checks
Every page skips a heading level: h2 → h4
All 34 pages jump from an <h2> straight to an <h4> with no intervening <h3>. This is a single shared layout or content-block template, so one component fix corrects all 34 pages at once. Fix: find the component emitting the <h4> and demote it to <h3>, or promote the parent, so nesting is contiguous.
Heading Hierarchy
og:image:width and og:image:height missing sitewide
All 34 pages emit og:image but none declare its dimensions, so Slack, LinkedIn and iMessage must fetch and measure the image before they can render a preview — which often means they render none at all on first paste. Fix: add og:image:width and og:image:height to the shared SeoService meta block.
Open Graph
OG image is a 1857×576 logo, not a 1200×630 share card
/brand/astrarad-logo-dark.png is a wide logo strip. At the 1.91:1 ratio social platforms crop to, it will be letterboxed or centre-cropped into a sliver. Fix: produce a real 1200×630 share card carrying the wordmark plus a headline stat, and point og:image at it.
Open Graph
29 of 34 titles fall outside the 50–60 character window
Ten are too short (/about at 16, /resources at 20, /privacy at 25) and 19 are too long (/sla at 70, /use-cases/stat-reads-under-30-minutes at 69). Titles are unique and descriptive, which is the harder half — this is length tuning only. Fix: pad short titles with a qualifier and trim long ones so Google does not truncate them in the SERP.
Meta Tags
Three titles contain the brand name twice
/compliance renders "HIPAA & GDPR Compliant Teleradiology | AstraRad · AstraRad", and /terms and /sla do the same. A per-page title already ending in the brand is then getting the global · AstraRad suffix appended on top. Fix: strip the brand from those three page-level titles and let the global suffix supply it.
Meta Tags
Six meta descriptions exceed 160 characters
/about (182), / (176), /pricing and /how-we-work (166), /resources (164), /services (161). Google truncates these mid-sentence in the SERP. All are unique and well written; they just need trimming to about 150. Fix: cut each to 150 characters or fewer.
Meta Tags
Five Article schema blocks are missing the required author property
All five /resources/* long-form pages emit @type: "Article" with headline and datePublished but no author, which Google requires for Article rich results. The JSON is otherwise valid. Fix: add an author node (Organization AstraRad, or the named reviewing radiologist).
Structured Data

Medium

12 checks
No social profiles linked from the site
Zero LinkedIn, X or Facebook links across all 34 pages. For a clinical B2B vendor, an unlinked LinkedIn company page is the most conspicuous gap — buyers check it before they call. Fix: add LinkedIn, X and Facebook links to the footer and mirror them into the MedicalOrganization sameAs array.
Social Presence · 3 checks
No published address or phone number
Neither appears anywhere on the site. For a healthcare vendor this reads as a trust gap, and it blocks any LocalBusiness or MedicalOrganization address enrichment. Fix: publish a business address and phone in the footer, then add address and telephone to the MedicalOrganization schema.
Local Business · 2 checks
No skip-to-content link on any page
All 34 pages lack a skip link, so keyboard and screen-reader users must tab through the full navigation on every page. Semantic landmarks, lang and form labels all pass — this is the only accessibility check failing. Fix: add a visually-hidden <a href="#main">Skip to content</a> as the first focusable element in the shared layout.
Accessibility-SEO
Client logo images have no width/height and are not lazy-loaded
The two homepage client logos (imbro.png 858×216, nyimaging.png 2383×582) carry good descriptive alt text but no explicit dimensions, which risks layout shift, and they sit below the fold without loading="lazy". Both are comfortably under 200 KB. Fix: add explicit width/height and loading="lazy", and downscale nyimaging.png from 2383px to its display size.
Image SEO · 2 checks
Tap targets below 44px on mobile
Measured at 375px: 20 of 35 interactive elements on / and 32 of 57 on /pricing are under 44px in at least one dimension. Viewport, 16px base font and no-horizontal-scroll all pass. Fix: raise minimum hit areas to 48×48 CSS pixels with at least 8px spacing, mostly on footer and inline text links.
Mobile Friendliness
/contact has only 216 words
The single page under the 300-word threshold, and at 3.1% its text-to-code ratio is by far the lowest on the site. It is a form page, so this is expected, but it currently ranks for nothing. Fix: add a short block on what happens after submitting, expected response time and coverage scope.
Content Quality
Text-to-code ratio below 25% on all 34 pages
Mean 15.8%, ranging from 3.1% (/contact) to 22.6% (/resources/in-house-vs-outsourced-radiology). The cause is Angular's inlined critical CSS and hydration state, not thin content — the same pages carry 1,400 words on average. Low severity, and partly a cost of the prerendering that fixed everything else. Fix: trim unused inlined CSS if convenient; do not sacrifice the SSG setup for this metric.
Content Analysis
Inline style attributes present
26 style="…" attributes on / and 3 on each other page. Minor, and mostly Angular-generated. Fix: move to component stylesheets where practical.
Email & Security

Action Plan

Remaining fixes, highest impact first0 of 16 completed
sitewideCreate a GA4 property and add the gtag.js snippet to index.html head so it prerenders onto all 34 pagesMonitoring
Search ConsoleSubmit https://astrarad.com/sitemap.xml in the already-verified Search Console propertyMonitoring
shared layoutFix the h2 to h4 skip in the shared content-block component — corrects heading nesting on all 34 pagesHeadings
SeoServiceEmit og:image:width and og:image:height alongside og:image in the shared meta blockOpen Graph
brand assetsProduce a 1200x630 OG share card and repoint og:image away from the 1857x576 logoOpen Graph
compliance, sla, termsRemove the brand name from these 3 page titles — the global "· AstraRad" suffix already appends itMeta Tags
19 routesTrim titles over 60 chars (sla 70, use-cases/stat-reads-under-30-minutes 69, nighthawk-radiology 69) to 50-60Meta Tags
10 routesExtend titles under 50 chars (about 16, resources 20, how-we-work 22, privacy 25) toward 50-60Meta Tags
6 routesTrim descriptions over 160 chars to ~150: about 182, / 176, pricing 166, how-we-work 166, resources 164, services 161Meta Tags
resources/* (5)Add the required author property to all 5 Article JSON-LD blocksStructured Data
footerAdd LinkedIn, X and Facebook links to the footer and mirror them into MedicalOrganization sameAsSocial Presence
footer + schemaPublish a business address and phone number, then add address and telephone to MedicalOrganizationLocal Business
shared layoutAdd a visually-hidden skip-to-content link as the first focusable elementAccessibility
/ (client logos)Add explicit width/height and loading="lazy" to both client logos; downscale nyimaging.png from 2383pxImage SEO
footer + inline linksRaise tap targets to 48x48 CSS px with 8px spacing (20/35 on /, 32/57 on /pricing are undersized)Mobile
/contactExpand from 216 words — add what happens after submitting, response time, and coverage scopeContent Quality

Your Next Steps

These two items need a credential from you and cannot be completed from the codebase alone. They are also the highest-leverage items left, because without them none of the other work can be measured.

Google Analytics 4 — get your Measurement ID

34 new pages just went live with no instrumentation. Until this exists, nobody can tell which of them work.

  1. Go to analytics.google.com and sign in
  2. Click Admin (gear icon, bottom-left)
  3. Click CreateProperty
  4. Enter "AstraRad" and https://astrarad.com
  5. Set time zone and currency, click Next, choose a business category, click Create
  6. Under Data collection, click Web
  7. Enter the site URL and stream name, click Create stream
  8. Copy the Measurement ID (starts with G-)
Paste back: the G-… ID, and it will be added to index.html so it prerenders onto every page.

Search Console — submit the sitemap

The property is already DNS-verified. At baseline there was no sitemap to submit; now there is a valid one with 34 URLs, and submitting it is what actually triggers crawling.

  1. Go to search.google.com/search-console
  2. Select the verified astrarad.com property
  3. Open Sitemaps in the left sidebar
  4. Enter sitemap.xml and click Submit
  5. Then open URL Inspection, paste https://astrarad.com/ and click Request indexing
Nothing to paste back — this one is done entirely in the Search Console UI. Check the Coverage report about a week later to confirm the 34 URLs are indexed.