← All posts
·6 min read

OG Image Generation at Scale with AI Agents

Last Updated: March 2026

TL;DR

  • OG images can increase link click-through rates by 2–3× on social platforms
  • HTML-to-image APIs let you generate unique OG images for every post programmatically
  • AgentGen renders 1200×630 PNGs in under 1 second — 500 images for under $10

Why OG images matter

When your link is shared on Twitter, LinkedIn, or Slack, the platform fetches your <meta property="og:image"> tag and renders a preview card. A generic screenshot or a missing image gets ignored. A clean, branded card with the article title gets clicked.

The challenge: most sites have a single static OG image for the entire domain. Every shared link looks the same. Dynamic OG images — unique per page — can significantly lift click-through rates, but generating them manually for hundreds of posts is impractical.

The HTML-to-image approach

Instead of designing each image in Figma or Canva, write one HTML template and render it with different data for each page. The template handles layout, typography, and branding. You inject the title, author, date, and category. AgentGen renders it to a 1200×630 PNG via headless Chrome.

def og_template(title: str, author: str, date: str, category: str) -> str:
    # Truncate long titles gracefully
    display_title = title if len(title) <= 65 else title[:62] + "..."
    return f"""
    <div style="
      width:1200px; height:630px;
      background:linear-gradient(135deg,#1e1b4b 0%,#312e81 60%,#1e1b4b 100%);
      display:flex; flex-direction:column; justify-content:center;
      padding:80px; box-sizing:border-box; font-family:'Inter',sans-serif;
      color:white; position:relative; overflow:hidden;
    ">
      <!-- Background texture -->
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 70% 50%,
                  rgba(99,102,241,0.15),transparent 70%)"></div>

      <!-- Category pill -->
      <div style="background:rgba(99,102,241,0.25);border:1px solid rgba(165,180,252,0.3);
                  color:#a5b4fc;padding:6px 16px;border-radius:999px;font-size:14px;
                  font-weight:600;width:fit-content;margin-bottom:28px;letter-spacing:.03em">
        {category}
      </div>

      <!-- Title -->
      <h1 style="font-size:54px;font-weight:800;line-height:1.1;margin:0 0 28px;
                 max-width:900px;position:relative">{display_title}</h1>

      <!-- Author + date -->
      <div style="display:flex;align-items:center;gap:16px;position:relative">
        <div style="width:44px;height:44px;border-radius:50%;background:rgba(99,102,241,0.4);
                    display:flex;align-items:center;justify-content:center;font-weight:700;
                    font-size:16px">{author[0].upper()}</div>
        <div>
          <p style="margin:0;font-weight:600;font-size:18px">{author}</p>
          <p style="margin:0;color:#a5b4fc;font-size:15px">{date}</p>
        </div>
      </div>

      <!-- Logo / brand -->
      <div style="position:absolute;bottom:40px;right:60px;
                  font-size:16px;font-weight:700;color:rgba(255,255,255,0.4)">
        YourBlog.com
      </div>
    </div>
    """

Single image generation

import os, requests

def generate_og_image(title: str, author: str, date: str, category: str) -> str:
    r = requests.post(
        "https://www.agent-gen.com/api/v1/generate/image",
        headers={"X-API-Key": os.environ["AGENTGEN_API_KEY"],
                 "Content-Type": "application/json"},
        json={
            "html": og_template(title, author, date, category),
            "width": 1200, "height": 630, "format": "png",
        },
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["url"]

url = generate_og_image(
    "How to Build an AI Invoice Generator",
    "Yair Levi", "March 2026", "Tutorial"
)
# → https://cdn.agent-gen.com/output/abc123.png

Bulk generation — backfill your entire blog

import asyncio, aiohttp, os

async def gen_og_async(session: aiohttp.ClientSession, post: dict) -> tuple[str, str]:
    async with session.post(
        "https://www.agent-gen.com/api/v1/generate/image",
        headers={"X-API-Key": os.environ["AGENTGEN_API_KEY"]},
        json={
            "html": og_template(post["title"], post["author"],
                                post["date"], post["category"]),
            "width": 1200, "height": 630, "format": "png",
        },
    ) as resp:
        data = await resp.json()
        return post["slug"], data["url"]

async def backfill_og_images(posts: list[dict]) -> dict[str, str]:
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(*(gen_og_async(session, p) for p in posts))
    return dict(results)

# Backfill 500 posts concurrently
og_map = asyncio.run(backfill_og_images(all_posts))
# Save og_map to your DB — {slug: og_image_url}

Using the URL in Next.js

// In your blog post page, after generating and storing the URL:
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)
  return {
    openGraph: {
      title: post.title,
      images: [{ url: post.ogImageUrl, width: 1200, height: 630 }],
    },
    twitter: { card: "summary_large_image", images: [post.ogImageUrl] },
  }
}

Cost

Each image costs 1 token. 500 OG images = 500 tokens = $9 at Starter tier. A 2,500-post blog costs $39 at Growth tier. Images are stored for 30 days; re-generate when your design changes.

Get started free → — 50 tokens on signup, enough for 50 OG images to test your template.

Ready to start generating?

Create a free account and generate your first PDF or image in minutes.

Get started free