---
title: "How to Generate OG Images Dynamically with an API"
description: "Create unique Open Graph images for every page automatically. Tutorial covers Next.js, static sites, and CMS setups with working code examples included."
url: "https://www.imejis.io/blogs/tutorials/generate-og-images-dynamically"
published: "2026-02-04"
---

# How to Generate OG Images Dynamically with an API

Every link you share has an Open Graph image. Some look great. Most look like afterthoughts: generic logos or blank previews that blend into the social feed.

The difference? Dynamic generation.

Sites that generate OG images dynamically create unique visuals for every page. Blog posts get images with the actual title. Product pages show the product. Landing pages display the headline that matters. [News and media sites use this to generate article thumbnails](/blogs/industry/news-media-article-thumbnails) at scale, ensuring every story has a branded preview.

Here's how to set it up for your site.

## What Are OG Images and Why They Matter

Open Graph images are the preview thumbnails that appear when you share a link on Twitter, LinkedIn, Facebook, Slack, or iMessage. They're controlled by a meta tag in your HTML:

```html
<meta property="og:image" content="https://yoursite.com/images/preview.png" />
```

The problem? Most sites use one generic image for everything. Or worse, they don't use anything at all.

**Why dynamic OG images work:**

- 40% higher click-through rates on shared links (based on [Twitter's own research](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards))
- Brand recognition in crowded feeds
- Each page becomes share-ready without manual design
- Professional appearance that builds trust

If you publish content regularly, manual OG image creation doesn't scale. You'll burn hours on repetitive work that an API handles instantly. And the effort is worth it. [Images in blogging significantly improve user engagement](/blogs/images-in-blogging-user-engagement), and OG images are a big part of that. Curious about other approaches? Read our [Puppeteer vs Satori vs template API](/blogs/tutorials/puppeteer-vs-satori-vs-template-api) comparison.

## The Architecture: How It Works

Dynamic OG generation follows this pattern:

```text
Page Loads → Extract Title/Data → Call Image API → Return Image URL → Serve as OG Tag
```

You have two timing options:

### Build Time Generation

Generate images when your site builds. Best for static sites and blogs where content doesn't change after publish.

**Pros:** Fast page loads, no API calls on visit
**Cons:** Rebuilds needed for updates, higher build times

### Runtime Generation

Generate images on-demand when the OG image URL is requested. Best for dynamic content and large sites.

**Pros:** Always current, no build dependency
**Cons:** First request slightly slower, requires caching

For most sites, build time works better. Runtime makes sense when you have thousands of pages or frequently changing content.

## Method 1: Next.js with API Routes

Next.js makes this straightforward with API routes that generate images on request.

### Step 1: Create the API Route

Create a file at `app/api/og/route.ts` (App Router) or `pages/api/og.ts` (Pages Router):

```typescript
// app/api/og/route.ts
import { NextRequest } from "next/server"

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url)
  const title = searchParams.get("title") || "Default Title"

  // Call Imejis.io API
  const response = await fetch(
    `https://render.imejis.io/v1/your-og-template-id`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.IMEJIS_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ title }),
    }
  )

  const data = await response.json()

  // Redirect to the generated image
  return Response.redirect(data.url, 302)
}
```

### Step 2: Add the Meta Tag

In your page component:

```typescript
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)

  return {
    openGraph: {
      images: [
        {
          url: `/api/og?title=${encodeURIComponent(post.title)}`,
          width: 1200,
          height: 630,
        },
      ],
    },
  }
}
```

Now every blog post gets a unique OG image with its title.

### Step 3: Add Caching

Generating the same image repeatedly wastes API calls. Add caching:

```typescript
// Add to your API route
export const revalidate = 86400 // Cache for 24 hours
```

Or use a more sophisticated caching strategy with Redis or your CDN's edge caching.

## Method 2: Static Site Generators

For Astro, Hugo, Eleventy, or other static generators, generate images at build time.

### Astro Example

```javascript
// src/pages/og/[...slug].png.ts
import type { APIRoute } from "astro"
import { getCollection } from "astro:content"

export async function getStaticPaths() {
  const posts = await getCollection("blog")
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { title: post.data.title },
  }))
}

export const GET: APIRoute = async ({ props }) => {
  const response = await fetch(
    "https://render.imejis.io/v1/your-og-template-id",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${import.meta.env.IMEJIS_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ title: props.title }),
    }
  )

  const data = await response.json()
  const imageResponse = await fetch(data.url)

  return new Response(await imageResponse.arrayBuffer(), {
    headers: { "Content-Type": "image/png" },
  })
}
```

The image generates during build and gets served as a static file.

## Method 3: Headless CMS Integration

If your content lives in a CMS like Contentful, Sanity, or Strapi, trigger image generation when content publishes.

### Webhook Approach

1. Set up a webhook that fires on content publish
2. Webhook calls your image generation endpoint
3. Generated image URL saves back to the CMS
4. Your site reads the URL from the CMS

```javascript
// Webhook handler (Vercel Function, AWS Lambda, etc.)
export async function handleContentPublish(content) {
  // Generate the OG image
  const response = await fetch(
    "https://render.imejis.io/v1/your-og-template-id",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.IMEJIS_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        title: content.title,
        author: content.author,
        category: content.category,
      }),
    }
  )

  const { url } = await response.json()

  // Save URL back to CMS
  await updateContentInCMS(content.id, { ogImage: url })
}
```

This approach pre-generates images so page loads stay fast. Learn more about [automating social media images](/blogs/tutorials/automate-social-media-images) with similar workflows. If your site runs on Webflow, see our dedicated [Webflow image API integration](/blogs/integrations/webflow-image-api-integration) guide for platform-specific setup.

## Designing Your OG Template

A good OG template includes:

**Required elements:**

- Title text (dynamic, editable via API)
- Your logo or brand mark (static)
- Background that works at any size

**Optional elements:**

- Author name or avatar
- Category or tag
- Reading time
- Publish date

### Design Specifications

OG images display at different sizes across platforms:

| Platform | Display Size | Recommended |
| -------- | ------------ | ----------- |
| Twitter  | 800x418px    | 1200x628px  |
| Facebook | 1200x630px   | 1200x630px  |
| LinkedIn | 1200x627px   | 1200x628px  |
| Slack    | 500x250px    | 1200x628px  |

**Always create at 1200x630px**. It's the standard that works everywhere. Check our [template library](/templates) for OG-specific designs.

### Text Handling

Long titles break layouts. Build your template to handle:

- Short titles (3-5 words)
- Medium titles (8-12 words)
- Long titles (15+ words with truncation)

Test with your longest realistic headline before deploying.

## Common Issues and Fixes

### Images Not Updating

Social platforms cache OG images aggressively. To force refresh:

- **Twitter/X:** Post a link in a draft tweet to preview the card (the standalone Card Validator was discontinued)
- **Facebook:** Use the [Sharing Debugger](https://developers.facebook.com/tools/debug/)
- **LinkedIn:** Add `?v=2` to your image URL to bust cache

### Wrong Image Dimensions

If images appear cropped or distorted, check your template dimensions. The 1200x630px ratio (1.91:1) is critical.

### Slow Generation

If images take too long:

1. Pre-generate during build instead of runtime
2. Add CDN caching (Cloudflare, Vercel Edge)
3. Use a simpler template with fewer elements

### API Errors

Wrap your image generation in error handling with a fallback:

```typescript
async function getOGImage(title: string): Promise<string> {
  try {
    const response = await fetch(/* ... */)
    const data = await response.json()
    return data.url
  } catch (error) {
    console.error("OG image generation failed:", error)
    return "/images/default-og.png" // Fallback
  }
}
```

Never let a broken OG image break your page.

## Measuring Impact

Track these metrics before and after implementing dynamic OG images:

**Social engagement:**

- Click-through rate on shared links
- Share counts per post
- Social referral traffic

**Brand metrics:**

- Visual consistency scores
- Brand mention sentiment

Most sites see measurable improvement within the first month. See [10 ways businesses use image APIs](/blogs/use-cases/10-ways-businesses-use-image-apis) for more examples of the impact.

## FAQ

### Do I need a different OG image for each social platform?

No. One 1200x630px image works across all major platforms. Twitter, Facebook, LinkedIn, and Slack all accept this size.

### How much does dynamic OG generation cost?

With [Imejis.io](/pricing), you pay per image generated. At $0.015 per image on the Basic plan, generating 1,000 OG images costs $15/month. Caching reduces this significantly. _Pricing reflects published rates as of July 2026; check the provider's site for current plans._

### Can I include emojis in OG titles?

Yes, if your template font supports them. Test specific emojis before deploying, as some render differently across platforms.

### What happens if the API is slow or down?

Always have a fallback image. Your site should work without the dynamic image, just with a generic preview instead.

### Should I regenerate OG images when I update content?

For title or major visual changes, yes. Minor edits usually don't warrant regeneration. Build logic to detect significant changes.

## Start Generating

The setup takes an afternoon. The benefit lasts as long as your site exists.

Start here:

1. Create an OG template in [Imejis.io](https://www.imejis.io)
2. Add the API integration to your framework
3. Update your meta tags to use dynamic URLs
4. Test with social platform debugging tools
5. Deploy and share

Every page you publish from now on gets a professional, branded preview image automatically.

[Get started with Imejis.io →](https://www.imejis.io)
