How to add Open Graph tags in Astro

Astro gives you full control over the <head> — which also means nothing is set up for you. The clean pattern: one base layout that renders all social tags from props, so every page only has to pass a title, description and image.

Want to see how your page looks right now?

The free checker shows your previews for nine platforms — from X and WhatsApp to iMessage, Discord and Bluesky.

Check your URL

Put the tags in your base layout

Create (or extend) src/layouts/Layout.astro and render the og: and twitter: tags in its <head> from props. Every page that uses the layout passes its own values — one source of truth, no copy-paste per page.

Make URLs absolute with Astro.url and the site config

Scrapers ignore relative image URLs. Set "site" in astro.config.mjs and build absolute URLs with new URL(image, Astro.site) — that works in dev, previews and production without hardcoding the domain.

Pass per-page values

In each page: <Layout title="…" description="…" image="/og/blog-post.png">. For Markdown/MDX content collections, map frontmatter fields to the layout props so authors set the preview from the frontmatter.

Verify the built output

Astro renders at build time, so what you ship is what scrapers see. Paste a deployed URL into the MetaPeek checker — or paste the built HTML (dist/…/index.html) into the paste-HTML mode before you deploy.

Code example

---
// src/layouts/Layout.astro
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>
    <title>{title}</title>
    <meta name="description" content={description} />
    <meta property="og:title" content={title} />
    <meta property="og:description" content={description} />
    <meta property="og:type" content="website" />
    <meta property="og:url" content={canonical} />
    <meta property="og:image" content={ogImage} />
    <meta name="twitter:card" content="summary_large_image" />
    <slot name="head" />
  </head>
  <body><slot /></body>
</html>

Common mistakes

Frequently asked questions

Does Astro generate og:image files for me?

Not out of the box. Community integrations (like astro-og-canvas or satori-based generators) can render 1200×630 images at build time; otherwise ship a static image per page or a good default.

Where do the tags go with content collections?

Keep rendering them in the layout. The page pulls title/description/image from the collection entry (entry.data) and passes them down as props.

How do I test before deploying?

Run astro build and paste the generated HTML file into the MetaPeek paste-HTML mode — no tunnel or deploy needed.

Changed your tags? Verify the result.

Paste your URL and see within two seconds whether everything is right — on every platform.

Open the checker

Related guides