Open Graph Images Generator
Generate social sharing thumbnails for your websites, with plain HTML + CSS templates.
Extract metadata from pages, on-the-fly (middleware) or from distributables (static folder).
No headless browser involved = fast cold boot, much less MBs.
Exposes all underlying APIs for full output customization.
Usable as a CLI, an API or via plugins for Astro, Express, Rollup, Vite and Web Dev Server.
Moreover, a handful of helpers + hot module reloading are here to ease poster images authoring.
Under the hood, it will transform your HTML / CSS to SVG, while retaining layout and typography calculations, then it's converted to PNG.
You can use gradients, borders, flexboxes, inline SVGs, and more…
Additional ressources
Installation
npm i og-images-generator
Create a og-images.config.js
in your current workspace root.
See this og-images.example-config.js for a full working example. It's the config used in every demo.
The gist is:
import { html, styled, OG_SIZE, FONTS } from 'og-images-generator';
const style1 = styled.div`
display: flex;
`;
export const paths = {
base: './dist',
out: './dist/og',
json: './dist/og/index.json',
};
export const template = ({ page }) =>
html`
<div style=${style1}>
${page.meta?.tags['og:title']} - ${page.meta?.tags['og:description']}
</div>`;
export const renderOptions = {
satori: { fonts: [await FONTS.sourceSans()], ...OG_SIZE },
};
At the minimum, you need to export renderOptions
(with size and font) and template
from your og-images-generator
configuration file.
paths
is optional.
[!NOTE]
Helpers
styled.div
is a dummy strings concatenation literal (bringing syntax highlighting and formatting).
div
is the only needed (and available) tag, as it makes no difference anyway for this sugar.
Also, you don't need to wrap interpolated HTML attributes with quotes (e.g. style="${foo}"
).
<foo-bar style=${styles.baz}></foo-bar>
just works.
You can also just clone this repo. and play with the demos for your favorite environments.
E.g.
git clone https://github.com/JulianCataldo/og-images-generator
cd og-images-generator
pnpm i -r
cd demos/<…>
Usage
As a preamble, don't forget to add the appropriate meta for your OGs, there is plenty
on ressources on the web on how to setup your SEO with your favorite environment.
That way, og-images-generator
will crawl them back to your template.
It will parse all the meta tags (in head) and JSON LDs script tags content (in head and body).
By default:
https://example.com/
gives https://example.com/og/index.png
https://example.com/my-page/
gives https://example.com/og/my-page.png
[!WARNING]
/
→ index.png
is an exception.
We don't want https://example.com/og.png
, as to keep this library output well segregated from the rest of your dist
folder.
That's why so we need to disambiguate the root path.
For https://example.com
:
<meta property="og:image" content="https://example.com/og/index.png" />
<meta property="og:image" content="https://example.com/og/nested/my-page.png" />
It's a contrived example. Fine-tuning SEO tags is an dark, ancient art.
You'll need the twitter:
stuff and other massaging, so you're sure it looks great everywhere.
But that's really out of the scope of this library, which does not mess with your HTML in the first place.
Alongside meta tag, JSON LD blocks are also extracted and made available for your template to consume.
What if I need to attribute different templates depending on the page route?
To achieve per URL template variations, add your branching logic in the root template.
You can split and import full or partial templates accordingly if it grows too much, or to organize styles separately.
Also, page.url
is provided, alongside metadata (which should hold those info too, like og:url
).
[!TIP]
Recommended VS Code extensions
- Styled Components for inline CSS highlighting:
styled-components.vscode-styled-components
- HTML highlighting:
bierner.lit-html
Please note that the HTML to SVG engine under the hood (Satori) has some limitations you have to be aware of.
It's kind of trial and error, but overall, you can achieve incomparable results from pure SVGs, especially for things like typography and fluid layouts.
Hopefully the example configuration will guide you towards some neat patterns I'm discovering empirically and collected here.
[!TIP]
Vite and Astro are supporting automatic regeneration of your template while your edit it, thanks to HMR.
It will even refresh your browser for you while your are visualizing your image inside an HTML document.
CLI
npx generate-og
npx generate-og --base dist --out dist/og --json dist/og/index.json
Programmatic (JS API)
Use this API if you want to build your custom workflow, or create a plugin for an unsupported dev/build tools or JS runtimes (e.g. "serverless" functions, Astro's server endpoints…).
import * as api from 'og-images-generator/api';
await api.generateOgImages();
await api.renderOgImage();
See also the tests folder for more minimal insights.
Express / Connect middleware
my-app.js
:
import express from 'express';
import { connectOgImagesGenerator } from 'og-images-generator/connect';
const app = express();
app.use(await connectOgImagesGenerator());
app.get('/', (_, res) => {
res.send(`
<html>
<head>
<meta property="og:title" content="Express / Connect demo" />
<meta property="og:description" content="Welcome to my website!" />
</head>
<body>
<img src="/og/index.png"/>
</body>
</html>
`);
});
app.listen(1234);
Web Dev Server
npm i express-to-koa
npm i -D @types/express-to-koa
web-dev-server.config.js
:
import expressToKoa from 'express-to-koa';
import { connectOgImagesGenerator } from 'og-images-generator/connect';
export default {
middleware: [expressToKoa(await connectOgImagesGenerator())],
};
Rollup plugin
rollup.config.js
:
import { rollupOgImagesGenerator } from 'og-images-generator/rollup';
export default {
plugins: [
rollupOgImagesGenerator(),
],
};
Vite plugin
vite.config.js
:
import { defineConfig } from 'vite';
import { viteOgImagesGenerator } from 'og-images-generator/vite';
export default defineConfig({
plugins: [
viteOgImagesGenerator(),
],
build: {
rollupOptions: {
input: {
foo: 'pages/foo.html',
bar: 'pages/bar.html',
},
},
},
});
Astro integration
astro.config.js
:
import { defineConfig } from 'astro/config';
import { astroOgImagesGenerator } from 'og-images-generator/astro';
export default defineConfig({
integrations: [
astroOgImagesGenerator(),
],
});
[!TIP]
You can leverage Astro's server endpoints capabilities, paired with the og-images-generator
JS API and Content Collections (or any data source).
See demos/astro/src/pages/og-endpoint-demo.ts.
Notes on image optimization
If you're running this on a server, you should use a CDN or any kind of proxying + caching, to handle on the fly image optimizations, with the rest of your assets.
Also AFAIK, all major social networks crawlers are transforming and caching assets themselves.
It's their job to normalize optimizations in order to serve images to their users efficiently.
References
Other projects 👀…
Find this project useful?
🔗 JulianCataldo.com