Social media preview images (Open Graph / Twitter Cards) can make or break your click-through rates. But most developers either skip them entirely or spend hours in Figma designing static images that go stale.
What if you could generate them automatically from HTML templates?
The Problem
Every time you publish a blog post, launch a feature, or share a link, platforms like Twitter, Slack, Discord, and LinkedIn look for an og:image meta tag. If it's missing or generic, your link looks... forgettable.
Designing a unique image per page doesn't scale. You need automation.
The Solution: HTML → Image
The idea is simple:
- Design your OG image as an HTML template (with CSS!)
- Pass dynamic data (title, author, date) as parameters
- Render it to a PNG via a headless browser
- Serve it from your
og:imagemeta tag
Here's a minimal example using a screenshot API:
curl "https://rendly-api.fly.dev/api/v1/templates/og-basic/render?title=My+Blog+Post&author=Mack" \
-H "Authorization: Bearer YOUR_API_KEY" \
--output og-image.png
That's it. One HTTP call, one image.
Building the HTML Template
Your template is just HTML + CSS. Here's a starter:
<div style="width: 1200px; height: 630px; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); font-family: system-ui; color: white; padding: 60px;">
<div>
<h1 style="font-size: 56px; margin: 0 0 20px 0;">{{title}}</h1>
<p style="font-size: 24px; opacity: 0.8;">by {{author}} · {{date}}</p>
</div>
</div>
The magic: you already know HTML and CSS. No new design tool to learn.
Integrating with Your Blog
Next.js / React
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
openGraph: {
images: [`https://rendly-api.fly.dev/api/v1/templates/og-basic/render?title=${encodeURIComponent(post.title)}&author=${post.author}`],
},
};
}
Rails
<%= tag.meta property: "og:image", content: "https://rendly-api.fly.dev/api/v1/templates/og-basic/render?title=#{ERB::Util.url_encode(@post.title)}&author=#{@post.author}" %>
Static Sites (Hugo, Jekyll, 11ty)
Just set the URL in your frontmatter or template. Most static site generators support dynamic meta tags.
Why Not Just Use Puppeteer Locally?
You can. But:
- Headless Chrome uses ~500MB+ RAM
- Cold starts are slow (2-5 seconds)
- You need to manage browser updates, fonts, and rendering quirks
- It doesn't scale well on serverless (Lambda timeout, memory limits)
A dedicated API handles all of this. You get a URL, you get an image.
Performance Tips
-
Cache aggressively — OG images rarely change. Set
Cache-Control: public, max-age=86400. - Use webhooks — If your API supports async rendering, generate images on publish rather than on-demand.
- Keep templates simple — Fewer DOM nodes = faster rendering.
-
Use system fonts — Custom fonts add latency.
system-uilooks great and loads instantly.
The ROI
Links with custom preview images get 2-3x more clicks on social media. For a blog that publishes weekly, automating this saves hours per month and measurably increases traffic.
Not bad for a single API call.
I'm building Rendly, a screenshot and image generation API designed for exactly this workflow. Free tier available — no credit card required.
Top comments (0)