TL;DR
- → Generate unique OG images for every post, product, or user profile via a REST API
- → Write once in HTML, render consistently every time via headless Chrome
- → 1 token per image (~$0.016). 500 OG images costs less than $10
HTML to Image API — OG Image Generation
Open Graph images determine how your links look on Twitter, LinkedIn, Slack, and iMessage. A unique, well-designed OG image can 2–3× your click-through rate. The problem: generating them manually for every post or product doesn't scale. The solution: an HTML template and one API call.
Why HTML → PNG for OG images?
- Consistent — the same template produces the same design every time, across all content types
- Programmable — loop over your entire blog archive and generate all images in minutes
- Maintainable — update the template once and all future images reflect the new design
- No Puppeteer infra — no headless Chrome servers to manage; AgentGen handles the rendering
Step 1 — Design your template
Write the OG image as a 1200×630 HTML div with inline styles. Include a gradient background, your tag/category pill, the title, and author line:
def og_template(title: str, author: str, date: str, tag: str) -> str:
return f"""
<div style="
width:1200px; height:630px;
background:linear-gradient(135deg,#1e1b4b,#312e81);
display:flex; flex-direction:column;
justify-content:center; padding:80px;
font-family:'Inter',sans-serif; color:white;
box-sizing:border-box;
">
<span style="
background:rgba(99,102,241,0.3); color:#a5b4fc;
padding:6px 16px; border-radius:999px;
font-size:14px; width:fit-content; margin-bottom:24px;
">{tag}</span>
<h1 style="
font-size:54px; font-weight:800;
line-height:1.1; margin:0 0 24px; max-width:900px;
">{title}</h1>
<p style="font-size:20px; color:#a5b4fc; margin:0">
{author} · {date}
</p>
</div>
"""Step 2 — Call the API
import os, requests
def generate_og_image(title: str, author: str, date: str, tag: str) -> str:
"""Render an OG image and return a permanent CDN URL."""
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, tag),
"width": 1200,
"height": 630,
"format": "png",
},
timeout=30,
)
r.raise_for_status()
return r.json()["url"]
# Single image
url = generate_og_image(
title="How to Build an AI Invoice Generator",
author="Yair Levi",
date="March 2026",
tag="Tutorial",
)
print(url) # https://cdn.agent-gen.com/output/abc123.pngStep 3 — Generate in bulk with asyncio
import asyncio, aiohttp, os
async def generate_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["tag"]),
"width": 1200, "height": 630, "format": "png",
},
) as resp:
data = await resp.json()
return post["slug"], data["url"]
async def backfill_all_og_images(posts: list[dict]) -> dict[str, str]:
async with aiohttp.ClientSession() as session:
results = await asyncio.gather(
*(generate_og_async(session, p) for p in posts)
)
return dict(results) # {slug: image_url}
# Backfill 500 blog posts concurrently
og_urls = asyncio.run(backfill_all_og_images(all_posts))Integrate with Next.js
Call generate_og_image() at build time in generateStaticParams, or on-demand in a Route Handler. Cache the resulting URL in your database to avoid re-generating on every request.
500 OG images = 500 tokens = less than $10 at any tier. Tokens never expire, so you can backfill your entire archive and use leftover tokens for future posts.
Generate your first OG image in 2 minutes
50 free tokens on signup — that's 50 unique OG images at no cost.