Add Dynamic Social Share Images to Any Site in Five Minutes (Next.js, Hugo, Jekyll, WordPress)
Here's the trick that makes dynamic social share images almost embarrassingly easy: og:image is just a URL. The platforms fetching your link preview don't care whether that URL points to a static file or an API that renders the image on request. So if you have an endpoint that turns query parameters into a finished PNG, every page on your site can have its own designed share card with zero build steps — no Figma, no plugin, no image pipeline.
Zooky is that endpoint. This post is the copy-paste recipe for wiring it into whatever you're running: plain HTML, Next.js, Hugo, Jekyll, or WordPress.
The URL anatomy
https://zooky.net/api/og
?title=Ship%20Faster%20With%20Preview%20Deploys
&subtitle=engineering.acme.com
&badge=Engineering
&theme=midnight
Paste that (on one line) into your browser and you get a rendered 1200 × 630 PNG back. The parameters:
title— the big text. The only required parameter.subtitle— smaller supporting line; a domain or author name works well.badge— a small label, great for category or section names.theme— one of seven designer themes:aurora,midnight,sunset,mint,ocean, and more, with accent-color customization.- Size variants: Open Graph 1200 × 630 (default), square 1080 × 1080, and wide 1600 × 840.
The free tier needs no signup — 50 images an hour with a small zooky.net watermark. Pro ($12/month) gets you an API key, watermark=0, 10,000 images a month, and priority rendering.
Now the recipes. Every one of them does the same two things: build the URL with the page's own title, and declare twitter:card so X shows the full-size image.
Plain HTML
<meta property="og:image" content="https://zooky.net/api/og?title=My%20Post%20Title&theme=aurora" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
Hand-encode the title (spaces become %20) and you're done. For a static site with a handful of pages, this is genuinely the whole integration.
Next.js (App Router)
In your route's generateMetadata:
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
const og =
`https://zooky.net/api/og` +
`?title=${encodeURIComponent(post.title)}` +
`&subtitle=${encodeURIComponent("blog.acme.com")}` +
`&theme=midnight`;
return {
title: post.title,
openGraph: { images: [{ url: og, width: 1200, height: 630 }] },
twitter: { card: "summary_large_image" },
};
}
Every post now ships a unique card derived from its own title — no image generation in your build, no extra dependencies.
Hugo
In layouts/partials/head.html (or your theme's equivalent):
<meta property="og:image" content="https://zooky.net/api/og?title={{ .Title | urlquery }}&badge={{ .Section | urlquery }}&theme=sunset" />
<meta name="twitter:card" content="summary_large_image" />
Hugo's urlquery filter handles the encoding, and using .Section as the badge gives you free category labels ("blog", "docs", "changelog") on every card.
Jekyll
In _includes/head.html:
<meta property="og:image" content="https://zooky.net/api/og?title={{ page.title | url_encode }}&theme=mint" />
<meta name="twitter:card" content="summary_large_image" />
WordPress
Drop this in your theme's functions.php (or a small custom plugin):
add_action('wp_head', function () {
if (!is_single()) return;
$og = 'https://zooky.net/api/og?title=' . rawurlencode(get_the_title()) . '&theme=ocean';
echo '<meta property="og:image" content="' . esc_url($og) . '" />' . "\n";
echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
});
If you run an SEO plugin that already emits og:image, set its image field to the Zooky URL instead, so you don't ship duplicate tags.
Gotchas worth knowing
- Always URL-encode the title. Ampersands, question marks, and em dashes in a raw title will break the query string. Every snippet above encodes; don't skip it when adapting them.
- Keep titles under ~80 characters. Long text wraps and shrinks, and a share card full of 20px type defeats the purpose. Truncate in your template if your titles run long.
- Test in a private Slack or Discord channel. Both fetch previews for new URLs instantly and are strict about what they accept — a thirty-second sanity check before you publish.
- Caches are your friend until they aren't. Platforms cache scraped previews aggressively. If you change themes later, bust the cache by adding
&v=2to the URL.
Five minutes, counted honestly
One minute picking a theme in your browser's address bar. Two minutes pasting the snippet for your stack. One minute making sure the title is encoded. One minute pasting a link into Slack to see the finished card. No signup, no credit card, no deploy of anything new.
If your site outgrows 50 images an hour, or you want the watermark gone, Pro is $12/month. Until then, the free tier is the integration — every link you share from now on arrives looking designed.
Copy-paste recipes for per-page og:image URLs in Next.js, Hugo, Jekyll, WordPress, and plain HTML — no image editor, no build step, no headless browser.
Try Zooky — OG Image API free