DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to Generate Open Graph Images Automatically for Your Blog

How to Generate Open Graph Images Automatically for Your Blog

When someone shares your blog post on Twitter, LinkedIn, or Slack, what do they see? If you don't have a custom Open Graph (OG) image, they get a generic preview with just your site title. That's a missed opportunity to make your content stand out.

Most content creators solve this manually: use Figma, create 10 variations, export them, name them carefully, upload them to the right folder. It's tedious. And when you publish 2-3 posts a week, manual OG images become a bottleneck.

Here's how to generate unique, branded OG images automatically — one API call per blog post.

The Problem: Manual OG Images Don't Scale

Right now, you probably:

  • Manually design OG images in Figma or Canva
  • Spend 5-10 minutes per image
  • Sometimes skip OG images entirely on low-priority posts
  • End up with inconsistent branding across social shares

Result: Your posts look boring on Twitter. Click-through rates suffer.

The Solution: Generate OG Images from HTML

Here's the simplest approach: create an HTML template with your post title and metadata, then convert it to an image on publish.

const fetch = require('node-fetch');

async function generateOGImage(title, author, category) {
  const response = await fetch('https://api.pagebolt.com/v1/og', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer YOUR_API_KEY`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      template: 'blog',
      title: title,
      subtitle: author,
      category: category
    })
  });

  return await response.buffer();
}
Enter fullscreen mode Exit fullscreen mode

That's it. 3 lines. No design work. No waiting for exports.

Real-World Example: Blog Post Publishing

Let's say you're using a static site generator (Next.js, Hugo, Astro) to publish blog posts. When you create a new post, you want to auto-generate an OG image.

Here's a Node.js script that hooks into your build process:

const fetch = require('node-fetch');
const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');

async function generateOGImagesForBlog() {
  // Read all markdown files in posts directory
  const postsDir = './posts';
  const files = fs.readdirSync(postsDir).filter(f => f.endsWith('.md'));

  for (const file of files) {
    const content = fs.readFileSync(path.join(postsDir, file), 'utf-8');
    const { data } = matter(content);

    // Skip if OG image already exists
    const ogImagePath = path.join('./public/og-images', `${data.slug}.png`);
    if (fs.existsSync(ogImagePath)) {
      console.log(`✓ OG image exists for ${data.slug}, skipping`);
      continue;
    }

    try {
      console.log(`Generating OG image for ${data.title}...`);

      const response = await fetch('https://api.pagebolt.com/v1/og', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          title: data.title,
          subtitle: `by ${data.author}`,
          category: data.category,
          // Custom branding
          backgroundColor: '#1a1a2e',
          textColor: '#00d4ff',
          logoUrl: 'https://yoursite.com/logo.png'
        })
      });

      if (!response.ok) {
        console.error(`Failed to generate OG image: ${response.statusText}`);
        continue;
      }

      const buffer = await response.buffer();

      // Ensure directory exists
      const dir = path.dirname(ogImagePath);
      if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
      }

      fs.writeFileSync(ogImagePath, buffer);
      console.log(`✓ Saved OG image to ${ogImagePath}`);

    } catch (error) {
      console.error(`Error generating OG image for ${data.slug}:`, error.message);
    }
  }

  console.log('✓ OG image generation complete');
}

// Run on build
generateOGImagesForBlog().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Add this to your package.json build script:

{
  "scripts": {
    "prebuild": "node generate-og-images.js",
    "build": "next build"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now every time you deploy, OG images are generated automatically for new posts.

Customizing Your OG Images

PageBolt supports custom styling for your OG images:

const response = await fetch('https://api.pagebolt.com/v1/og', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer YOUR_API_KEY`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'How to Generate PDFs Without Puppeteer',
    subtitle: 'Technical Tutorial',
    category: 'Development',

    // Branding options
    backgroundColor: '#ffffff',
    textColor: '#000000',
    accentColor: '#3b82f6',
    logoUrl: 'https://yoursite.com/logo.png',
    fontFamily: 'Inter',

    // Layout options
    layout: 'minimal',  // or 'card', 'gradient'
    padding: 60
  })
});
Enter fullscreen mode Exit fullscreen mode

Why This Beats Manual Design

Manual approach:

  • Design in Figma: 5-10 minutes per image
  • Export and optimize: 2 minutes per image
  • Upload and link in frontmatter: 1 minute per image
  • Total: 8-13 minutes × posts/week = 1+ hour/week

Automated approach:

  • Write blog post (already doing this)
  • Run build script: 10 seconds for 10 posts
  • OG images auto-generate and deploy
  • Total: 10 seconds/week

For a blog publishing 4 posts/week, automated OG images save ~30 minutes/week. That's 26+ hours/year.

Batch Generate OG Images for Existing Blog

Already have 50 posts without OG images? PageBolt can batch-generate them:

async function batchGenerateOGImages() {
  const posts = await getAllBlogPosts(); // Your function
  const results = [];

  // Process 10 at a time to avoid rate limits
  for (let i = 0; i < posts.length; i += 10) {
    const batch = posts.slice(i, i + 10);
    const promises = batch.map(post =>
      generateOGImage(post.title, post.author, post.category)
        .then(buffer => ({
          slug: post.slug,
          buffer: buffer,
          status: 'success'
        }))
        .catch(error => ({
          slug: post.slug,
          status: 'error',
          error: error.message
        }))
    );

    results.push(...await Promise.all(promises));
    console.log(`Processed ${i + 10}/${posts.length} posts`);
  }

  // Save all OG images
  results.forEach(result => {
    if (result.status === 'success') {
      const path = `./public/og-images/${result.slug}.png`;
      fs.writeFileSync(path, result.buffer);
    }
  });

  return results;
}
Enter fullscreen mode Exit fullscreen mode

Getting Started

  1. Sign up free at pagebolt.dev/pricing — 100 OG images/month
  2. Get your API key from the dashboard
  3. Create an HTML template or use the built-in blog template
  4. Integrate generateOGImage() into your blog build process
  5. Deploy → OG images auto-generate for every post

Your blog posts will now have unique, branded social previews — automatically.

Start free: pagebolt.dev/pricing. 100 OG images/month, no credit card required.

Top comments (0)