Open Graph (OG) Images represent your content on the web when shared. They are those little preview images displayed next to your link on social media, messengers or your journal app.

If you're not keen to create an OG Image manually for each of your pages on your Eleventy site, there are mainly two approaches to generate them:

  1. Create a HTML template, style with CSS and take a screenshot with a headless browser
  2. Create a SVG template, render it to a bitmap

First approach is easy to style but hard to render. Managing a headless browser can be a hassle at times. Second approach might be a bit harder to style, depending on your level of SVG knowledge, but is much more consistent to render.

Combining the best of both worlds let me introduce eleventy-plugin-og-image – it is a shameless plug of my very first open source project. It allows to create OG images from HTML (or any template language supported by Eleventy) and CSS. Instead of a headless browser, satori transforms your HTML to SVG, allowing a simple rendering to bitmap afterward. This is the complete render flow:

Flow of OG image generation

How to setup eleventy-plugin-og-image

First install the package:

bash
npm install eleventy-plugin-og-image --save-dev

Afterward we add the plugin to our .eleventy.js. Note, this example configuration already uses ESM with @11ty/eleventy@3.0.0. You need to load all fonts, which are used in your OG-image-templates:

js
import EleventyPluginOgImage from 'eleventy-plugin-og-image';
/** @param { import('@11ty/eleventy/src/UserConfig').default } eleventyConfig */
export default async function (eleventyConfig) {
eleventyConfig.addPlugin(EleventyPluginOgImage, {
satoriOptions: {
fonts: [
{
name: 'Inter',
data: fs.readFileSync('../path/to/font-file/inter.woff'),
weight: 700,
style: 'normal',
},
],
},
});
}

Now we create an OG-image-template og-image.og.njk. It is easiest to place the CSS in a <style> tag directly in your template:

twig
<style>
.root {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
background: linear-gradient(135deg, #ef629f, #eecda3);
}
.title {
color: white;
font-size: 80px;
margin: auto 0;
}
</style>
<div class="root">
<h1 class="title">{{ title }}</h1>
</div>

The styles will be inlined as style="" attributes by the plugin. You can use remote images, which will be fetched during rendering. This template expects to get a title attribute provided as data.

Last call the ogImage shortcode inside your <head> of a page template or layout. The first argument of the shortcode is the filePath of the OG-image-template (required), second argument is for data (optional). This is how it looks in a example-page.njk:

twig
{% ogImage "./og-image.og.njk", { title: "Hello World!" } %}

This will create a bitmap _site/og-images/s0m3h4sh.png in your output path:

Resulting OG image
Resulting OG image, resolution and file type are configurable

The ogImage shortcode generates the following HTML into the compiled _site/example-page/index.html to actually embed your OG image:

html
<meta property="og:image" content="/og-images/s0m3h4sh.png" />

For more configuration and usage options see the docs. A basic example is also included in the project or find a rather more complex example in the implementation of this blog. I'm happy to hear your feedback in the repository!