Get an API Key Demo

Dynamic OG Images

Auto-generate a unique social preview card for every page of your blog, SaaS, or e-commerce site.

The problem

When someone shares a URL on Twitter, LinkedIn, or Slack, the platform fetches the og:image meta tag and renders a preview card. A single static image doesn't scale — you need a unique, branded card for every blog post, product, or user profile.

The classic solutions are either slow (headless browser per request) or fragile (canvas hacks). StarkRender gives you a REST API: design your card once in HTML, save it as a template, and call the API with each page's data. You get back a permanent URL to use as og:image.


Step 1 — Design the card in HTML

The standard OG image size is 1200 × 630 px. Design your card as a self-contained HTML snippet. Use {{variable}} placeholders for the dynamic parts.

HTML Template
<div style="
  width:1200px; height:630px;
  background:#0f172a;
  display:flex; flex-direction:column;
  justify-content:flex-end;
  padding:60px;
  font-family:Inter, sans-serif;
  box-sizing:border-box;
">
  <p style="color:#94a3b8;font-size:20px;margin:0 0 16px">
    {{category}}
  </p>
  <h1 style="color:#fff;font-size:52px;font-weight:800;line-height:1.15;margin:0 0 28px">
    {{title}}
  </h1>
  <div style="display:flex;align-items:center;gap:16px">
    <img src="{{author_avatar}}" width="44" height="44"
         style="border-radius:50%;object-fit:cover">
    <div>
      <p style="color:#fff;font-size:18px;font-weight:600;margin:0">{{author_name}}</p>
      <p style="color:#64748b;font-size:16px;margin:4px 0 0">{{date}}</p>
    </div>
  </div>
  <div style="position:absolute;top:48px;right:60px;color:#C9952A;font-size:22px;font-weight:700">
    YourBrand
  </div>
</div>

Step 2 — Save the template (once)

Call POST /v1/template to store the HTML. You get back a template_id — save it in your environment config. You only need to do this once.

cURL
curl -X POST https://api.starkrender.com/v1/template \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Blog OG card", "html": "<!-- your template HTML -->"}'
Response
{
  "status":      "success",
  "template_id": "86c4dab7-6570-442a-9a46-74bb2a472aed"
}

Step 3 — Render per page

On each new post or page, call POST /v1/render with the template ID and the page's data. Pass device_scale: 2 for retina-quality output (Twitter and LinkedIn both support it).

Node.js

JavaScript
async function generateOgImage(post) {
  const res = await fetch('https://api.starkrender.com/v1/render', {
    method: 'POST',
    headers: {
      'x-api-key':     process.env.STARKRENDER_API_KEY,
      'Content-Type':  'application/json',
    },
    body: JSON.stringify({
      template_id:  '86c4dab7-6570-442a-9a46-74bb2a472aed',
      variables: {
        title:        post.title,
        category:     post.category,
        author_name:  post.author.name,
        author_avatar: post.author.avatarUrl,
        date:         post.publishedAt,   // e.g. "May 8, 2026"
      },
      width:        1200,
      height:       630,
      device_scale: 2,              // retina — 2400×1260px output
    }),
  });

  const { url } = await res.json();
  return url;   // persist this — point og:image here
}

Python

Python
import os, requests

def generate_og_image(post: dict) -> str:
    resp = requests.post(
        "https://api.starkrender.com/v1/render",
        headers={
            "x-api-key":    os.environ["STARKRENDER_API_KEY"],
            "Content-Type": "application/json",
        },
        json={
            "template_id":  "86c4dab7-6570-442a-9a46-74bb2a472aed",
            "variables": {
                "title":         post["title"],
                "category":      post["category"],
                "author_name":   post["author"]["name"],
                "author_avatar": post["author"]["avatar_url"],
                "date":          post["published_at"],
            },
            "width":        1200,
            "height":       630,
            "device_scale": 2,
        },
    )
    resp.raise_for_status()
    return resp.json()["url"]   # persist this — point og:image here

Step 4 — Wire up the meta tag

Store the returned URL alongside your post in the database. Then render it into your page's <head>.

HTML
<meta property="og:image"         content="https://api.starkrender.com/v1/image/uuid">
<meta property="og:image:width"   content="2400">
<meta property="og:image:height"  content="1260">
<meta name="twitter:card"         content="summary_large_image">
<meta name="twitter:image"        content="https://api.starkrender.com/v1/image/uuid">
ℹ️
The image URL is permanent — it won't change or expire. Cache it in your DB and only re-render when the post title or cover changes.

Tips

Generate on publish, not on request

Call the API when a post is created or updated — not on every page view. Store the returned URL in your database alongside the post. This keeps latency at zero for readers and avoids unnecessary renders.

Use device_scale: 2 for retina

Twitter, LinkedIn, and most modern scrapers support high-DPI images. Passing device_scale: 2 produces a 2400 × 1260 px image from a 1200 × 630 layout — sharper text and edges with no extra work on your end.

Long titles — clamp with CSS

Add overflow protection to your template so long titles don't break the layout:

CSS
h1 {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

Batch-generate for existing content

If you need to backfill OG images for existing posts, use POST /v1/render/batch to render up to 25 at once in a single request — all processed in parallel.

JavaScript
const res = await fetch('https://api.starkrender.com/v1/render/batch', {
  method: 'POST',
  headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    requests: posts.map(post => ({
      template_id:  TEMPLATE_ID,
      variables:    { title: post.title, category: post.category, ... },
      width:  1200, height: 630, device_scale: 2,
    })),
  }),
});

const { results } = await res.json();
// results[i].url → og:image for posts[i]
On This Page
The Problem Step 1 — Design the card Step 2 — Save the template Step 3 — Render per page Step 4 — Wire up the meta tag Tips