DEV Community

Mack
Mack

Posted on

Automate Social Media Preview Images with a Screenshot API

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:

  1. Design your OG image as an HTML template (with CSS!)
  2. Pass dynamic data (title, author, date) as parameters
  3. Render it to a PNG via a headless browser
  4. Serve it from your og:image meta 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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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}`],
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

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}" %>
Enter fullscreen mode Exit fullscreen mode

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

  1. Cache aggressively — OG images rarely change. Set Cache-Control: public, max-age=86400.
  2. Use webhooks — If your API supports async rendering, generate images on publish rather than on-demand.
  3. Keep templates simple — Fewer DOM nodes = faster rendering.
  4. Use system fonts — Custom fonts add latency. system-ui looks 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)