Tutorial Social Media

Build an Automatic Social Media Preview Generator

Published February 20, 2026 ยท 8 min read

Instagram social media app open on smartphone

Photo via Unsplash

When someone shares your link on Twitter, LinkedIn, or Slack, the preview image (og:image) makes or breaks the click. A boring default image? Ignored. A custom, dynamic preview showing the actual content? That gets clicks.

Building an OG image generator API used to require complex canvas rendering or Puppeteer servers. With a screenshot API, you can design OG images in HTML/CSS (which you already know) and convert them to images instantly.

๐Ÿš€ TL;DR: Design your social preview cards in HTML, host them as templates, and use SnapAPI to render them as images on-the-fly. Dynamic OG images for every page, zero design tools needed.

How It Works

The approach is simple and powerful:

Step 1: Design the HTML Template

Create a simple HTML page that renders your OG image. Host it on your server or use SnapAPI's HTML rendering feature:

<!-- og-template.html -->
<html>
<body style="margin:0; width:1200px; height:630px; display:flex;
  align-items:center; justify-content:center; 
  background: linear-gradient(135deg, #0f0f1a, #1a1a2e);
  font-family: -apple-system, sans-serif;">
  
  <div style="text-align:center; padding:60px;">
    <div style="font-size:20px; color:#00d4ff; 
      text-transform:uppercase; letter-spacing:3px; 
      margin-bottom:24px;">
      {{category}}
    </div>
    <h1 style="font-size:52px; color:white; 
      line-height:1.2; margin:0 0 24px;">
      {{title}}
    </h1>
    <p style="font-size:20px; color:#94a3b8;">
      {{author}} ยท {{date}}
    </p>
    <div style="margin-top:32px;">
      <img src="https://snapapi.pics/logo-translucent-128.png" 
        width="40" height="40" />
    </div>
  </div>
</body>
</html>

Step 2: Render with SnapAPI

Option A: Screenshot a hosted template URL

curl -X POST https://api.snapapi.pics/v1/screenshot \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yoursite.com/og-template?title=My+Blog+Post&author=Jane+Doe&date=Feb+2026&category=Tutorial",
    "width": 1200,
    "height": 630,
    "format": "png"
  }' --output og-image.png

Option B: Render raw HTML directly

curl -X POST https://api.snapapi.pics/v1/screenshot \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<html><body style=\"margin:0;width:1200px;height:630px;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#0f0f1a,#1a1a2e);font-family:sans-serif\"><h1 style=\"color:white;font-size:48px;text-align:center;padding:40px\">My Amazing Blog Post</h1></body></html>",
    "width": 1200,
    "height": 630,
    "format": "png"
  }' --output og-image.png

Node.js โ€” Dynamic OG Image Server

const express = require('express');
const fetch = require('node-fetch');
const app = express();

const SNAPAPI_KEY = process.env.SNAPAPI_KEY;
const OG_CACHE = new Map();

app.get('/og/:slug', async (req, res) => {
  const { slug } = req.params;
  
  // Check cache (OG images don't change often)
  if (OG_CACHE.has(slug)) {
    res.set('Content-Type', 'image/png');
    res.set('Cache-Control', 'public, max-age=86400');
    return res.send(OG_CACHE.get(slug));
  }
  
  // Fetch post data from your CMS/database
  const post = await db.getPost(slug);
  if (!post) return res.status(404).send('Not found');
  
  // Build template URL with dynamic data
  const templateUrl = new URL('https://yoursite.com/og-template.html');
  templateUrl.searchParams.set('title', post.title);
  templateUrl.searchParams.set('author', post.author);
  templateUrl.searchParams.set('date', post.date);
  templateUrl.searchParams.set('category', post.category);
  
  // Capture screenshot
  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({
      url: templateUrl.toString(),
      width: 1200,
      height: 630,
      format: 'png'
    })
  });
  
  const buffer = Buffer.from(await response.arrayBuffer());
  OG_CACHE.set(slug, buffer);
  
  res.set('Content-Type', 'image/png');
  res.set('Cache-Control', 'public, max-age=86400');
  res.send(buffer);
});

app.listen(3000);

Python โ€” Flask OG Image Generator

from flask import Flask, send_file, abort
from io import BytesIO
import requests
import os

app = Flask(__name__)
SNAPAPI_KEY = os.environ['SNAPAPI_KEY']
cache = {}

@app.route('/og/<slug>')
def generate_og(slug):
    if slug in cache:
        return send_file(
            BytesIO(cache[slug]),
            mimetype='image/png'
        )
    
    # Get post data from your database
    post = db.get_post(slug)
    if not post:
        abort(404)
    
    # Build HTML for the OG image
    html = f"""
    <html>
    <body style="margin:0;width:1200px;height:630px;display:flex;
      align-items:center;justify-content:center;
      background:linear-gradient(135deg,#0f0f1a,#1a1a2e);
      font-family:sans-serif">
      <div style="text-align:center;padding:60px">
        <div style="color:#00d4ff;font-size:18px;
          text-transform:uppercase;letter-spacing:3px;
          margin-bottom:20px">{post['category']}</div>
        <h1 style="color:white;font-size:48px;
          line-height:1.2;margin:0">{post['title']}</h1>
        <p style="color:#94a3b8;font-size:18px;
          margin-top:20px">{post['author']} ยท {post['date']}</p>
      </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,
            'width': 1200,
            'height': 630,
            'format': 'png'
        }
    )
    
    cache[slug] = response.content
    return send_file(BytesIO(response.content), mimetype='image/png')

Step 3: Add to Your Meta Tags

Point your og:image to your OG image endpoint:

<!-- In your page's <head> -->
<meta property="og:image" content="https://yoursite.com/og/my-blog-post" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://yoursite.com/og/my-blog-post" />

Advanced: Template Variations

Create different templates for different content types:

Performance & Caching Tips

Platform-Specific Sizes

Pricing

OG image generation is extremely cost-effective with SnapAPI:

With caching, even a site with millions of pages only needs to generate each image once.

Get Started

Stop using boring default OG images. Sign up for free and start generating dynamic social previews in minutes.

๐Ÿ’ก Pro tip: Test your OG images with Facebook's Sharing Debugger and Twitter's Card Validator to ensure they render correctly on each platform.

Related Reading

Last updated: February 20, 2026