Why Social Media Preview Images Matter
When you share a link on Twitter, Facebook, LinkedIn, or Slack, those platforms look for Open Graph (OG) meta tags to render a rich preview. Without them, your link shows up as plain text -- no image, no description, just a URL nobody clicks.
Links with preview images get 2-3x more clicks than plain links. For blogs, SaaS landing pages, and documentation sites, that's a massive difference in traffic.
The problem? Manually creating OG images for every page is tedious. You need a template, a design tool, and time. Or you can automate it with a screenshot API.
The Approach: Screenshot Your Own Pages
The simplest way to generate OG images automatically:
- Create an OG template page -- a simple HTML page that displays your title, description, and branding
- Screenshot it via API -- use a service like GrabShot to capture it at 1200x630px (the standard OG image size)
- Serve the image -- cache it and reference it in your meta tags
This approach works for any framework: Next.js, Nuxt, Astro, plain HTML, or even dynamic dashboards.
Quick Start with curl
The fastest way to generate an OG image:
# Capture at OG image dimensions (1200x630)
curl "https://grabshot.dev/v1/screenshot?\
url=https://yoursite.com/og-template?title=My+Blog+Post\
&width=1200&height=630&format=webp&key=YOUR_API_KEY" \
-o og-image.webp
That's it. One HTTP request, one image. Add it to your build pipeline and every page gets a unique preview image.
Node.js Example: Automated OG Images for a Blog
import fs from 'fs';
const API_KEY = process.env.GRABSHOT_KEY;
const BASE = 'https://grabshot.dev/v1/screenshot';
async function generateOGImage(title, slug) {
// Your OG template page accepts title as a query param
const templateUrl = `https://yoursite.com/og?title=${encodeURIComponent(title)}`;
const url = `${BASE}?url=${encodeURIComponent(templateUrl)}&width=1200&height=630&format=webp&key=${API_KEY}`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
fs.writeFileSync(`./public/og/${slug}.webp`, buffer);
console.log(`Generated OG image for: ${title}`);
}
// Generate for all your blog posts
const posts = [
{ title: 'Getting Started with React', slug: 'getting-started-react' },
{ title: 'Why TypeScript Matters', slug: 'why-typescript' },
];
for (const post of posts) {
await generateOGImage(post.title, post.slug);
}
Python Example
import requests
from urllib.parse import quote
API_KEY = "YOUR_API_KEY"
def generate_og_image(title: str, output_path: str):
template_url = f"https://yoursite.com/og?title={quote(title)}"
params = {
"url": template_url,
"width": 1200,
"height": 630,
"format": "webp",
"key": API_KEY,
}
resp = requests.get("https://grabshot.dev/v1/screenshot", params=params)
resp.raise_for_status()
with open(output_path, "wb") as f:
f.write(resp.content)
print(f"Saved OG image to {output_path}")
generate_og_image("My Awesome Post", "og-image.webp")
Pro Tips
Frameworks That Work Great with This
Next.js
Generate OG images in getStaticProps or as an API route. Cache them in /public/og/.
Astro
Use a build integration to screenshot templates during astro build.
Hugo / Jekyll
Add a post-build script that generates OG images for all markdown posts.
Rails / Django
Generate on first request, cache in S3 or local storage. Serve via CDN.