Published 2026-10-22 · Data collected 2026-10-20 and 2026-10-21
We checked 3,197 Astro sites for SEO basics
We looked for a sitemap on every site in the Astro showcase, then audited 3,927 pages on the 358 sites with 500 or more URLs in their sitemap. Most of them are in good shape: 72% had none of the serious problems on any page we sampled. The rest tend to miss the same few things, and each one is a small fix in Astro.
1. A third still ship FAQ markup Google stopped showing
116 of the 358 large sites (32%) have FAQPage or HowTo structured data on at least one sampled page: FAQPage on 114, HowTo on 7. That is 611 of 3,927 pages (16%), and 48 of the 356 showcase entry pages.
Google limited FAQ rich results to government and health sites in 2023, removed HowTo results the same year, and stopped showing FAQ results entirely on 7 May 2026. The markup does no harm: there's no penalty, and other search engines may still read it. It just no longer earns anything in Google, so it's not worth adding to new pages or maintaining by hand.
2. One in five has pages that share as a bare link
74 of 358 sites (21%) have at least one sampled page without an og:image, and 33 (9%) have none on any page we sampled. Across all pages it's 520 of 3,927 (13%). Without one, LinkedIn, Facebook and Slack show a card without a picture, or just the URL. 159 pages had no Open Graph tags at all.
The homepage usually isn't the problem: 14% of showcase entry pages lacked an og:image. It's the blog post or docs page someone actually shares, rendered by a layout that only sets the image when a page passes one.
3. Duplicate titles and descriptions
We sampled about 11 pages per site. On 69 of the 353 sites with two or more audited pages (20%), at least two of those pages had exactly the same title or meta description: 64 sites repeated a description, 38 a title. With only 11 pages sampled per site, the real number is higher. 38 sites (11%) also had pages with no meta description at all (198 pages, 5%).
The usual cause is a layout with a default description that every page inherits.
4. Sitemaps: missing, or hidden behind a broken robots.txt line
Of the 2,831 showcase sites that responded, 554 (20%) had no sitemap at the URL in their robots.txt, at /sitemap-index.xml or at /sitemap.xml. For a five-page portfolio that hardly matters; for a site with hundreds of pages it does.
The odder group: 81 sites have a Sitemap: line in robots.txt that leads nowhere, and 57 of them have a working sitemap at the default path all along. The line points at a relative path (Google needs the full URL), at a placeholder domain like example.com left over from a template, or at an old host.
| Sitemap URLs at sizing | Sites (of 3,197) |
|---|---|
| No sitemap found (incl. 366 sites that didn't load) | 978 (31%) |
| Empty sitemap (0 URLs) | 18 (1%) |
| 1–49 | 995 (31%) |
| 50–499 | 840 (26%) |
| 500–4,999 | 280 (9%) |
| 5,000 or more | 86 (3%) |
5. Noindex pages listed in the sitemap
20 of the 358 sites (6%) list pages in their sitemap that carry noindex: 57 pages in all. They're mostly pages people noindex on purpose, such as tag archives, pagination, embedded demos and translated variants. Noindexing them is fine. Listing them in the sitemap sends the opposite signal: a sitemap is meant to list the pages you want in search. @astrojs/sitemap includes every page unless you filter some out.
Everything we measured
| Check | Pages (of 3,927) | Sites with at least one (of 358) |
|---|---|---|
| FAQPage or HowTo JSON-LD | 611 (16%) | 116 (32%) |
| No og:image | 520 (13%) | 74 (21%) |
| No meta description | 198 (5%) | 38 (11%) |
| No canonical URL | 245 (6%) | 36 (10%) |
| No H1 | 248 (6%) | 63 (18%) |
| noindex (while listed in the sitemap) | 57 (1%) | 20 (6%) |
| No JSON-LD at all | 1,003 (26%) | |
| No twitter:card | 485 (12%) | |
| Images without alt | 214 (5%) | |
| Title outside 30–60 characters | 1,756 (45%) | |
| Description outside 70–155 characters | 1,661 (42%) | |
No <title> | 40 (1%) | |
No lang on <html> | 49 (1%) |
The average page scored 87 out of 100 on our free checker's ten checks, mostly losing points on title and description length. 257 of the 358 sites (72%) had no missing og:image, missing description or noindex page anywhere in the sample.
How to fix it in Astro
A default og:image and a description every page must set
Put the tags in one layout, give the image a fallback, and make description a required prop so astro check flags any page that forgets it. Set site in astro.config.mjs so the URLs come out absolute: Open Graph needs absolute URLs.
---
// src/layouts/BaseLayout.astro
interface Props {
title: string;
description: string;
image?: string;
}
const { title, description, image = '/og-default.png' } = Astro.props;
const canonical = new URL(Astro.url.pathname, Astro.site);
const ogImage = new URL(image, Astro.site);
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta name="twitter:card" content="summary_large_image" />
</head>
<body>
<slot />
</body>
</html>
Put a 1200×630 image at public/og-default.png. Pages pass their own with <BaseLayout title="…" description="…" image="/og/post.png">. For content collections, make description required in the collection's schema too, so a post without one fails the build instead of inheriting a default.
A sitemap that robots.txt points to correctly
npx astro add sitemap
// astro.config.mjs
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [
sitemap({
// Leave out pages you mark noindex, such as tag archives.
filter: (page) => !page.includes('/tags/'),
}),
],
});
The build writes sitemap-index.xml and sitemap-0.xml. Generate robots.txt from the same site value instead of hard-coding a URL, so it can't drift to a relative path or a template's placeholder domain:
// src/pages/robots.txt.ts
import type { APIRoute } from 'astro';
const getRobotsTxt = (sitemapURL: URL) => `User-agent: *
Allow: /
Sitemap: ${sitemapURL.href}
`;
export const GET: APIRoute = ({ site }) => {
const sitemapURL = new URL('sitemap-index.xml', site);
return new Response(getRobotsTxt(sitemapURL));
};
Delete public/robots.txt if you have one, so there is only one source. This follows the @astrojs/sitemap guide.
FAQ markup
Nothing breaks if you leave it. If you maintain it by hand, it's safe to stop adding it to new pages.
If you'd rather not write descriptions and Open Graph tags for every page yourself, Headlark can write them after astro build. To see where your own site stands, run any page through the free SEO checker.
How we did it
- Who: all 3,197 sites in the Astro showcase. Sites are submitted by their makers, so this is a self-selected group that skews toward developers, docs and portfolios, not a random sample of Astro sites.
- Sitemaps: we read the
Sitemap:lines in each site's robots.txt or, if there were none, tried/sitemap-index.xmland/sitemap.xml, and counted the URLs. "No sitemap" means none at those places. We re-checked every site without one: 366 didn't load at all (down, blocked or timed out) and are left out of the percentages. - Audit: for the 358 sites with 500 or more sitemap URLs (excluding 7 sites on shared platform subdomains and 1 that blocked us), the showcase page plus 11 pages spread evenly across the sitemap: 3,927 pages, about 11 per site. Each page went through the same ten checks as our free checker, on the HTML the server sends, without running JavaScript.
- When: 20–21 October 2026, a single point in time.
- We re-checked every page flagged for a missing og:image, a missing description or noindex with a second, independent parser, and all of them held.
- No site is named here. The numbers are aggregates only.