DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to Generate Open Graph Images Automatically (No Design Tools Required)

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:

  1. 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.
  2. 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)
  3. 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
  4. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

What this does:

  1. Takes blog post metadata (title, category, slug)
  2. Calls PageBolt's /og-image endpoint
  3. Gets back a PNG file
  4. Saves it to public/og-images/{slug}.png
  5. 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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

Then reference it:

<meta property="og:image" content="https://yoursite.com/api/og-image?slug=post-slug&title=Post%20Title" />
Enter fullscreen mode Exit fullscreen mode

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
  });
});
Enter fullscreen mode Exit fullscreen mode

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:

  1. Designer creates Figma template
  2. For each post, designer duplicates template
  3. Designer updates title, excerpt, color
  4. Designer exports PNG (10 minutes per post)
  5. 3 posts/week = 30 minutes of design work

New workflow:

  1. Post published
  2. API call triggered automatically
  3. OG image generated in < 1 second
  4. 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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

3. Regenerate on updates — If post title changes, regenerate:

hooks.on('post:update', regenerateOGImage);
Enter fullscreen mode Exit fullscreen mode

4. Use consistent branding — Pick 2-3 colors per category. Consistency builds recognition:

const categoryColors = {
  'tutorial': '#3b82f6',
  'ai-agents': '#8b5cf6',
  'compliance': '#ec4899'
};
Enter fullscreen mode Exit fullscreen mode

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.

Get started free →

Top comments (0)