Guide

OG Image Generation API: Dynamic Social Sharing Cards

Guide OG Images

Generate Dynamic Open Graph Images with a Screenshot API

February 9, 2026 · 6 min read

MacBook Pro showing Material Design interface components

Photo by Tirza van Dijk on Unsplash

When someone shares your page on Twitter, LinkedIn, Slack, or Discord, the link preview image is the first thing people see. A well-designed Open Graph image can dramatically increase click-through rates. But creating unique OG images for every blog post, product page, or user profile manually is impractical. The solution: generate them dynamically from HTML templates using a screenshot API.

What Are Open Graph Images?

Open Graph (OG) images are the preview images that appear when a URL is shared on social platforms. They are defined using meta tags in your HTML:

<meta property="og:image" content="https://yoursite.com/og/my-post.png">
<meta property="og:title" content="My Blog Post Title">
<meta property="og:description" content="A short description of the post">

The recommended dimensions are 1200x630 pixels for maximum compatibility across all platforms. Without a custom OG image, platforms either show a generic icon or a random image from your page, which looks unprofessional and lowers engagement.

Why Dynamic OG Images Matter

  • Higher CTR: Posts with custom images get 2-3x more clicks on social platforms
  • Brand consistency: Every shared link reinforces your brand design
  • Zero manual work: Generate images automatically for thousands of pages
  • Always up to date: Images reflect current content, not stale screenshots

The Approach: HTML Template to Image

The workflow is simple:

  1. Create an HTML/CSS template for your OG image design
  2. Inject dynamic data (title, author, date, etc.) into the template
  3. Send the HTML to SnapAPI, which renders it in a real browser and returns a PNG
  4. Serve or cache the resulting image

Key advantage: Since SnapAPI renders HTML in a real Chromium browser, you get full CSS support -- gradients, custom fonts, flexbox, grid, shadows, and even background images all work perfectly.

Step 1: Design Your HTML Template

Here is a clean, reusable OG image template. Note the exact 1200x630 dimensions:

const template = (title, author, date) => `
<!DOCTYPE html>
<html>
<head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      width: 1200px;
      height: 630px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: 80px;
      background: linear-gradient(135deg, #0a0a1a 0%, #1a0a2e 50%, #0a1a2e 100%);
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      color: white;
    }
    .logo {
      font-size: 24px;
      font-weight: 800;
      margin-bottom: 40px;
      opacity: 0.7;
    }
    .logo span { color: #00d4ff; }
    h1 {
      font-size: 56px;
      font-weight: 800;
      line-height: 1.2;
      margin-bottom: 30px;
      background: linear-gradient(135deg, #ffffff, #94a3b8);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    .meta {
      font-size: 20px;
      color: #64748b;
    }
    .meta span { color: #8b5cf6; }
    .corner {
      position: absolute;
      bottom: 40px;
      right: 80px;
      width: 60px;
      height: 60px;
      border-radius: 12px;
      background: linear-gradient(135deg, #00d4ff, #8b5cf6);
    }
  </style>
</head>
<body>
  <div class="logo">Snap<span>API</span> Blog</div>
  <h1>${title}</h1>
  <div class="meta">By <span>${author}</span> &middot; ${date}</div>
  <div class="corner"></div>
</body>
</html>
`;

Step 2: Generate the Image with Node.js

Send the HTML template to SnapAPI using the html parameter instead of url:

const fs = require("fs");

const SNAPAPI_KEY = "your_api_key";

async function generateOgImage(title, author, date) {
  const html = template(title, author, date);

  const response = await fetch("https://api.snapapi.pics/v1/screenshot", {
    method: "POST",
    headers: {
      "X-Api-Key": SNAPAPI_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      html: html,
      format: "png",
      width: 1200,
      height: 630,
      responseType: "image",
    }),
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  const buffer = Buffer.from(await response.arrayBuffer());
  return buffer;
}

// Generate and save
async function main() {
  const image = await generateOgImage(
    "How to Build a Screenshot API",
    "SnapAPI Team",
    "February 9, 2026"
  );

  fs.writeFileSync("og-image.png", image);
  console.log("OG image generated: og-image.png");
}

main();

Step 3: Generate with Python

The same approach works in Python:

import requests

SNAPAPI_KEY = "your_api_key"

def generate_og_image(title: str, author: str, date: str) -> bytes:
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{
          width: 1200px;
          height: 630px;
          display: flex;
          flex-direction: column;
          justify-content: center;
          padding: 80px;
          background: linear-gradient(135deg, #0a0a1a 0%, #1a0a2e 50%, #0a1a2e 100%);
          font-family: -apple-system, BlinkMacSystemFont, sans-serif;
          color: white;
        }}
        .logo {{ font-size: 24px; font-weight: 800; margin-bottom: 40px; opacity: 0.7; }}
        .logo span {{ color: #00d4ff; }}
        h1 {{
          font-size: 56px;
          font-weight: 800;
          line-height: 1.2;
          margin-bottom: 30px;
        }}
        .meta {{ font-size: 20px; color: #64748b; }}
        .meta span {{ color: #8b5cf6; }}
      </style>
    </head>
    <body>
      <div class="logo">Snap<span>API</span> Blog</div>
      <h1>{title}</h1>
      <div class="meta">By <span>{author}</span> &middot; {date}</div>
    </body>
    </html>
    """

    response = requests.post(
        "https://api.snapapi.pics/v1/screenshot",
        headers={
            "X-Api-Key": SNAPAPI_KEY,
            "Content-Type": "application/json",
        },
        json={
            "html": html,
            "format": "png",
            "width": 1200,
            "height": 630,
            "responseType": "image",
        },
        timeout=30,
    )
    response.raise_for_status()
    return response.content


# Generate for a blog post
image = generate_og_image(
    "Building AI Agents with Web Data",
    "SnapAPI Team",
    "February 9, 2026"
)

with open("og-image.png", "wb") as f:
    f.write(image)

print(f"Generated OG image: {len(image)} bytes")

Serving OG Images Dynamically

In a real application, you want to serve OG images on demand. Here is an Express.js endpoint that generates and caches OG images:

const express = require("express");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");

const app = express();
const CACHE_DIR = "./og-cache";
const SNAPAPI_KEY = "your_api_key";

// Ensure cache directory exists
fs.mkdirSync(CACHE_DIR, { recursive: true });

app.get("/og/:slug.png", async (req, res) => {
  const { slug } = req.params;

  // Check cache first
  const cacheKey = crypto.createHash("md5").update(slug).digest("hex");
  const cachePath = path.join(CACHE_DIR, `${cacheKey}.png`);

  if (fs.existsSync(cachePath)) {
    res.setHeader("Content-Type", "image/png");
    res.setHeader("Cache-Control", "public, max-age=86400");
    return res.sendFile(path.resolve(cachePath));
  }

  // Look up post data from your database
  const post = await getPostBySlug(slug);
  if (!post) return res.status(404).send("Not found");

  // Generate OG image
  const html = template(post.title, post.author, post.date);

  const response = await fetch("https://api.snapapi.pics/v1/screenshot", {
    method: "POST",
    headers: {
      "X-Api-Key": SNAPAPI_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      html,
      format: "png",
      width: 1200,
      height: 630,
      responseType: "image",
    }),
  });

  if (!response.ok) {
    return res.status(500).send("Failed to generate image");
  }

  const buffer = Buffer.from(await response.arrayBuffer());

  // Write to cache
  fs.writeFileSync(cachePath, buffer);

  // Serve the image
  res.setHeader("Content-Type", "image/png");
  res.setHeader("Cache-Control", "public, max-age=86400");
  res.send(buffer);
});

app.listen(3000, () => console.log("OG image server on :3000"));

Then reference it in your HTML:

<meta property="og:image" content="https://yoursite.com/og/my-blog-post.png">

Caching Strategies

Generating OG images on every request is wasteful. Here are three proven caching approaches:

1. Build-Time Generation

Generate images during your build step (e.g., in a Next.js getStaticProps or a custom build script). Best for static sites where content changes infrequently.

2. On-Demand + File Cache

Generate on first request, save to disk, and serve from cache on subsequent requests (as shown in the Express example above). Good for sites with moderate traffic.

3. CDN Edge Caching

Put your OG image endpoint behind a CDN like Cloudflare or AWS CloudFront. Set long Cache-Control headers so the CDN caches the image at the edge. Best for high-traffic sites.

// Set headers for CDN caching
res.setHeader("Cache-Control", "public, max-age=604800, s-maxage=2592000");
res.setHeader("CDN-Cache-Control", "max-age=2592000");

Pro tip: Use AVIF format instead of PNG for 50% smaller files. Just change format: "png" to format: "avif". Most social platforms now support AVIF, and the smaller file size means faster page loads when platforms fetch your OG image.

Template Ideas

Here are some common OG image template patterns you can build:

  • Blog post card: Title + author + publication date + category tag
  • Product page: Product name + price + hero image (use an <img> tag with an absolute URL)
  • User profile: Avatar + username + bio + stats (followers, posts)
  • Documentation: Page title + section breadcrumb + brand logo
  • Changelog: Version number + release date + key feature highlights

Since you are writing full HTML/CSS, the design possibilities are unlimited. You can use Google Fonts (via <link> tag), SVG icons, background images, and any CSS feature supported by Chromium.

Testing Your OG Images

After implementing, test your OG images with these tools:

Next Steps

Try SnapAPI Free

Get 200 free screenshots per month. No credit card required.

Get Started Free →

Start Capturing for Free

200 screenshots/month. Screenshots, PDF, scraping, and video recording. No credit card required.

Get Free API Key →