Every blog post, product page, and news article shared on social media renders a preview card. That card is driven by Open Graph meta tags — and the image behind it determines whether people click or scroll past.
Generating OG images manually doesn't scale. Once you have more than a few pages, you need automation: a consistent visual style, dynamic text injection, and an API that returns a rendered image in under a second.
This guide covers how to generate OG images programmatically with a free API.
What is an OG Image?
An OG (Open Graph) image is a 1200×630 PNG or JPEG linked in a page's <meta> tags:
<meta property="og:image" content="https://yoursite.com/og/my-post.png" />
<meta property="twitter:image" content="https://yoursite.com/og/my-post.png" />When someone shares your URL on Twitter/X, LinkedIn, Slack, or iMessage, the platform fetches this image and uses it as the preview card. A good OG image increases click-through rate significantly — studies show social cards with images get 3× more engagement than text-only shares.
Option 1: Generate OG Images via API (recommended)
The fastest approach is an API that accepts template data and returns a rendered image. No infrastructure, no browser dependencies.
Quick start with SnapSharp
SnapSharp's /v1/og-image endpoint accepts a template name and data payload, renders the image server-side with a headless browser, and returns the PNG in under 200ms:
curl -X POST https://api.snapsharp.dev/v1/og-image \
-H "Authorization: Bearer YOUR_FREE_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "blog-post",
"data": {
"title": "How We Cut Infrastructure Costs by 40%",
"author": "Sarah Kim",
"date": "April 2026",
"tag": "Engineering"
}
}' \
--output og-image.pngReturns a 1200×630 PNG. The free tier includes 100 OG image requests per month — no credit card required.
Built-in templates
Five templates ship out of the box:
| Template | Best for |
|---|---|
blog-post | Blog articles with title, author, date, tag |
product-card | Product pages with name, price, description |
social-card | General sharing with title and subtitle |
quote-card | Pull quotes with attribution |
github-readme | GitHub repository documentation |
Node.js example
import SnapSharp from '@snapsharp/sdk';
import { writeFile } from 'fs/promises';
const client = new SnapSharp(process.env.SNAPSHARP_API_KEY!);
async function generateOgImage(post: { slug: string; title: string; author: string; date: string; category: string }) {
const image = await client.ogImage({
template: 'blog-post',
data: {
title: post.title,
author: post.author,
date: post.date,
tag: post.category,
},
});
await writeFile(`./public/og/${post.slug}.png`, image);
console.log(`Generated OG image for: ${post.title}`);
}Python example
from snapsharp import SnapSharp
import os
client = SnapSharp(os.environ['SNAPSHARP_API_KEY'])
def generate_og_image(post: dict) -> bytes:
return client.og_image(
template='blog-post',
data={
'title': post['title'],
'author': post['author'],
'date': post['date'],
'tag': post['category'],
}
)
# Save to file
with open(f"public/og/{post['slug']}.png", 'wb') as f:
f.write(generate_og_image(post))Option 2: Custom HTML/CSS templates
If the built-in templates don't match your brand, you can build custom templates using HTML and CSS in the SnapSharp dashboard. The template editor gives you full control over layout, fonts, colors, and background.
Custom templates use Handlebars syntax for dynamic data injection:
<!-- Custom OG template -->
<div style="
width: 1200px; height: 630px;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
display: flex; flex-direction: column;
padding: 80px; font-family: 'Inter', sans-serif;
">
<div style="color: #10b981; font-size: 18px; font-weight: 600; margin-bottom: 32px;">
{{tag}}
</div>
<h1 style="color: white; font-size: 56px; line-height: 1.1; flex: 1; margin: 0;">
{{title}}
</h1>
<div style="display: flex; align-items: center; gap: 16px; margin-top: 40px;">
<div style="color: #94a3b8; font-size: 20px;">{{author}} · {{date}}</div>
</div>
</div>Then call it by template ID:
curl -X POST https://api.snapsharp.dev/v1/og-image \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"template": "tpl_a1b2c3d4", "data": {"title": "...", "tag": "...", "author": "...", "date": "..."}}'Integrating with Next.js
The most common pattern is generating OG images at build time for static content, or on-demand using Next.js Route Handlers:
Build-time generation (recommended for blogs)
// scripts/generate-og-images.ts
import SnapSharp from '@snapsharp/sdk';
import { writeFile } from 'fs/promises';
import { getAllPosts } from './lib/posts';
const client = new SnapSharp(process.env.SNAPSHARP_API_KEY!);
async function main() {
const posts = await getAllPosts();
// Generate in batches of 10 to avoid rate limits
for (let i = 0; i < posts.length; i += 10) {
const batch = posts.slice(i, i + 10);
await Promise.all(batch.map(async (post) => {
const image = await client.ogImage({
template: 'blog-post',
data: { title: post.title, author: post.author, date: post.date, tag: post.category },
});
await writeFile(`public/og/${post.slug}.png`, image);
}));
console.log(`Generated ${Math.min(i + 10, posts.length)} of ${posts.length}`);
}
}
main();Run this script as part of your build:
{
"scripts": {
"build": "tsx scripts/generate-og-images.ts && next build"
}
}On-demand generation (for dynamic content)
// app/api/og/route.ts
import { NextRequest, NextResponse } from 'next/server';
import SnapSharp from '@snapsharp/sdk';
const client = new SnapSharp(process.env.SNAPSHARP_API_KEY!);
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const title = searchParams.get('title') ?? 'Untitled';
const author = searchParams.get('author') ?? '';
const image = await client.ogImage({
template: 'blog-post',
data: { title, author, date: new Date().toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) },
});
return new NextResponse(image, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=86400, s-maxage=86400',
},
});
}Then reference the route in your metadata:
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
const post = await getPost(params.slug);
const ogUrl = `${process.env.NEXT_PUBLIC_APP_URL}/api/og?title=${encodeURIComponent(post.title)}&author=${encodeURIComponent(post.author)}`;
return {
openGraph: {
images: [{ url: ogUrl, width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
images: [ogUrl],
},
};
}Caching OG images
OG images rarely change after generation. Cache them aggressively:
- CDN caching: Set
Cache-Control: public, max-age=604800(7 days) on the response - Redis caching: SnapSharp caches repeated identical requests automatically (set
cache: true) - Static files: For build-time generation, serve from
/public/og/directly — zero compute
// With Redis cache (subsequent requests return in ~50ms)
const image = await client.ogImage({
template: 'blog-post',
data: { title, author, date },
cache: true,
cache_ttl: 86400, // 24 hours
});Comparison: API vs. self-hosted
| SnapSharp API | @vercel/og | Puppeteer self-hosted | |
|---|---|---|---|
| Setup time | 5 minutes | 30 minutes | 2–4 hours |
| Infrastructure | None | Vercel only | Your server |
| Custom fonts | Via template | Edge font loading | Full control |
| Complex layouts | Full HTML/CSS | Limited (Satori) | Full HTML/CSS |
| Pricing | Free–$149/mo | Vercel pricing | Server cost |
| Languages | Any (HTTP) | JavaScript only | Any |
@vercel/og is great for simple layouts on Vercel. For complex HTML/CSS templates, multi-language projects, or non-Vercel deployments, an API approach gives you more flexibility.
Free OG image generator
SnapSharp's free tier includes 100 OG image requests per month. That covers a small blog or testing in production:
# Test with your own content — replace with your API key
curl -X POST https://api.snapsharp.dev/v1/og-image \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"template": "blog-post", "data": {"title": "Your Post Title", "author": "Your Name", "date": "April 2026", "tag": "Tutorial"}}' \
--output test-og.pngSign up at snapsharp.dev/sign-up — no credit card required.