Astro Open Graph Meta Tags: Complete Setup Guide

How to add og:title, og:image, og:description, and Twitter card tags to Astro sites — covering static pages, content collections, and dynamic OG image generation.

Why Astro is great for OG tags

Astro renders to static HTML by default, which means your Open Graph meta tags are present in the raw HTML response — exactly what social crawlers need. There's no client-side hydration required for OG tags to work; they just work.

This makes Astro one of the easiest frameworks for getting correct social previews out-of-the-box.

Basic OG tags in an Astro layout

Create a base layout that accepts OG props and renders them in <head>:

---
// src/layouts/BaseLayout.astro
interface Props {
  title: string;
  description: string;
  ogImage?: string;
  ogUrl?: string;
  ogType?: string;
}

const {
  title,
  description,
  ogImage = 'https://example.com/og/default.jpg',
  ogUrl = Astro.url.href,
  ogType = 'website',
} = Astro.props;
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>{title}</title>
    <meta name="description" content={description} />

    <!-- Open Graph -->
    <meta property="og:title" content={title} />
    <meta property="og:description" content={description} />
    <meta property="og:image" content={ogImage} />
    <meta property="og:url" content={ogUrl} />
    <meta property="og:type" content={ogType} />

    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:title" content={title} />
    <meta name="twitter:description" content={description} />
    <meta name="twitter:image" content={ogImage} />
  </head>
  <body>
    <slot />
  </body>
</html>

Using OG tags in pages

---
// src/pages/index.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---

<BaseLayout
  title="My App — Fast OG Tag Checker"
  description="Preview how your links look on Twitter, LinkedIn, and Discord."
  ogImage="https://example.com/og/home.jpg"
  ogUrl="https://example.com"
>
  <main><!-- page content --></main>
</BaseLayout>

Dynamic OG tags for content collections

Astro Content Collections let you define frontmatter schema and use those values to generate OG tags automatically:

---
// src/pages/blog/[slug].astro
import { getCollection, getEntry } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await post.render();
const ogImage = post.data.coverImage ?? 'https://example.com/og/default.jpg';
---

<BaseLayout
  title={post.data.title}
  description={post.data.excerpt}
  ogImage={ogImage}
  ogUrl={`https://example.com/blog/${post.slug}`}
  ogType="article"
>
  <article>
    <h1>{post.data.title}</h1>
    <Content />
  </article>
</BaseLayout>

Generating dynamic OG images

Astro supports API routes, which you can use to generate OG images server-side using Satori or the @vercel/og package:

// src/pages/og/[slug].png.ts
import { getEntry } from 'astro:content';
import satori from 'satori';
import { html } from 'satori-html';
import { Resvg } from '@resvg/resvg-js';

export async function GET({ params }: { params: { slug: string } }) {
  const post = await getEntry('blog', params.slug);
  const svg = await satori(
    html`<div style="display:flex;width:1200px;height:630px;background:#0a0a0a;align-items:center;justify-content:center;">
      <h1 style="color:white;font-size:60px;">${post.data.title}</h1>
    </div>`,
    { width: 1200, height: 630, fonts: [] }
  );
  const resvg = new Resvg(svg);
  return new Response(resvg.render().asPng(), {
    headers: { 'Content-Type': 'image/png' },
  });
}

Common Astro OG tag mistakes

  • Relative og:image URLs: always use absolute HTTPS URLs.
  • SSR mode without static OG: if using output: 'server', make sure OG tags are generated in the server response, not deferred to client JS.
  • Missing og:url: always include the canonical URL.
  • Not verifying after deploy: test with OGFixer after every change.

Verify your Astro OG tags → Paste your URL into OGFixer to preview your link on Twitter, LinkedIn, Discord, and Slack instantly.