Generate Open Graph images for your Astro site.
npm install astro-opengraph-images

Generate Open Graph images for your Astro site.
This project is actively maintained. If you have a feature request or need help, please create an issue.
Open Graph is a protocol created by Facebook. It allows pages on your site to be richly embedded into other sites and applications.
You've probably seen this in action when posting a link on Facebook, Twitter, Slack, iMessage, or Discord. Links posted in supported applications will display the Open Graph metadata which often includes an image. This library will generate those images for you.
> [!WARNING]
> This integration has only been tested with statically rendered sites. It is untested with server-side rendering.
- Written in TypeScript
- Generate Open Graph images for every page on your site.
- Use a preset renderer to get started quickly.
- Images are fully customizable using Satori.
- Use React/JSX + Tailwind syntax or vanilla JavaScript to define your own custom images.
- Supports both static pages and Astro content collections.
- Pages can be written in Markdown, MDX, HTML, or any other format.
To better illustrate these steps, I've created a video following them to help others follow along.
1. Add this integration to your Astro config:
- Option 1: use the astro command:
``bash`
npx astro add astro-opengraph-images
- Option 2: install the package and add the integration to your Astro config:
`bash`
npm i astro-opengraph-images
`diff
+import opengraphImages from "astro-opengraph-images";
export default defineConfig({
integrations: [
+ opengraphImages()
],
});
`
1. Install React. React is used by the presets, and can be used to easily author custom images. Note that React is only used for generating the images and will not be shipped to clients.
`bash`
npm i -D react
1. Install the fonts you want to use. Fonts must be explicitly declared to be used for images. System fonts are _not_ available. For this quick start guide, we'll install the Roboto font:
`bash`
npm i @fontsource/roboto
You can find more fonts on Fontsource, or you can use any font file that you have. See Satori's font documentation for more information.
1. Configure the integration in your Astro config:
`diff
-import opengraphImages from "astro-opengraph-images";
+import opengraphImages, { presets } from "astro-opengraph-images";
+import * as fs from "fs"; // The fs module is required to load fonts
export default defineConfig({
integrations: [
- opengraphImages()
+ opengraphImages({
+ options: {
+ fonts: [
+ {
+ name: "Roboto",
+ weight: 400,
+ style: "normal",
+ data: fs.readFileSync("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff"),
+ },
+ ],
+ },
+ render: presets.blackAndWhite,
+ }),
],
});
`
1. Set the site property in your Astro config:
Open Graph requires URLs to be absolute, including the domain your site is hosted at. This integration uses the site defined in your Astro config to create the correct URLs for Open Graph which is site must be defined.
`diff`
export default defineConfig({
+ site: "https://
integrations: [
opengraphImages({
options: {
fonts: [
{
name: "Roboto",
weight: 400,
style: "normal",
data: fs.readFileSync("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff"),
},
],
},
render: presets.blackAndWhite,
}),
],
});
1. Update your main Astro layout with the appropriate meta tags. The Open Graph site has more information possible tags.
The following meta tags must be defined:
- og:titleog:type
- This field may be used when generating images.
- og:image
- See the Open Graph documentation for valid values.
- getImagePath
- Set this to the return value of (example shown below).og:image
- If the value of does not match what this integration expects then your site will fail to build. This will ensure your site is correctly configured to display Open Graph images.og:description
-
- Optional. This field may be used when generating images.
Your site will fail to build if the tags above are not set.
- Option 1: Use the astro-seo package:
Install the astro-seo package:
`bash`
npm i astro-seo
Update your Astro layout to use the SEO component:
`diff
---
+import { SEO } from "astro-seo";
+import { getImagePath } from "astro-opengraph-images";
interface Props {
title: string;
}
const { title } = Astro.props;
+const { url, site } = Astro;
+const openGraphImageUrl = getImagePath({ url, site });
---
+
+ {
+ basic: {
+ title: title,
+ type: "website",
+ image: openGraphImageUrl,
+ url: url,
+ },
+ optional: {
+ description: "My page description",
+ },
+ }
+ }
+ />
- Option 2: Manually add the
meta tags to your Astro layout.1. Build your site. You should see a
.png file next to each .html page in your dist folder. Double-check that the og:image proprety in your .html file matches the path to the .png file.1. Deploy your site. You can verify that your images are correct by:
- Sending a link to your site in an application that supports Open Graph like iMessage, Slack, Discord, etc.
- Visit opengraph.xyz and test your site.
Examples
examples/.$3
If you're using this project, open a PR to add your site to this list.
Custom Renderers
You can create your own custom images with a render function. Take a look at how a preset works.
Renderers have access to the page's DOM using jsdom. You can use this to render your Open Graph image using any of the content from the associated HTML page. An example of this is shown in the custom property preset which shows a preview of the page's body text in the Open Graph image.
This library uses Satori to convert React components to SVG. The SVG is then converted to a PNG using resvg-js.
> [!TIP]
> Satori supports a subset of CSS. Be sure to familiarize yourself with its limitations.
>
> You can use the Satori playground to work on your images.
>
> You can use Tailwind syntax with tw-to-css. An example is the Tailwind preset. You'll need to install this package yourself.
$3
You may receive an error when setting the source attribute on an
img tag, claiming you need an absolute URL. When using a custom renderer, you can load local images to use in your final image using the following syntax in your .tsx file:`javascript
const filePath = path.join(process.cwd(), "src", "assets", "my-image.png");
const imageBase64 = data:image/png;base64,${fs.readFileSync(filePath).toString("base64")};
`The code above will load the image at
src/assets/my-image.png and convert it to a base64 string which can be passed to an image tag's src attribute. Be sure to update the data:image/png;base64, part of the string to match the image's type and that the image's file ath is correct.`jsx
style={{
...twj("absolute inset-0 w-full h-full"),
...{ objectFit: "cover" },
}}
src={imageBase64}
/>
`Here's a complete example of a custom renderer with a locally loaded image:
`tsx
import type { RenderFunctionInput } from "astro-opengraph-images";
const { twj } = await import("tw-to-css");// Remember to import these modules
import path from "path";
import * as fs from "node:fs";
const filePath = path.join(
process.cwd(),
"src",
"assets",
"my-image.png",
);
const imageBase64 =
data:image/png;base64,${fs.readFileSync(filePath).toString("base64")};// from https://fullstackheroes.com/resources/vercel-og-templates/simple/
export async function simpleBlog({ title, description }: RenderFunctionInput): Promise {
return Promise.resolve(
style={{
...twj("absolute inset-0 w-full h-full"),
...{ objectFit: "cover" },
}}
src={imageBase64}
/>
{title}
{description}
,
);
}
`Emoji Support
By default, emojis in your page titles or descriptions will not render correctly because system fonts are disabled and standard fonts don't include emoji glyphs.
To enable emoji support, use the
loadAdditionalAsset option to fetch emoji images from a CDN like Twemoji:`typescript
import opengraphImages, { presets } from "astro-opengraph-images";
import * as fs from "fs";export default defineConfig({
site: "https://example.com",
integrations: [
opengraphImages({
options: {
fonts: [
{
name: "Roboto",
weight: 400,
style: "normal",
data: fs.readFileSync("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff"),
},
],
loadAdditionalAsset: async (languageCode, segment) => {
if (languageCode === "emoji") {
// Fetch emoji SVG from Twemoji CDN
return
https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/svg/${segment.codePointAt(0)?.toString(16)}.svg;
}
// Return empty array for other assets (e.g., fallback fonts)
return [];
},
},
render: presets.blackAndWhite,
}),
],
});
`The
loadAdditionalAsset callback is called by Satori whenever it encounters a character that isn't covered by the provided fonts. For emojis, returning an SVG URL will render the emoji correctly in your Open Graph images.Presets
src/presets/. Open a pull request to contribute a preset you've created.tw-to-css library. You'll need to install this dependency separately when using one of these presets. You'll see an error if the library is not already installed.`bash
npm i tw-to-css
`$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.backgroundImage,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.blackAndWhite,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.brandedLogo,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.customProperty,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.gradients,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.podcast,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.rauchg,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.simpleBlog,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.tailwind,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.vercel,
}),
],
});
`
$3
`diff
import opengraphImages, { presets } from "astro-opengraph-images";export default defineConfig({
integrations: [
opengraphImages({
+ render: presets.waveSvg,
}),
],
});
``
Here are some similar libraries using Satori and Astro. I haven't done a feature comparison.
- https://github.com/florian-lefebvre/satori-astro (This library looks excellent)
- https://github.com/delucis/astro-og-canvas (Doesn't allow arbitrary layouts)
- https://github.com/thewebforge/astro-og-images (Only allows you to choose from a list of templates)
- https://github.com/tomaskebrle/astro-og-image (Seems limited)
- https://github.com/cijiugechu/astro-satori (Possibly dead, hasn't been updated in a year)
- https://github.com/kevinzunigacuellar/astro-satori (Possibly dead, hasn't been updated in a year)
- https://github.com/rumaan/astro-vercel-og (Possibly dead, hasn't been updated in a year)