API Reference

Open Graph

Screenshot any URL or render from a template — both endpoints return a cached image in under 200 ms on repeat requests.

GET /render

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_…
ParamDefaultDescription
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.
Host allowlist: if ALLOWED_HOSTS is configured (comma-separated exact hostnames), requests to unlisted hosts return 403 host_not_allowed:<host>. Empty means allow-all.

GET /template/:name

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_…
ParamDefaultDescription
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.
Shipped templates: 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.

Template structure

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" }
    ]
  }
}
typeElement tag: div, span, img, p, h1h6.
twTailwind classes (Satori subset). Containers with more than one child must include flex. Supports {{name}} interpolation.
textLeaf text content. {{name}} interpolates from query params.
srcImage source URL for img elements. Supports {{name}} interpolation.
whenConditional render — node is dropped when the named param is missing or empty string.
styleInline CSS object (fallback for things the Tailwind subset doesn't cover). String values support {{name}} interpolation — useful for dynamic colors.
childrenNested node array.
defaultsPer-param fallback values applied when the request omits them or passes an empty string.

API keys

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
Enforcement is in transition. Requests without a valid key currently receive a placeholder SVG image rather than an HTTP error. Hard enforcement (401/403) will be enabled once all callers have migrated.

Cache behaviour

Both endpoints share the same KV-backed cache with a 30-day TTL.

ScenarioResult
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.
HTTP responses carry Cache-Control: public, max-age=31536000, immutable. Serve them through a CDN or directly — the KV cache is the source of truth.