Skip to content

SEO & OG image

Every theme uses a shared Layout.astro that reads SEO defaults from siteConfig.seo and lets each page override them via props.

src/config/site.ts
seo: {
title: "Aurora — The modern platform for ambitious teams",
description: "Aurora helps teams ship faster, stay organized, and deliver results without the complexity.",
ogImage: "/og.png",
twitterHandle: "@yourhandle",
}
FieldWhere it lands
titleThe <title> tag and Open Graph / Twitter card title.
description<meta name="description">, OG description, Twitter description.
ogImagePath or URL to the share card. Recommended: 1200×630 PNG.
twitterHandleSets twitter:site and twitter:creator if present.

The canonical URL is built from siteConfig.url plus the current pathname, so set that too:

url: "https://yourdomain.com", // no trailing slash

Inside any page, pass props to the layout:

src/pages/pricing.astro
---
import Layout from "~/layouts/Layout.astro";
---
<Layout
title="Pricing — Aurora"
description="Three plans, no surprises. Start free, scale when you're ready."
ogImage="/og/pricing.png"
>
{/* …page content… */}
</Layout>

Only the props you pass override the defaults — everything else falls back to siteConfig.seo.

The image at siteConfig.seo.ogImage is what shows up when someone shares your URL on Slack, Twitter, LinkedIn, iMessage, etc.

Every theme ships a generic /public/og.png at 1200×630. Replace it with your own keeping the same path and dimensions, and you’re done.

Drop a PNG into public/og/ and reference it from the page:

<Layout
title="The 2026 State of Astro Themes"
ogImage="/og/state-of-astro.png"
>

If you want every blog post to have its own OG card automatically, look at the script in scripts/generate-og.mjs on the marketing repo for reference. Drop a similar script into your theme, wire og to package.json, and call it as part of your build:

package.json
"scripts": {
"og": "node scripts/generate-og.mjs",
"build": "npm run og && astro build"
}

Layout.astro sets a sensible default:

<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">

For pages you don’t want indexed (a checkout success page, a private demo), pass noindex to the layout:

<Layout title="Thanks!" noindex>

That swaps the meta tag to noindex, nofollow.

@astrojs/sitemap is already configured in every theme. After npm run build, you’ll find dist/sitemap-index.xml and dist/sitemap-0.xml. Submit https://yourdomain.com/sitemap-index.xml to Google Search Console.

To exclude a route, edit astro.config.mjs:

astro.config.mjs
sitemap({
filter: (page) =>
!page.includes('/preview/') &&
!page.includes('/admin/'),
}),