Every OG image guide walks you through making a card — ours included. Design it, export it, point a meta tag at it. Baked into those instructions is an assumption nobody states: that the thing the card describes holds still. A landing page does. Most things worth sharing don't:
- A product card whose price has changed twice since launch
- A podcast episode card — a new one every week, forever
- A job post with a salary band and an "actively hiring" badge that will eventually need to say "closed"
- A programmatic SEO site, ten thousand landing pages, each wanting its own card
- A weekly metrics page whose entire point is this week's numbers
You can hand-make cards for any of these. You'll be doing it again next week. The interesting question is what replaces the treadmill, because the first answer most teams reach for carries a quiet flaw.
The pipeline everyone builds first
The obvious architecture goes: data changes → webhook fires → render a new image → upload to storage → point the meta tag at it. Four steps. Two of them fail in ways you notice weeks later.
Who fires the webhook? Every path that can change a price now has to remember to trigger a re-render. The CMS edit remembers. The bulk import script doesn't. The admin's late-night manual database fix definitely doesn't. One forgotten trigger at a time, the cards drift away from reality.
Who busts the caches? The refreshed image usually ships at the same
URL — og/product-42.png — and social crawlers, as covered in
the sizing guide, cache by URL and
hold on for days. Your bucket has the new image. LinkedIn shows the old
one. You built the whole pipeline and lost anyway.
The two failures share one root: the image is a stored artifact that stays correct only through discipline. Discipline doesn't scale.
Turn the image into a function
Here's the pattern that deletes both failure modes: stop storing images. Declare the image as a URL whose parameters are the data, and let it render on demand:
<meta property="og:image" content=
"https://api.shotium.com/v1/og-image?template=product&title=Standing%20Desk&price=%24449&uid=...&sig=...">
What that one line buys, property by property:
Nothing renders until someone looks. The first crawler to fetch the URL triggers the render, and the result caches at the CDN edge. Ten thousand programmatic pages don't cost ten thousand renders up front — they cost renders for the pages people actually share.
Data changed? The URL changed. Your page template already knows the current price; it prints it into the meta tag the same way it prints it into the page body. New price, new URL — and a new URL is a new cache key everywhere at once, our edge and the social crawlers alike. The stale-cache problem from the naive pipeline isn't solved. It stops existing. This is the versioned-URL trick taken to its logical end: the version is the data.
No key in the page. The URL carries an HMAC signature proving the parameters weren't tampered with, which makes it safe to print into public HTML. No API key appears anywhere, and nobody can edit your query params to turn your card into their free rendering service.
Repeat shares are free. Same data, same URL, same cache key, edge hit. A render gets paid for when the card's content is genuinely new — which is exactly the moment you'd want a fresh image anyway.
The mental shift is small and total at once: the OG image stops being a file you keep in sync and becomes a deterministic function of your data — evaluated lazily, cached by its own arguments.
What this looks like in practice
Generating the signed URL server-side amounts to a canonical query string and one HMAC. The docs carry copy-paste implementations in Node and Python; inside a workflow engine it's the Generate Signed URL operation of our n8n node, computed locally, no API call involved.
The five built-in templates cover the recurring shapes: product with a price pill, podcast episode with cover art, event with date and location, blog post with author, minimal title card. Each takes typed parameters — which is the whole point. Parameters are the moving parts, and the moving parts are what gets signed.
Where the pattern doesn't apply
The honesty section. Two cases where this is the wrong reach:
- A static site with a handful of pages. One hand-designed card per page beats any pipeline. Nothing here earns its complexity at that scale.
- Genuinely real-time data. The card renders when a crawler first fetches it, and platforms cache what they saw. A share is a snapshot, not a live feed. "This week's numbers" works beautifully; "this second's stock price" is a promise no OG image can keep.
Between those poles sits everything that changes on the cadence of edits, releases, or weeks — and that's where data-driven cards quietly outwork hand-made ones.
Testing the claim costs nothing: sign up, take the 100 free renders, and wire one template into the page whose card you're most tired of regenerating. If the meta tag prints your data today, it prints your card from now on.