March 28, 2026 · 9 min read

How to Automate OG Images for Your SaaS Blog (Zero Design Skills Needed)

Every blog post deserves a unique social preview image. But manually creating them in Figma is a time sink that doesn't scale. Here's how to fully automate OG image generation for your SaaS blog—with working code for Next.js, Hugo, Jekyll, and WordPress.

Automate OG images for SaaS blog

Why OG Images Matter for SaaS Blogs

When someone shares your blog post on Twitter, LinkedIn, Slack, or Discord, the first thing people see is the social preview card. That card is driven by your Open Graph image—the og:image meta tag in your HTML.

Posts with custom OG images get 2-3x more engagement than posts with generic favicons or no image at all. For a SaaS blog that's trying to drive signups, that difference compounds across every piece of content you publish.

The problem is creating these images. The typical workflow looks like:

  1. Open Figma or Canva
  2. Duplicate your OG image template
  3. Change the title text
  4. Export as PNG at 1200×630
  5. Upload to your CMS or /public folder
  6. Reference it in your meta tags

That's 5-10 minutes per post. For a team publishing twice a week, that's 8-10 hours a year spent on images that exist solely for social sharing. And if you rebrand, you get to redo all of them.

The Automated Approach

Instead of creating images manually, you generate them dynamically from your post's metadata. The flow becomes:

  1. Write your blog post (title, category, date)
  2. Your template automatically constructs an OG image URL using that metadata
  3. When a social platform crawls your page, the API generates the image on the fly

No design tool. No export step. No upload. The image is always in sync with your content because it's derived from it.

How OGPeek Works

OGPeek is an API that generates OG images from URL parameters. You pass a title, subtitle, template, theme, and brand color. It returns a 1200×630 PNG in under 200ms.

The simplest possible integration is a URL in your meta tags:

<meta property="og:image"
  content="https://ogpeek.com/api/v1/og
    ?title=Your+Post+Title
    &subtitle=Your+Blog+Name
    &template=gradient
    &theme=midnight
    &brandColor=%23FF7A00" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

The free tier gives you 50 images per day with no signup. For a SaaS blog, that's more than enough—social platforms cache images after the first fetch, so even a blog with hundreds of posts won't hit the limit under normal traffic.

Dogfooding: This very blog post uses OGPeek to generate its own OG image. Check the page source—the og:image meta tag points to the OGPeek API.

Next.js Integration

Next.js (App Router) makes this especially clean with the generateMetadata function. Here's a complete implementation for a blog with dynamic routes.

Blog Post Layout

// app/blog/[slug]/page.tsx
import { getPostBySlug, getAllPosts } from '@/lib/posts';

export async function generateStaticParams() {
  const posts = getAllPosts();
  return posts.map(post => ({ slug: post.slug }));
}

export async function generateMetadata({ params }) {
  const post = getPostBySlug(params.slug);

  const ogImageUrl = `https://ogpeek.com/api/v1/og?${new URLSearchParams({
    title: post.title,
    subtitle: post.category || 'Your SaaS Blog',
    template: 'gradient',
    theme: 'midnight',
    brandColor: '#6366F1'   // match your brand
  })}`;

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.date,
      images: [{
        url: ogImageUrl,
        width: 1200,
        height: 630,
        alt: post.title,
      }],
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.excerpt,
      images: [ogImageUrl],
    },
  };
}

Every blog post now gets a unique, branded OG image automatically. When you publish a new post, the OG image exists the moment the page does. No extra step.

Customizing Per Category

Want different colors for different categories? Map your categories to brand colors:

const categoryColors = {
  'Engineering': '#6366F1',
  'Product': '#10B981',
  'Company': '#F59E0B',
  'Tutorial': '#FF7A00',
};

const brandColor = categoryColors[post.category] || '#6366F1';

Now your engineering posts have indigo cards, product posts have green, and tutorials have orange. Instant visual differentiation in social feeds.

Hugo Integration

Hugo uses Go templates for meta tags. Add this to your layouts/partials/head.html or equivalent:

{{/* layouts/partials/og-image.html */}}
{{ $title := .Title | urlquery }}
{{ $subtitle := .Site.Title | urlquery }}
{{ $template := "gradient" }}
{{ $theme := "midnight" }}
{{ $brandColor := "%236366F1" }}

{{ if .Params.category }}
  {{ $subtitle = .Params.category | urlquery }}
{{ end }}

<meta property="og:image"
  content="https://ogpeek.com/api/v1/og?title={{ $title }}&subtitle={{ $subtitle }}&template={{ $template }}&theme={{ $theme }}&brandColor={{ $brandColor }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image"
  content="https://ogpeek.com/api/v1/og?title={{ $title }}&subtitle={{ $subtitle }}&template={{ $template }}&theme={{ $theme }}&brandColor={{ $brandColor }}" />

Then include it in your head partial:

{{ partial "og-image.html" . }}

Every Hugo page—blog posts, docs, landing pages—now has an auto-generated OG image derived from its front matter.

Jekyll Integration

Jekyll uses Liquid templates. Add this to your _includes/head.html:

<!-- _includes/og-image.html -->
{% assign og_title = page.title | url_encode %}
{% assign og_subtitle = page.category | default: site.title | url_encode %}
{% assign og_template = "gradient" %}
{% assign og_theme = "midnight" %}
{% assign og_brand = "%236366F1" %}

<meta property="og:image"
  content="https://ogpeek.com/api/v1/og?title={{ og_title }}&subtitle={{ og_subtitle }}&template={{ og_template }}&theme={{ og_theme }}&brandColor={{ og_brand }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image"
  content="https://ogpeek.com/api/v1/og?title={{ og_title }}&subtitle={{ og_subtitle }}&template={{ og_template }}&theme={{ og_theme }}&brandColor={{ og_brand }}" />

Include it in your layout:

{% include og-image.html %}

Works with any Jekyll theme. No plugins required, no build-time dependencies.

WordPress Integration

For WordPress, you have two options: a theme function or a lightweight plugin approach. Here's the theme function method—add this to your functions.php:

// functions.php
function ogpeek_og_image() {
  if (is_singular('post')) {
    $title = urlencode(get_the_title());
    $category = '';
    $cats = get_the_category();
    if (!empty($cats)) {
      $category = urlencode($cats[0]->name);
    }

    $og_url = "https://ogpeek.com/api/v1/og?"
      . "title={$title}"
      . "&subtitle={$category}"
      . "&template=gradient"
      . "&theme=midnight"
      . "&brandColor=%236366F1";

    echo '<meta property="og:image" content="' . esc_url($og_url) . '" />' . "\n";
    echo '<meta property="og:image:width" content="1200" />' . "\n";
    echo '<meta property="og:image:height" content="630" />' . "\n";
    echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
    echo '<meta name="twitter:image" content="' . esc_url($og_url) . '" />' . "\n";
  }
}
add_action('wp_head', 'ogpeek_og_image');

WordPress note: If you use Yoast SEO or Rank Math, they inject their own og:image tags. You'll need to disable their social image output or use their filter hooks to override the image URL with the OGPeek URL instead.

Overriding Yoast SEO

// Override Yoast's OG image with OGPeek
add_filter('wpseo_opengraph_image', function($url) {
  if (is_singular('post')) {
    $title = urlencode(get_the_title());
    return "https://ogpeek.com/api/v1/og?title={$title}"
      . "&template=gradient&theme=midnight&brandColor=%236366F1";
  }
  return $url;
});

Using the POST Endpoint for Paid Plans

The free tier uses GET requests and adds a small watermark. On paid plans ($9/mo Pro, $29/mo Business), you use the POST endpoint with an API key for watermark-free images:

// Server-side: generate and cache OG images
const response = await fetch('https://ogpeek.com/api/v1/og', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.OGPEEK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: post.title,
    subtitle: post.category,
    template: 'gradient',
    theme: 'midnight',
    brandColor: '#6366F1',
  }),
});

const imageBuffer = await response.arrayBuffer();
// Save to your CDN or public folder

This approach lets you pre-generate images at build time and serve them from your own CDN, giving you full control over caching and delivery.

Choosing the Right Template

OGPeek offers four templates, each suited to different content types:

For a SaaS blog, gradient is the most versatile. It looks professional in every social feed and the gradient adapts to your brandColor automatically.

Themes and Brand Matching

Each template supports five built-in themes:

Pair the theme with your brandColor to match your SaaS product's visual identity. If your product uses a dark UI (like Linear or Vercel), use midnight. If it's a light, clean UI, use light.

Testing Your OG Images

After implementing, verify everything works with these tools:

The most common issues are missing og:image:width and og:image:height tags (some platforms won't display the image without them) and title encoding problems (special characters like & need URL encoding).

Advanced: Pre-generating at Build Time

For static sites, you can pre-generate all OG images during your build step instead of relying on runtime generation. This is useful if you want to self-host the images:

// scripts/generate-og-images.js
const fs = require('fs');
const path = require('path');
const posts = require('./posts.json');

async function generateAll() {
  for (const post of posts) {
    const params = new URLSearchParams({
      title: post.title,
      subtitle: post.category,
      template: 'gradient',
      theme: 'midnight',
      brandColor: '#6366F1',
    });

    const res = await fetch(
      `https://ogpeek.com/api/v1/og?${params}`
    );
    const buffer = await res.arrayBuffer();
    const outPath = path.join('public', 'og', `${post.slug}.png`);
    fs.writeFileSync(outPath, Buffer.from(buffer));
    console.log(`Generated: ${outPath}`);
  }
}

generateAll();

Run this in your CI/CD pipeline, and every deploy generates fresh OG images for all your content. Point your og:image tags at the local files instead of the API URL.

Get started free

50 images per day, no signup, no credit card. Automate your blog's OG images in under 5 minutes.

Open the playground →

Conclusion

Automating OG images is one of those small improvements that pays off every time you publish. You stop thinking about social preview cards entirely—they just exist, branded and consistent, for every piece of content you ship.

The integration takes 5-10 minutes regardless of your framework. The free tier handles most SaaS blogs without hitting limits. And when you're ready for watermark-free images at higher volume, the Pro plan is $9/month.

For more on the API, read our complete guide to dynamic OG image generation. If you're comparing tools, check out our Cloudinary vs OGPeek comparison. And for platform-specific image dimensions, see the OG image size guide.

More developer APIs from the Peek Suite