How to Generate OG Images Automatically for Your Website
Every link shared on Twitter, Slack, Discord, or LinkedIn shows an Open Graph preview image. If you don't set one, your links look boring. If you design them manually, you'll go crazy after 10 blog posts.
The solution: auto-generate OG images using HTML templates and a screenshot API.
The Approach
- Design a template in HTML/CSS (1200x630px, the OG standard)
- Inject dynamic data (title, author, date, category)
- Screenshot it via API to get a PNG
- Serve it as your og:image
This is exactly how Vercel's og package works, except you don't need Vercel. Any screenshot API does the job.
Step 1: Create Your HTML Template
Host a simple page that accepts query parameters and renders a card:
<!-- og-template.html -->
<html>
<head>
<style>
body {
width: 1200px; height: 630px;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(135deg, #667eea, #764ba2);
font-family: -apple-system, sans-serif;
color: white; margin: 0; padding: 60px;
}
.card {
text-align: center;
}
h1 { font-size: 56px; line-height: 1.2; margin-bottom: 16px; }
p { font-size: 24px; opacity: 0.8; }
.logo { font-size: 20px; margin-top: 32px; opacity: 0.6; }
</style>
</head>
<body>
<div class="card">
<h1 id="title"></h1>
<p id="subtitle"></p>
<div class="logo">yourbrand.com</div>
</div>
<script>
const params = new URLSearchParams(location.search);
document.getElementById('title').textContent = params.get('title') || 'My Blog Post';
document.getElementById('subtitle').textContent = params.get('subtitle') || '';
</script>
</body>
</html>
Step 2: Screenshot It with GrabShot
# Generate OG image for a specific blog post
curl "https://grabshot.dev/api/screenshot?\
url=https://yourdomain.com/og-template.html?title=My+Amazing+Post\
&width=1200&height=630&format=png" \
-H "X-API-Key: your-key" \
--output og-image.png
That's it. One API call, perfect OG image every time.
Step 3: Automate It
For a blog or CMS, generate OG images at build time or on first request:
// Node.js example: generate OG image on demand
const express = require('express');
const fetch = require('node-fetch');
const app = express();
const GRABSHOT_KEY = process.env.GRABSHOT_API_KEY;
app.get('/og/:slug', async (req, res) => {
const { slug } = req.params;
const post = await getPostBySlug(slug); // your data source
const templateUrl = `https://yoursite.com/og-template.html?` +
`title=${encodeURIComponent(post.title)}` +
`&subtitle=${encodeURIComponent(post.date)}`;
const response = await fetch(
`https://grabshot.dev/api/screenshot?url=${encodeURIComponent(templateUrl)}&width=1200&height=630`,
{ headers: { 'X-API-Key': GRABSHOT_KEY } }
);
const buffer = await response.buffer();
// Cache for 7 days
res.set('Cache-Control', 'public, max-age=604800');
res.set('Content-Type', 'image/png');
res.send(buffer);
});
Then in your HTML:
<meta property="og:image" content="https://yoursite.com/og/my-blog-post">
Design Tips for Great OG Images
- Keep text large — OG images are often shown small. 48-60px for titles minimum.
- Use high contrast — White text on a gradient or dark background works great.
- Include your logo/brand — People should recognize it's from you.
- Test on multiple platforms — Twitter crops differently than LinkedIn. Use MetaPeek to preview how your meta tags render.
- 1200x630px — The universal safe size for all platforms.
Why Not Vercel OG?
Vercel's @vercel/og is great if you're on Vercel. But it uses Satori (limited CSS subset), only works in Edge Runtime, and you're locked into their platform.
A screenshot API approach works with any framework, any hosting, and supports full CSS/JS. More flexible, same result.
Generate OG Images with GrabShot
Screenshot any HTML template at 1200x630. Perfect social previews, every time.
Try Free →Want to see GrabShot in action?
Try our free screenshot tool — no signup required.
Try GrabShot Free →