Generate Social Media Cards Automatically with a Screenshot API
Every link shared on Twitter, LinkedIn, Slack, or Discord shows a preview card. That card is usually generated from your page's og:image meta tag. If you don't have one, the platform either shows nothing or picks a random image from your page.
Most developers solve this by manually creating images in Figma or Canva. That doesn't scale. If you have a blog with 50 posts, a docs site with 200 pages, or a SaaS with dynamic user profiles, you need automated card generation.
The Screenshot Approach
Instead of building a custom image generation pipeline, you can screenshot a purpose-built HTML template. Here's how:
- Create an HTML page that renders your card design
- Pass dynamic data (title, description, author) via URL parameters
- Screenshot it at the right dimensions (1200x630 for Open Graph)
curl "https://hermesforge.dev/api/screenshot?url=https://yoursite.com/og-card?title=My+Post&width=1200&height=630&format=webp"
Why This Works Better Than You'd Think
It's just HTML and CSS. You already know how to style a card. You don't need to learn Canvas, Sharp, Puppeteer internals, or a template language. Write CSS, get an image.
It handles dynamic content naturally. User avatars, variable-length titles, custom colors — all trivial in CSS, painful in image generation libraries.
WebP output keeps files small. A 1200x630 social card in WebP is typically 30-50KB. Fast to serve, fast to load.
A Minimal Card Template
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
width: 1200px;
height: 630px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: system-ui, sans-serif;
color: white;
box-sizing: border-box;
}
h1 { font-size: 56px; margin: 0 0 20px 0; line-height: 1.2; }
p { font-size: 24px; opacity: 0.9; margin: 0; }
.footer { margin-top: auto; font-size: 20px; opacity: 0.7; }
</style>
</head>
<body>
<h1>Your Post Title Here</h1>
<p>A brief description of what this post covers</p>
<div class="footer">yoursite.com</div>
</body>
</html>
Host this template, pass the title and description as query parameters, and screenshot it. Done.
Automating at Build Time
If you use a static site generator (Next.js, Hugo, Astro), you can generate cards during the build:
import requests
posts = get_all_posts() # your CMS/markdown reader
for post in posts:
params = {
"url": f"https://yoursite.com/og-template?title={post.title}",
"width": 1200,
"height": 630,
"format": "webp",
"quality": 85
}
resp = requests.get("https://hermesforge.dev/api/screenshot", params=params)
with open(f"public/og/{post.slug}.webp", "wb") as f:
f.write(resp.content)
Then reference the generated image in your HTML:
<meta property="og:image" content="https://yoursite.com/og/my-post-slug.webp" />
Dynamic Generation with Caching
For sites where content changes frequently, generate cards on-demand and cache them:
from flask import Flask, send_file, request
import requests
import hashlib
import os
app = Flask(__name__)
CACHE_DIR = "/tmp/og-cache"
@app.route("/og/<path:slug>.png")
def og_image(slug):
cache_key = hashlib.md5(slug.encode()).hexdigest()
cache_path = os.path.join(CACHE_DIR, f"{cache_key}.webp")
if not os.path.exists(cache_path):
resp = requests.get(
"https://hermesforge.dev/api/screenshot",
params={
"url": f"https://yoursite.com/og-template?slug={slug}",
"width": 1200, "height": 630,
"format": "webp"
}
)
os.makedirs(CACHE_DIR, exist_ok=True)
with open(cache_path, "wb") as f:
f.write(resp.content)
return send_file(cache_path, mimetype="image/webp")
Platform-Specific Dimensions
Different platforms expect different sizes:
| Platform | Recommended Size | Aspect Ratio |
|---|---|---|
| Twitter/X | 1200 × 628 | ~1.91:1 |
| 1200 × 627 | ~1.91:1 | |
| 1200 × 630 | ~1.91:1 | |
| Discord | 1200 × 630 | ~1.91:1 |
| Slack | 800 × 418 | ~1.91:1 |
Good news: 1200×630 works well everywhere. Use that as your default.
The No-Signup Option
You don't need an API key to try this. The screenshot API at hermesforge.dev works without authentication for basic usage. Just pass a URL and get an image back.
For production use with higher rate limits, get a free API key — it takes 10 seconds.
Why Not Use a Dedicated OG Image Service?
Services like Cloudinary and Imgix offer OG image generation. They work, but:
- Cost: They charge per transformation or per month. Screenshot APIs are often free for low volume.
- Flexibility: You're constrained to their template system. With screenshots, you use standard HTML/CSS.
- Control: Your template lives on your infrastructure. No vendor lock-in.
The screenshot approach trades some performance (generating an image takes 2-3 seconds vs. milliseconds for a template engine) for maximum flexibility. Cache the results and the performance difference disappears.