How to Generate Open Graph Images Automatically for Your Blog
Every blog post needs an Open Graph image. Creating them by hand does not scale. Here is how to generate OG images automatically using a single API endpoint, with integration code for Next.js, Astro, and Hugo.
Why Automatic OG Images Matter
When someone shares your blog post on Twitter, LinkedIn, Slack, or Discord, the platform fetches the URL and renders a preview card. That card pulls its image from the og:image meta tag in your HTML.
Posts with a custom OG image get 2-3x more clicks than posts with no image or a generic favicon fallback. That is not speculation—Twitter's own data shows that tweets with images receive 150% more retweets than text-only tweets.
The problem is obvious: if you publish twice a week, you need 100+ OG images per year. Creating each one manually in Figma takes 5-10 minutes. That is 8-16 hours per year spent on images that most visitors never even see on your site—they only appear in social feeds.
The solution is an og image generator API that creates these images on the fly, from parameters you define in code.
How Automatic OG Image Generation Works
Instead of designing an image, exporting a PNG, uploading it somewhere, and pasting the URL into a meta tag, you construct a URL with parameters. The API returns a rendered 1200×630 PNG.
Here is the simplest possible example:
curl
curl "https://ogpeek.com/api/v1/og?title=My+Blog+Post&template=gradient&theme=dark" \
--output og-image.png
That single request produces a production-ready image with your title rendered on a dark gradient background. No Figma, no Canva, no headless browser running Puppeteer.
The image is generated server-side using SVG-native rendering (Satori + resvg), not a headless browser. Response times are typically under 200ms. Social platforms cache the image after the first request, so subsequent shares are instant.
The OGPeek API
OGPeek exposes two endpoints. The free GET endpoint is perfect for getting started. The POST endpoint unlocks higher volume and removes the watermark.
GET endpoint (free tier)
curl
curl "https://ogpeek.com/api/v1/og\
?title=How+to+Generate+OG+Images+Automatically\
&subtitle=A+Practical+Guide+for+Developers\
&template=gradient\
&theme=midnight\
&brandColor=%23F59E0B" \
--output og.png
POST endpoint (paid plans)
curl
curl -X POST "https://ogpeek.com/api/v1/og" \
-H "x-api-key: ogp_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "How to Generate OG Images Automatically",
"subtitle": "A Practical Guide for Developers",
"template": "gradient",
"theme": "midnight",
"brandColor": "#F59E0B"
}' \
--output og.png
Available parameters
title— Primary text (required). Your blog post title.subtitle— Secondary text. Author name, date, or tagline.template— One ofbasic,gradient,split,hero.theme— One ofdark,light,midnight,forest,sunset.brandColor— Hex color for accent elements (URL-encode the#as%23).
Integration: Next.js App Router
Next.js 14 and 15 use the App Router's generateMetadata function for dynamic meta tags. This is the cleanest way to generate automatic open graph images for every route.
app/blog/[slug]/page.tsx
import { Metadata } from 'next';
type Props = { params: { slug: string } };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const post = await getPostBySlug(params.slug);
const ogImageUrl = new URL('https://ogpeek.com/api/v1/og');
ogImageUrl.searchParams.set('title', post.title);
ogImageUrl.searchParams.set('subtitle', post.author);
ogImageUrl.searchParams.set('template', 'gradient');
ogImageUrl.searchParams.set('theme', 'midnight');
ogImageUrl.searchParams.set('brandColor', '#F59E0B');
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{
url: ogImageUrl.toString(),
width: 1200,
height: 630,
alt: post.title,
}],
},
twitter: {
card: 'summary_large_image',
title: post.title,
images: [ogImageUrl.toString()],
},
};
}
Why URL constructor? Using new URL() with searchParams.set() handles encoding automatically. No manual encodeURIComponent() calls, no broken # symbols in brand colors.
Integration: Astro
Astro's component-based architecture makes OG image automation straightforward. Create a reusable layout component that builds the OG URL from frontmatter.
src/layouts/BlogPost.astro
---
const { title, description, author } = Astro.props;
const ogParams = new URLSearchParams({
title,
subtitle: author || 'My Blog',
template: 'gradient',
theme: 'midnight',
brandColor: '#F59E0B',
});
const ogImageUrl = `https://ogpeek.com/api/v1/og?${ogParams}`;
---
<html lang="en">
<head>
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImageUrl} />
<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={ogImageUrl} />
</head>
<body>
<slot />
</body>
</html>
Every blog post that uses this layout gets an automatic OG image. Write a new Markdown file, and the image generates itself from the frontmatter title.
src/content/blog/my-post.md
---
title: "Automatic OG Images Are a Game Changer"
description: "How I stopped wasting time in Figma."
author: "Jane Developer"
layout: ../../layouts/BlogPost.astro
---
Your blog content here...
Integration: Hugo
Hugo uses Go templates. Create a partial that generates the OG image URL from page variables, then include it in your base template.
layouts/partials/og-image.html
{{ $title := .Title }}
{{ $subtitle := .Site.Title }}
{{ $brandColor := "%23F59E0B" }}
{{ $template := "gradient" }}
{{ $theme := "midnight" }}
{{ $ogUrl := printf "https://ogpeek.com/api/v1/og?title=%s&subtitle=%s&template=%s&theme=%s&brandColor=%s"
(querify "" $title | strings.TrimPrefix "=")
(querify "" $subtitle | strings.TrimPrefix "=")
$template
$theme
$brandColor
}}
<meta property="og:image" content="{{ $ogUrl }}" />
<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="{{ $ogUrl }}" />
A simpler approach that works for most Hugo sites:
layouts/partials/og-image-simple.html
{{ $ogUrl := printf "https://ogpeek.com/api/v1/og?title=%s&subtitle=%s&template=gradient&theme=midnight&brandColor=%%23F59E0B"
(urlquery .Title)
(urlquery .Site.Title)
}}
<meta property="og:image" content="{{ $ogUrl }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
Then in your baseof.html:
<head>
...
{{ partial "og-image.html" . }}
</head>
Every page on your Hugo site now gets a unique OG image generated from its title. Zero manual work per post.
Pricing: Free Tier and Paid Plans
OGPeek is designed to let you start for free and scale when you need to.
| Plan | Price | Volume | Features |
|---|---|---|---|
| Free | $0 | 50 images/day | All templates, small watermark |
| Pro | $9/mo | 5,000 images/mo | No watermark, API key, priority rendering |
| Business | $29/mo | 50,000 images/mo | No watermark, custom fonts, webhook notifications |
The free tier is enough for personal blogs and side projects. At 50 images per day, you can serve a site with hundreds of pages—social platforms cache images after the first request, so the same URL rarely generates more than once.
The $9/mo Pro plan removes the watermark and gives you an API key for the POST endpoint. This is the right choice for professional blogs, startup landing pages, and SaaS documentation sites.
The $29/mo Business plan is built for content-heavy sites and platforms where users generate shareable pages (think: dashboards, portfolios, event pages).
Testing Your OG Images
After integrating, verify that everything renders correctly before sharing:
- Facebook Sharing Debugger — Paste your URL at developers.facebook.com/tools/debug. Click "Scrape Again" to force a fresh fetch.
- Twitter Card Validator — Use cards-dev.twitter.com/validator to preview your card.
- Open Graph Preview — Check the rendered image at
https://ogpeek.com/api/v1/og?title=Your+Titledirectly in your browser. - LinkedIn Post Inspector — Use linkedin.com/post-inspector to verify LinkedIn renders your card correctly.
Common pitfall: Social platforms aggressively cache OG images. If you change the title and the old image still shows, append a cache-busting parameter: &v=2. Or wait 24 hours for the cache to expire.
Best Practices for Automatic OG Images
After generating OG images for thousands of blog posts, here is what works:
- Keep titles under 60 characters. Longer titles get truncated or shrunk to unreadable sizes. Write a shorter OG-specific title if your blog title is long.
- Use your brand color. Set
brandColorto your primary brand color so social cards are instantly recognizable in feeds. - Pick one template and stick with it. Consistency builds recognition. Do not use a different template for every post.
- Always include
og:image:widthandog:image:height. These meta tags tell social platforms the dimensions upfront so they can reserve layout space before fetching the image. - Use subtitle for context. The subtitle field is a good place for your blog name, author, or publication date.
Why Not Build Your Own?
You absolutely can. Vercel's Satori library is open source and the rendering pipeline is well-documented. But building your own means:
- Setting up a serverless function or dedicated endpoint
- Installing and configuring Satori + resvg (or a headless browser)
- Designing templates from scratch
- Handling font loading, caching, and error cases
- Maintaining the infrastructure over time
For most developers, the 4-8 hours of setup time is not worth it when an API handles everything for $9/mo. If you have specific design requirements that go beyond parameter-based templates, building your own makes sense. For standard blog OG images, an API is the pragmatic choice.
Start generating OG images automatically
Try the free tier right now. No signup, no API key, no credit card. Just a URL.
Open the playground →Conclusion
Generating OG images automatically removes a tedious, repetitive task from your publishing workflow. Instead of opening Figma every time you write a blog post, you define the image as code and let the API render it on demand.
The setup takes less than five minutes for any framework. Next.js, Astro, Hugo—the pattern is always the same: build a URL from your page title, set it as the og:image meta tag, done. Every new post gets a branded social preview card without any manual work.
Start with the free tier (50 images/day), and upgrade to Pro when you need to remove the watermark or increase volume.