DEV Community

Custodia-Admin
Custodia-Admin

Posted on Edited 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://pagebolt.dev/api/v1/og-image \
  -H "x-api-key: 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://pagebolt.dev/api/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://pagebolt.dev/api/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)