How to Generate Open Graph Images Automatically (No Design Tools Required)
You published a blog post.
Your co-founder shares it on Twitter. The link preview shows... a blank gray box with your domain name.
No title. No description. No image.
Thirty minutes later, they share a different post. This time there's an image—a custom-designed social card with the headline, a gradient background, and your logo.
Thirty tweets later, you've published thirty blog posts. You've designed thirty custom OG images in Figma. That's 15+ hours of manual design work.
And tomorrow you're publishing five more posts.
There's a better way.
The Problem: OG Images Don't Scale
Open Graph images are the preview card that shows when someone shares your link on Twitter, LinkedIn, Facebook, Slack, or Discord.
They drive:
- Click-through rates — good image = 2-3x more clicks
- Brand consistency — every share looks professional
- SEO — image previews improve engagement metrics
But creating them manually doesn't scale:
-
Every post needs a unique image
- Blog post? Design an image.
- Product page? Design an image.
- Pricing page? Design an image.
- Documentation? Design an image.
-
Designers are expensive
- Design a template in Figma: 30 minutes
- Adjust for each post: 10 minutes per post
- 20 posts per month = 200 minutes (3+ hours)
-
Designers are slow
- You publish a post at 9 AM
- Designer is in a meeting
- OG image ready by 2 PM
- By then, social sharing opportunity is gone
-
Designers leave
- Your designer quits
- No one else knows Figma
- OG images stop happening
- Social sharing breaks
Developers have solved this problem before. The solution: generate OG images dynamically.
The Solution: API-Generated OG Images
Instead of designing in Figma:
You publish a post
→ API call to generate OG image
→ Image automatically created
→ Image auto-inserted in HTML meta tags
→ Twitter/LinkedIn/Slack shows rich preview
Total time: < 1 second. No designer. No Figma. One API call.
Here's how it works:
Step 1: Define your OG image template
curl -X POST https://api.pagebolt.dev/v1/og-image \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "default",
"title": "How to Build AI Agents That Pass Compliance Audits",
"subtitle": "Add visual proof to your audit trails",
"width": 1200,
"height": 630,
"bgColor": "#0f172a",
"textColor": "#ffffff"
}' \
-o og-image.png
Step 2: Use the image in your HTML
<meta property="og:image" content="https://your-cdn.com/og-images/post-slug.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
Step 3: Done. Next time someone shares the link, they see your custom image.
Real-World Implementation
Here's a complete Node.js example:
import axios from 'axios';
import fs from 'fs';
import path from 'path';
const PAGEBOLT_API_KEY = process.env.PAGEBOLT_API_KEY;
const OG_IMAGES_DIR = './public/og-images';
// Ensure directory exists
if (!fs.existsSync(OG_IMAGES_DIR)) {
fs.mkdirSync(OG_IMAGES_DIR, { recursive: true });
}
async function generateOGImage(post) {
/**
* Generate an OG image for a blog post.
*
* Args:
* post: { slug, title, excerpt, author, date, category }
*/
console.log(`🖼️ Generating OG image for: ${post.title}`);
try {
const response = await axios.post(
'https://api.pagebolt.dev/v1/og-image',
{
template: 'default',
title: post.title,
subtitle: post.excerpt || post.category,
accentColor: getCategoryColor(post.category),
bgColor: '#0f172a',
textColor: '#ffffff',
logo: 'https://pagebolt.dev/logo.png',
width: 1200,
height: 630
},
{
headers: {
Authorization: `Bearer ${PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
}
);
// Save to public/og-images/{slug}.png
const filename = path.join(OG_IMAGES_DIR, `${post.slug}.png`);
fs.writeFileSync(filename, response.data);
console.log(`✅ Saved: ${filename}`);
return {
slug: post.slug,
path: `/og-images/${post.slug}.png`,
url: `https://yoursite.com/og-images/${post.slug}.png`
};
} catch (error) {
console.error(`❌ Failed to generate OG image: ${error.message}`);
return null;
}
}
function getCategoryColor(category) {
/**
* Different colors for different post categories.
*/
const colors = {
'tutorial': '#3b82f6', // Blue
'ai-agents': '#8b5cf6', // Purple
'compliance': '#ec4899', // Pink
'devops': '#14b8a6', // Teal
'security': '#f59e0b', // Amber
'default': '#6366f1' // Indigo
};
return colors[category] || colors['default'];
}
async function generateAllBlogPosts() {
/**
* Generate OG images for all blog posts.
* Call this after publishing new posts.
*/
const blogPosts = [
{
slug: 'how-to-build-ai-agents',
title: 'How to Build AI Agents That Pass Compliance Audits',
excerpt: 'Add visual proof to your audit trails',
category: 'ai-agents',
author: 'Federico Brooks',
date: '2026-03-23'
},
{
slug: 'website-monitoring-screenshots',
title: 'Monitor Your Website for Visual Changes with Screenshots',
excerpt: 'Detect layout changes, broken CSS, missing images',
category: 'devops',
author: 'Federico Brooks',
date: '2026-03-23'
},
{
slug: 'narrated-demo-videos',
title: 'Auto-Generate Narrated Demo Videos for Your SaaS',
excerpt: 'No Loom. No manual recording. One API call.',
category: 'tutorial',
author: 'Federico Brooks',
date: '2026-03-23'
}
];
console.log(`\n🎨 Generating OG images for ${blogPosts.length} posts...\n`);
const results = [];
for (const post of blogPosts) {
const result = await generateOGImage(post);
if (result) results.push(result);
}
console.log(`\n✅ Complete! Generated ${results.length} OG images.\n`);
return results;
}
// Generate OG images after publishing
generateAllBlogPosts();
What this does:
- Takes blog post metadata (title, category, slug)
- Calls PageBolt's
/og-imageendpoint - Gets back a PNG file
- Saves it to
public/og-images/{slug}.png - You reference it in your HTML:
<meta property="og:image" content="/og-images/{slug}.png" />
Using Custom HTML (Advanced)
For full design control, pass custom HTML instead of using templates:
async function generateCustomOGImage(post) {
const customHTML = `
<div style="
width: 1200px;
height: 630px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: 'Inter', sans-serif;
color: white;
padding: 60px;
box-sizing: border-box;
text-align: center;
">
<h1 style="font-size: 48px; margin: 0 0 20px 0; font-weight: 700;">
${post.title}
</h1>
<p style="font-size: 24px; margin: 0 0 40px 0; opacity: 0.9;">
${post.excerpt}
</p>
<div style="display: flex; align-items: center; gap: 15px; margin-top: 40px;">
<img src="https://pagebolt.dev/logo.png" style="width: 40px; height: 40px; border-radius: 50%;" />
<span style="font-size: 14px; opacity: 0.8;">${post.author} • ${post.date}</span>
</div>
</div>
`;
const response = await axios.post(
'https://api.pagebolt.dev/v1/og-image',
{
html: customHTML,
width: 1200,
height: 630
},
{
headers: { Authorization: `Bearer ${PAGEBOLT_API_KEY}` },
responseType: 'arraybuffer'
}
);
return response.data;
}
You get complete design control. Gradients, images, fonts, custom layouts—anything you can do in HTML/CSS.
Integration with Your Blog
Next.js / Vercel (recommended):
// pages/api/og-image.js
// Generates OG image on-demand for any post
import { generateOGImage } from '@/lib/og-generator';
export default async function handler(req, res) {
const { slug, title, excerpt } = req.query;
const imageBuffer = await generateOGImage({
slug,
title,
excerpt,
category: 'tutorial'
});
res.setHeader('Content-Type', 'image/png');
res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache 1 day
res.send(imageBuffer);
}
Then reference it:
<meta property="og:image" content="https://yoursite.com/api/og-image?slug=post-slug&title=Post%20Title" />
WordPress / Headless CMS:
// Hook: when a post is published
hooks.addAction('publish_post', async (post) => {
await generateOGImage({
slug: post.slug,
title: post.title,
excerpt: post.excerpt
});
});
Cost & Scale
| Plan | Images/Month | 10 posts/month | 100 posts/month | 500 posts/month |
|---|---|---|---|---|
| Free | 100 | ✅ Yes | ❌ No | ❌ No |
| Starter | 5,000 | ✅ Yes | ✅ Yes | ❌ No |
| Growth | 50,000 | ✅ Yes | ✅ Yes | ✅ Yes (10K/mo) |
| Scale | Unlimited | ✅ Yes | ✅ Yes | ✅ Yes |
One OG image per post. If you publish 50 posts per month:
- Free plan: Not enough
- Starter plan ($29/month): Perfect fit
- Growth plan ($99/month): Can handle 500+ posts/month
Real-World Scenarios
Scenario 1: Blog with Dynamic Posts
Your SaaS blog publishes 3 posts per week. Each post needs a custom OG image.
Old workflow:
- Designer creates Figma template
- For each post, designer duplicates template
- Designer updates title, excerpt, color
- Designer exports PNG (10 minutes per post)
- 3 posts/week = 30 minutes of design work
New workflow:
- Post published
- API call triggered automatically
- OG image generated in < 1 second
- No designer needed
Savings: 2.5 hours per week = 130 hours per year
Scenario 2: Documentation Site
Your docs have 500 pages. Each page should have its own OG image for social sharing.
Old workflow:
- Hire designer
- Create 500 custom images
- 10 hours per 100 images
- Total: 50 hours of design work
New workflow:
- Write a Node.js script
- Batch generate all 500 images
- Takes < 10 minutes total
- Done
Savings: 49+ hours, plus instant regeneration when docs change
Scenario 3: SaaS with User-Generated Content
Your platform lets users create public profiles. Each profile needs an OG image.
Old workflow:
- Every new user = manual image design
- Doesn't scale
- Many profiles have no custom image
New workflow:
- User creates profile
- OG image auto-generated from their data
- Every profile has a unique image
- Scales infinitely
Result: Better social sharing, more profile views, more signups
Production Tips
1. Cache aggressively — OG images don't change often. Cache for 24 hours or longer:
Cache-Control: public, max-age=86400
2. Pre-generate at publish time — Don't wait for the first Twitter share. Generate when the post is published:
hooks.on('post:publish', generateOGImage);
3. Regenerate on updates — If post title changes, regenerate:
hooks.on('post:update', regenerateOGImage);
4. Use consistent branding — Pick 2-3 colors per category. Consistency builds recognition:
const categoryColors = {
'tutorial': '#3b82f6',
'ai-agents': '#8b5cf6',
'compliance': '#ec4899'
};
5. Test social previews — Use Twitter's Card Validator or Facebook's Sharing Debugger to verify images render correctly.
The Bottom Line
Manual OG image design doesn't scale. It's a bottleneck in your publishing workflow.
API-generated OG images solve it:
- ✅ Automatic (no designer needed)
- ✅ Instant (< 1 second per image)
- ✅ Consistent (same template, every post)
- ✅ Scalable (works for 10 posts or 10,000)
Every SaaS needs this.
Ready to automate your OG images?
Generate your first OG image in 5 minutes. Free tier: 100 images/month. Starter plan: up to 5,000 images/month for just $29.
Top comments (0)