GET /og — OG Image API
Generate Open Graph images from a signed URL. Public endpoint, no API key required.
Endpoint
GET https://api.renderog.app/og
Request Parameters
| Parameter | Type | Default | Limits | Notes |
|---|---|---|---|---|
template |
string | — | basic, gradient, blog, product |
Required |
title |
string | — | ≤200 chars | Required, the main text |
subtitle |
string | — | optional | Secondary text (template-dependent) |
description |
string | — | optional | Longer text, used by some templates |
theme |
string | dark |
light, dark |
Color scheme |
w |
int | 1200 |
100–2400 | Width in pixels |
h |
int | 630 |
100–1260 | Height in pixels |
format |
string | png |
png, webp, avif, svg |
Output format |
expires |
int | — | unix seconds | Optional; if set, signature must include this and must be in the future |
sig |
string | — | hex, 64 chars | HMAC-SHA256 signature (required) |
Response
Status 200 (success):
Content-Type:image/png,image/webp,image/avif, orimage/svg+xmlContent-Length: size in bytesCache-Control: public, s-maxage=31536000, immutable— cached at edge for 1 yearX-Render-Ms: milliseconds to render (≤100ms cached, ≤500ms cold)X-Cache:HITorMISS
Status 400 (invalid params):
{ "error": { "code": "invalid_params", "message": "..." } }
Not billed. Check title length, dimensions, template name.
Status 403 (signature invalid/expired):
{ "error": { "code": "invalid_signature", "message": "..." } }
Not billed. Verify signature calculation and that expires (if set) is a future unix timestamp.
Status 422 (render failed):
{ "error": { "code": "render_failed", "message": "..." } }
Not billed. Usually invalid CSS or template HTML. Test with a simple template first.
Status 429 (rate limited):
{ "error": { "code": "rate_limited", "message": "..." } }
Not billed. Includes Retry-After header. Free: 60/min, Paid: 600/min.
Signing
All /og requests must be signed with HMAC-SHA256:
- Collect all parameters except
sig - Sort alphabetically by key
- URL-encode each value
- Join with
&:key1=value1&key2=value2... - Compute
sig = HMAC-SHA256(SIGNING_SECRET, canonical)and encode as hex - Append to URL:
...&sig=<sig>
Example (canonical):
format=png&h=630&template=basic&theme=dark&title=Hello&w=1200
(Note: sig is excluded, everything else sorted alphabetically)
If expires is set, it must be included in the signature:
expires=1700000000&format=png&h=630&template=basic&theme=dark&title=Hello&w=1200
Templates
basic
Clean, minimal layout. Left-aligned text with accent color.
Example:
https://api.renderog.app/og?template=basic&title=My%20Startup&subtitle=Build%20fast&theme=dark&sig=...
title: Required, large headingsubtitle: Optional, smaller secondary text- Colors: White on dark background (default), or dark on light (if
theme=light)
gradient
Modern gradient background with centered text.
Example:
https://api.renderog.app/og?template=gradient&title=Ship%20It&description=Fast%20deployments&theme=dark&sig=...
title: Requireddescription: Optional, line-wrapped body texttheme: Affects gradient colors and text contrast
blog
Article-style layout with byline and date placeholders.
Example:
https://api.renderog.app/og?template=blog&title=Next.js%2015%20is%20Here&subtitle=What%27s%20New&theme=dark&sig=...
title: Article headlinesubtitle: Byline or publication namedescription: Summary text (optional)
product
Product-card layout with icon placeholder and feature list.
Example:
https://api.renderog.app/og?template=product&title=RenderOG&subtitle=OG%20Images%20at%20the%20Edge&theme=light&sig=...
title: Product namesubtitle: Taglinedescription: Bullet-point features (optional)
Caching Behavior
Every OG image is cached at Cloudflare's edge for 1 year (s-maxage=31536000). The cache key is the full URL including query parameters.
First render (MISS): 50–100ms depending on image complexity and font subsetting. Cached render (HIT): <5ms.
Cache hits do not count toward your quota and are never billed.
Satori & CSS Constraints
OG images are rendered with Satori (React JSX → SVG → PNG). Templates are written as HTML/CSS strings, not JSX.
Supported CSS
- Flexbox layout (
display: flex,flex-direction,justify-content,align-items,gap,flex-wrap, etc.) - Sizing:
width,height,min-width,max-width,padding,margin,border-radius - Colors:
color,background-color,border(solid only) - Text:
font-size,font-weight(numerical: 400–900),letter-spacing,line-height,text-align,text-transform - Positioning:
absolute,relative(withtop,left,right,bottom)
Not Supported
- Grid (
display: griddoes not work) calc()— use fixed dimensionsvar()or custom properties — inline values only- System fonts — must pass font data explicitly (Inter subset is bundled)
- Remote image URLs — Satori's internal fetch fails on Workers; fetch images in the route handler and inline as base64 data URIs
- Transforms (
transform: rotate(),skew, etc.) - Filters (
filter: blur(), etc.) - Animations — static renders only
Fonts
Built-in: Inter (latin + cyrillic subset, weights 400–700, @font-face included).
For other fonts, pass base64-encoded TTF/OTF data at template render time (API key route). Standard web fonts (Google Fonts, etc.) are accessible via @font-face if you inline the url() as a base64 data URI.
Examples
Minimal OG (curl)
curl "https://api.renderog.app/og?template=basic&title=Hello%20World&w=1200&h=630&sig=abc123def456..."
With Expiry
Signature includes expires (unix seconds, ~1 hour from now):
https://api.renderog.app/og?expires=1723000000&format=png&h=630&template=basic&title=Hello&w=1200&sig=...
If current time > expires, the API returns 403 expired.
Different Format
https://api.renderog.app/og?template=blog&title=Article&format=webp&sig=...
Light Theme
https://api.renderog.app/og?template=product&title=RenderOG&theme=light&w=1200&h=630&sig=...
Performance Notes
- Cached renders: <5ms, served from Cloudflare's edge in your region
- Cold renders: 50–150ms depending on CSS complexity
- Max dimensions: 2400×1260 px (larger images take longer)
- Wasm initialization: Happens once per Worker instance, not per-request
- Font subsetting: Inter is pre-subset and bundled; custom fonts add ~10–30ms
Debugging
Not rendering? Use the Playground to preview before signing. Common issues:
- Empty or wrong text: Check
titleis provided and URL-encoded - Layout broken: Satori only supports flexbox. No grid, no
calc(). - Image not showing: Satori can't fetch remote images. Fetch and inline as data URI instead.
- Wrong colors: Double-check
themevalue and ensure CSS color values are valid hex/rgb.
See Error Codes for all status codes and meanings.