Every shared link renders a preview card, and one static og:image wastes it. This developer guide shows how to generate dynamic OG images from your real app data — a typed 1200 × 630 template, idempotent renders, validated batches and cache-safe URLs.
Why one static og:image is not enough
A dynamic OG image is generated per page from your real app data — title, author, price or chart — by rendering a template at publish time or on request, and serving the result as that page's og:image URL. A single static file cannot reflect page-specific data, and a generic logo fallback wastes the most visible pixel area of every shared link.
The preview card is effectively your ad slot in chats, feeds and search surfaces. When a reader shares a product page, a docs article or a public report, the card is usually the only context the next reader sees. Marketing teams notice quickly: they ask for per-page visuals, someone exports them by hand, the data changes, and the previews go stale. That loop is exactly what a small render pipeline removes.
What the Open Graph protocol actually expects
The Open Graph protocol defines four required properties for any page that should render as a rich object, plus optional structured properties for the image itself:
| Property | Required | Purpose |
|---|---|---|
og:title | Yes | The object's title as it should appear in the graph |
og:type | Yes | The object type, e.g. website or article |
og:image | Yes | An image URL that represents the object |
og:url | Yes | The canonical URL used as the object's permanent ID |
og:image:width / og:image:height | Recommended | Pixel dimensions, so scrapers can lay out the card |
og:image:alt | Recommended | A description of the image content (not a caption) |
Two practical notes for rendering pipelines: the specification also allows og:image:secure_url and og:image:type, so declare what you serve; and pick one card size and stick to it. A 1200 × 630 landscape card is a common choice for link previews — it is also the size of the image project in JsonCut's API quickstart, which is what the pipeline below builds on.
Three architectures for og:image generation
| Approach | How it works | Strengths | Watch-outs |
|---|---|---|---|
| Static fallback | One uploaded file serves every page | Trivial, zero latency | No page relevance; goes stale as data changes |
| Render-on-request | An endpoint composes the image when a scraper asks | Always reflects current data | Cold starts and timeouts under scraper load; caching becomes your problem |
| Template pipeline | A typed template is published once; each page renders at publish or save time, and the artifact URL is stored | Deterministic output, validated inputs, cache-friendly | Needs one pipeline step plus artifact storage |
The template pipeline is the one that scales honestly: the design is approved once, the data contract is explicit, and every render is reproducible. If you are new to the concept, the typed templates documentation describes the input contract, and our earlier article on dynamic image generation without brittle templates covers why ad-hoc HTML-to-image scripts break down. Planning the input fields carefully matters just as much as the design — see template input design: text, prices, images and badges.
A four-step pipeline, from design to og:image
1. Design the card once. Build a 1200 × 630 image project with the fixed brand layers locked down and the variable parts exposed as inputs: title, kicker, accentColor, maybe an author photo as a media input. Design it visually in Studio or code-first via the quickstart project format; either way the result stays editable.
2. Publish it as a template. Publishing pins a version and produces a typed input contract. The inputs endpoint reports required fields, types, constraints and accepted MIME types — string, number, boolean, color, image and bounded flat arrays are supported — so no consumer has to guess field names.
3. Render per page, idempotently. When content is published or updated, render one variant with an idempotency key derived from the page:
curl -X POST "$JSONCUT_API/api/v2/templates/$TEMPLATE_ID/renders" \
-H "X-API-Key: $JSONCUT_API_KEY" \
-H "Idempotency-Key: docs-page-og-4821" \
-H "Content-Type: application/json" \
-d '{"values":{"title":"Dynamic OG images from your app data","kicker":"Developer guides"},"kind":"image","format":"webp","imageQuality":92}'
Renders are asynchronous — they move through queued, rendering and completed or failed states — and the quickstart recommends signed webhooks over frequent polling in production. Image output supports PNG, JPEG and WebP, with a quality setting such as imageQuality: 92.
4. Store the artifact and version the URL. Serve the rendered file from your CDN or storage, set og:image to that URL, and include the structured width/height and alt properties. Most social scrapers cache previews aggressively, so changing the image URL (for example, appending the content version) is the reliable way to bust that cache after an update.
For launches and section-wide redesigns, you do not have to loop over single renders: JSON and CSV batches are capped at 500 rows, every row is validated against the pinned template version before queueing, and invalid rows are reported with their index without preventing valid rows from rendering. Regenerating a whole docs section becomes one auditable batch.
Failure modes a typed contract prevents
| Failure | Typical cause | Prevention |
|---|---|---|
| Text overflows the card | Unbounded titles | Constrain the title input; define truncation in the template; test with worst-case strings |
| Broken avatar or logo | Wrong MIME type or dead URL | The input contract lists accepted MIME types; validate media before rendering |
| Blank or generic preview | Missing data fields | Required-field validation; an optional fallback layer that hides when data is absent |
| Stale preview after an edit | Scraper caches the old image | Version the og:image URL with the content version |
| One bad row blocks a batch | All-or-nothing rendering | Per-row validation isolates invalid rows; valid rows still render |
Where 2026's generation models fit
Generation models are useful for the base layer of a preview card, not for its data typography. Google's Nano Banana 2 (announced February 26, 2026) brought precision text rendering and subject consistency at resolutions from 512 pixels to 4K, and Meta's Muse Image (announced July 7, 2026) added agentic tool use and precise reference-based editing. Both are strong at producing a hero visual or background texture that seeds your template.
Keep the parts that must be exact — the page title, the price, the date — in the deterministic template layer, where a render either matches the contract or fails validation. That division also keeps generated assets replaceable: when a model improves, you swap the background layer without touching the input contract. If an assistant should draft or iterate these visuals, the MCP workflow for AI assistants describes the review loop before any final render.
FAQ
What size should a dynamic OG image be?
A 1200 × 630 landscape card is a common, safe choice for link previews, but there is no single mandated size in the protocol. Declare og:image:width and og:image:height so scrapers can lay out the card correctly, and test with the platforms your audience actually uses.
Should I render at publish time or when the scraper requests the image? Publish-time rendering with a stored URL is easier to operate: it is cache-friendly, deterministic and keeps scraper traffic away from your render stack. On-request rendering only pays off when the underlying data changes faster than content is republished.
Can AI-generated images be used as og:image? Yes, as the base visual. Generate the background or hero art with a model, import it as a media input, and let the template render title and data deterministically on top — that combination keeps previews on-brand without hand-exporting every page.
Sources
https://ogp.me/ — The Open Graph protocol, required properties and structured image properties (retrieved 2026-10-08)
https://jsoncut.com/docs/templates/ — JsonCut typed templates, input contract, renders and 500-row bulk batches (retrieved 2026-10-08)
https://jsoncut.com/docs/quickstart/ — JsonCut project quickstart, 1200 × 630 example, render flow, webhook recommendation (retrieved 2026-10-08)
https://blog.google/innovation-and-ai/technology/ai/nano-banana-2/ — Google, "Nano Banana 2", February 26, 2026 (retrieved 2026-10-08)
https://ai.meta.com/blog/introducing-muse-image-muse-video-msl/ — Meta AI, "Introducing Muse Image and Muse Video", July 7, 2026 (retrieved 2026-10-08)