API reference
One endpoint. Every unique combination of parameters is rendered once and then cached.
Contents: Endpoint · Parameters · Templates · Examples · Caching · Limits · Errors · API keys · Other endpoints · Acceptable use · Privacy
Acceptable use: no impersonation, phishing or illegal content. Matching requests get 403 blocked_content and reported images are taken down.
Endpoint
GET https://ogforge.mike-tusa.workers.dev/api/og?template=blog&title=Hello%20world
Returns a 1200×630 PNG (Content-Type: image/png). HEAD is supported, and /og.png is an alias of /api/og for platforms that want a .png path. CORS is open (Access-Control-Allow-Origin: *) and images can be embedded from any site.
Parameters
All parameters are optional query-string values. URL-encode them. Unknown parameters are ignored and don't affect caching.
| Name | Type / limit | Description |
|---|---|---|
template (alias t) | blog | launch | docs | minimal | gradient | Layout. Default blog. |
title | text, 120 chars | Main headline. The font size shrinks for long titles, and anything over 3 lines is clipped with “…”. Default “Untitled”. |
subtitle (alias description) | text, 200 chars | Secondary line (max 2 lines shown). |
label (alias tag) | text, 40 chars | Category (blog), pill (launch), version (docs) or eyebrow (gradient). Not shown in minimal. |
site | text, 60 chars | Site or product name / domain. |
author | text, 60 chars | Author name (blog), or the breadcrumb section (docs). |
emoji | one emoji | Shown as the logo mark (Twemoji graphics). Ignored when logo loads. |
logo | https URL, 512 chars | PNG, JPEG or SVG, at most 300 KB, fetched with a 3 s timeout. Must be a public https:// hostname (no IPs, credentials or custom ports). If it can't be loaded, the image renders without it, is cached for only 5 minutes, and carries an X-OgForge-Warning header. |
theme | light | dark | Base palette. Defaults: blog/minimal light; launch/docs dark. |
bg | hex color | Background (0f172a, #0f172a or fff). For gradient it's the end color (default db2777). |
fg | hex color | Text color. If omitted with a custom bg, black or white is picked for contrast. |
accent | hex color | Accent bar, pills and highlights. For gradient it's the start color (default 6366f1). |
Text is cleaned (control characters removed, whitespace collapsed). Text longer than its limit is truncated with “…” rather than rejected, and the response carries X-OgForge-Truncated: title,subtitle. The whole query string may be at most 2,000 characters. Bundled fonts cover Latin scripts (incl. accents); other scripts aren't supported yet.
Templates
| Template | Default theme | Uses |
|---|---|---|
blog | light | label, title, subtitle, emoji/logo, site, author |
launch | dark | emoji/logo tile, label pill, title, subtitle, site · author |
docs | dark | emoji/logo, site / author breadcrumb (monospace), label as version pill, title, subtitle |
minimal | light | title, subtitle, emoji/logo, site · author |
gradient | white text on accent→bg gradient | emoji/logo, label, title, subtitle, site · author |
Machine-readable list: /api/templates. See them all on the home page or try them in the playground.
Examples
curl -o og.png "https://ogforge.mike-tusa.workers.dev/api/og?template=launch&title=Introducing%20Nimbus%202.0&label=Now%20live&emoji=%F0%9F%9A%80"
curl -o og.png "https://ogforge.mike-tusa.workers.dev/api/og?template=docs&title=Rate%20limits&label=v1.4.0&site=acme%20docs&author=API"
curl -o og.png "https://ogforge.mike-tusa.workers.dev/api/og?template=gradient&title=Big%20news&accent=0ea5e9&bg=22c55e"
JavaScript
const params = new URLSearchParams({ template: 'blog', title: post.title, subtitle: post.excerpt, site: 'example.com' });
const ogImage = `https://ogforge.mike-tusa.workers.dev/api/og?${params}`;
HTML
<meta property="og:image" content="https://ogforge.mike-tusa.workers.dev/api/og?template=minimal&title=Hello">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://ogforge.mike-tusa.workers.dev/api/og?template=minimal&title=Hello">
Caching
- The cache key is a SHA-256 of the normalized parameters (template, theme, cleaned and truncated text, emoji, logo URL, lower-case 6-digit colors) plus the renderer version. Parameter order, unknown parameters and
#in colors don't matter. - Successful images are sent with
Cache-Control: public, max-age=31536000, immutableand anETag;If-None-Matchreturns304. - Server side, renders are kept in an in-memory cache and in Cloudflare's Cache API.
X-OgForge-Cachetells you which layer answered:MISS(rendered now),HIT-MEMORY,HIT-EDGEorREVALIDATED(304). - To get a fresh image, change a real parameter (title, colors, …). Unknown parameters such as
v=2are ignored and do not bust the cache.
Free-tier limits
| Limit | Value | Notes |
|---|---|---|
| Image requests per IP | about 120 / minute | All /api/og requests, cached or not. |
| New renders per IP | about 20 / minute | Only cache misses count. Cached images don't. |
| New renders, whole service | about 60 / minute per Cloudflare location | Protects the free renderer. Returns 429 busy. |
| Badge | “ogforge” in the bottom-right corner | Free renders only. Pro (coming soon) removes it. |
| Output | 1200×630 PNG | Other sizes and formats aren't available yet. |
Limits are approximate (counted per Cloudflare location) and may change. A 429 includes Retry-After: 60.
Errors
Errors are JSON with Cache-Control: no-store:
{ "error": { "code": "invalid_color", "message": "\"accent\" must be a hex color like 0f172a or #0f172a (3 or 6 hex digits).", "field": "accent" } }
| Status | Code | When |
|---|---|---|
| 400 | invalid_template | Unknown template. |
| 400 | invalid_theme | theme isn't light or dark. |
| 400 | invalid_color | bg, fg or accent isn't a 3- or 6-digit hex color. |
| 400 | invalid_emoji | emoji isn't exactly one emoji. |
| 400 | invalid_logo | logo isn't a public https URL. |
| 400 | param_too_long | logo URL longer than 512 characters. |
| 414 | query_too_long | Query string over 2,000 characters. |
| 403 | blocked_content | Text or logo host matches the acceptable-use denylist, or the image was taken down. The matched term isn't echoed back; field says which parameter matched, when applicable. |
| 405 | method_not_allowed | Anything except GET, HEAD or OPTIONS. |
| 429 | rate_limited | Per-IP request or render limit hit. Includes limit, window and scope. |
| 429 | busy | Service-wide render cap hit. Cached images still work. |
| 500 | render_failed / internal_error | Unexpected failure. Please retry. |
API keys (coming soon)
There is no paid plan yet, and no key is needed. A future Pro tier will accept a key only in a header (X-Api-Key: … or Authorization: Bearer …), never in the query string, because image URLs end up in public HTML. Until then, requests that send a key are served as free tier and get an X-OgForge-Note header saying so.
Other endpoints
GET /api/templates: templates, descriptions and text limits (JSON).GET /api/health: service status and version (JSON).
Acceptable use
Don't use OgForge for impersonation (pretending to be a brand, person or organization you don't represent), phishing, or illegal content. OgForge keeps a denylist of phrases (checked in title, subtitle, label, site and author, ignoring case, accents and punctuation), of logo hosts, and of individual images. It is checked before the cache, so a taken-down image stops being served right away (copies already cached by other services may persist until they expire). Report abuse to digitalpromohub.support@gmail.com.
Privacy
- No request logs, cookies or analytics. Your IP address is used only in short-lived rate-limit counters.
- Image text is stored only inside the cached image (server memory and Cloudflare's cache).
- Logo URLs are fetched server-side by OgForge (from Cloudflare's network, user agent
OgForge/0.1), so the logo host sees a request from OgForge, never from the people viewing your page. - Emoji graphics are loaded from jsDelivr (
cdn.jsdelivr.net, Twemoji) server-side when an image contains emoji.
Response headers on images
| Header | Meaning |
|---|---|
X-OgForge-Cache | MISS, HIT-MEMORY, HIT-EDGE or REVALIDATED |
X-OgForge-Tier | free (only tier today) |
X-OgForge-Truncated | Comma-separated fields that were cut to their limit |
X-OgForge-Warning | e.g. logo_fetch_failed, logo_unsupported_type, logo_too_large, logo_http_404 |
ETag | Cache-key hash, for If-None-Match |