Screenshot any URL or render from a template — both endpoints return a cached image in under 200 ms on repeat requests.
Navigates a headless Chrome to any URL and returns a screenshot. Results are cached in KV for 30 days. The cache key rolls over weekly so images stay fresh without manual cache-busting.
GET/render?url=https://example.com GET/render?url=https://example.com&format=png&w=1200&h=630 GET/render?url=https://example.com&selector=.og-card&api_key=ogsk_…
| Param | Default | Description |
|---|---|---|
| url | — | Target URL to screenshot. Must be a fully-qualified URL including scheme. |
| w | 1440 | Viewport width in pixels. Clamped to 1–4096. |
| h | 788 | Viewport height in pixels. Clamped to 1–4096. |
| dpr | 2 | Device pixel ratio — 1, 2, or 3. Higher values produce sharper images on HiDPI screens but increase file size. |
| format | jpeg | Output image format: jpeg, png, or webp. JPEG quality is fixed at 85. PNG and WebP use a transparent background. |
| selector | — | CSS selector to clip the screenshot to a single element. Falls back to full-page if the selector isn't found within 5 s. |
| scheme | — | Override the URL scheme before navigating — e.g. https. Useful when the url param omits the scheme. |
| digest | ISO week | Cache-key suffix. Defaults to YYYY-Www (rolls weekly). Pass any string to pin a specific render version. |
| force | — | Set force=1 to bypass the KV cache and always re-render. |
| api_key | — | API key for authenticated access. Also accepted as Authorization: Bearer <key>. See Authentication. |
| …extra params | — | Any other query params are forwarded to the target URL and baked into the cache key. Useful for auth tokens, feature flags, preview modes, etc. |
ALLOWED_HOSTS is configured (comma-separated exact hostnames),
requests to unlisted hosts return 403 host_not_allowed:<host>. Empty means allow-all.
Renders a saved Satori template to a PNG image. No browser needed — renders from a JSON tree in ~200 ms.
Always returns image/png. Missing a required param returns 400 with usage instructions.
GET/template/hero?title=Hello+World GET/template/hero?title=Hello&subtitle=World&eyebrow=My+Site GET/template/card?title=Post+Title&api_key=ogsk_…
| Param | Default | Description |
|---|---|---|
| w | template default | Output width in pixels. Clamped to 1–4096. |
| h | template default | Output height in pixels. Clamped to 1–4096. |
| dpr | 2 | Resvg zoom factor 1–3. Higher values produce sharper images. |
| digest | week + updatedAt | Cache-key suffix. Defaults to ISO week combined with the template's updatedAt timestamp — so edits in the admin UI automatically bust the cache. |
| force | — | Set force=1 to bypass the KV cache. |
| api_key | — | API key for authenticated access. Also accepted as Authorization: Bearer <key>. |
| …template params | — | All other query params are passed as template variables (e.g. title, subtitle). Required params are declared per-template; missing ones return 400. |
hero — dark bg, title + optional eyebrow & subtitle (1200×630, requires title) ·
card — light bg, title + subtitle + byline (1200×630, requires title) ·
promo — dynamic colors, feature bullets, CTA (requires title).
Manage all templates in the admin UI.
Templates are JSON objects defining a Satori node tree. Edit them live in the admin UI — no redeploy needed.
{
"name": "hero",
"defaultSize": { "w": 1200, "h": 630 },
"required": ["title"],
"sampleParams": { "title": "Hello", "subtitle": "World" },
"defaults": { "eyebrow": "My Site" },
"tree": {
"type": "div",
"tw": "flex h-full w-full flex-col justify-center bg-slate-950 text-white px-20",
"children": [
{ "type": "div", "tw": "text-2xl text-slate-400", "text": "{{eyebrow}}", "when": "eyebrow" },
{ "type": "div", "tw": "text-7xl font-bold", "text": "{{title}}" },
{ "type": "div", "tw": "text-4xl text-slate-300 mt-6", "text": "{{subtitle}}", "when": "subtitle" }
]
}
} div, span, img, p, h1–h6.flex. Supports {{name}} interpolation.{{name}} interpolates from query params.img elements. Supports {{name}} interpolation.{{name}} interpolation — useful for dynamic colors.
API keys control access to the image endpoints. Keys are ogsk_-prefixed 64-character hex strings managed in the admin UI.
# query param — works in <img src> tags /render?url=https://example.com&api_key=ogsk_abc123… # Authorization header curl -H "Authorization: Bearer ogsk_abc123…" /template/hero?title=Hello
Both endpoints share the same KV-backed cache with a 30-day TTL.
| Scenario | Result |
|---|---|
Default request (no digest) | Cache key includes the ISO week (YYYY-Www). Images roll over weekly automatically. |
Pinned digest=v2 | Cache key is locked to that string. The same image is served until you change the digest. |
| Template edited in admin UI | The default digest for /template/:name includes updatedAt, so saved edits automatically bust cached renders. |
force=1 | Skips the cache read. A new image is rendered and written back to KV. |
Cache-Control: public, max-age=31536000, immutable.
Serve them through a CDN or directly — the KV cache is the source of truth.