How to Add OG Images to Astro — Step-by-Step Guide
Add dynamic Open Graph images to your Astro site in minutes. Covers content collections, Layout components, head injection, and API-based OG image generation.
Quick Answer
To add OG images in Astro, place a <meta property="og:image"> tag inside the <head> of your Layout component and pass the image URL as a prop from each page. The fastest approach is using an API like ogimg.xyz to generate images dynamically from your page title and description.
How OG Images Work in Astro
Astro renders pages to static HTML at build time by default, which means your Open Graph meta tags are present in the initial HTML response — exactly what social media crawlers need. Unlike client-side React frameworks, Astro gives you zero-JavaScript OG image support out of the box.
The standard approach is to add og:image meta tags in your Layout component's <head> section and pass the image URL as a prop from each page or content collection entry.
Adding OG Images via a Layout Component
Create a reusable Layout component that accepts an ogImage prop:
---
// src/layouts/BaseLayout.astro
interface Props {
title: string;
description: string;
ogImage?: string;
}
const { title, description, ogImage } = Astro.props;
const defaultOgImage = `https://ogimg.xyz/api/og?${new URLSearchParams({
title,
description,
template: "gradient",
}).toString()}`;
const image = ogImage || defaultOgImage;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<meta name="description" content={description} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<!-- 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={image} />
</head>
<body>
<slot />
</body>
</html>
Now every page that uses BaseLayout automatically gets Open Graph tags. If no custom ogImage prop is provided, the layout falls back to generating one via the ogimg.xyz API.
Dynamic OG Images with Content Collections
Astro's Content Collections (introduced in Astro 2.0) let you define typed content schemas. Here's how to add OG images to collection-based blog posts:
---
// src/content/config.ts
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
ogImage: z.string().optional(),
date: z.date(),
}),
});
export const collections = { blog };
---
---
// src/pages/blog/[...slug].astro
import { getCollection } 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.ogImage ||
`https://ogimg.xyz/api/og?${new URLSearchParams({
title: post.data.title,
description: post.data.description,
template: "blog",
pattern: "dots",
}).toString()}`;
---
<BaseLayout title={post.data.title} description={post.data.description} ogImage={ogImage}>
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
</BaseLayout>
Each blog post now gets a unique, automatically generated OG image based on its title and description. Authors can optionally override with a custom ogImage in their frontmatter.
Using an API Key for Production
For sites with more than 50 pages, add your ogimg.xyz API key to unlock higher limits:
// .env
OGIMG_API_KEY=your_api_key_here
---
// In your Layout or page component
const ogImage = `https://ogimg.xyz/api/og?${new URLSearchParams({
title,
description,
template: "gradient",
key: import.meta.env.OGIMG_API_KEY,
}).toString()}`;
---
Astro uses import.meta.env for environment variables. Variables prefixed with PUBLIC_ are available client-side; without the prefix, they're server/build-time only — perfect for API keys.
After deploying, verify your OG images work by testing with the Facebook Sharing Debugger and the Twitter Card Validator.
Frequently Asked Questions
Does this work with Astro SSR mode?
Yes. Whether you use Astro in static (SSG) or server-side rendering (SSR) mode, the og:image meta tags are rendered into the HTML response. Both modes work perfectly with social media crawlers.
Can I use @vercel/og with Astro?
You can, but it requires setting up an API endpoint in Astro and writing JSX templates with Satori's limited CSS support. Using an API like ogimg.xyz is simpler — just set the og:image URL to an API endpoint with your page data as query parameters.
Do I need different OG images for each Astro page?
It's best practice to have a unique OG image per page so each link preview looks distinct on social media. With an API-based approach, each page automatically gets a unique image from its title — no manual design needed.
Related Guides
Compare with Alternatives
See how OG Image Generator stacks up against other tools.
Start Generating OG Images
Free API for developers. 50 images/month, 10 templates, no credit card required.