Public URLs
GET /i/{keyId}/{sig} (see Signing)
needs your app to compute an HMAC over the request. Some sites have no
server or build step that can do that — a Hugo or Jekyll site built on
GitHub Pages, a Ghost theme, a Webflow page. For those, mint a
public key in the dashboard instead: it accepts
unsigned requests, but only for the templates you explicitly allow.
The URL shape
GET https://ogmake.com/p/{keyId}/{template}?title=...&description=... {keyId} is the public key's id (starts with
k_), {template} is one of the
key's allow-listed templates (e.g. blog), and every other query
param is that template's own field — same params as the signed route, just no
sig. A request for a template outside the key's allow-list, or
against a key that isn't marked public, is refused — like every other refusal on this route
(see below), that's a 200 fallback image, never an error status.
Create a public key
Sign in at /login, open the dashboard, and under "API keys" check which templates the new key may render, then "Create public key". The key id (not the bearer secret) is what goes in the URL — it is safe to commit into a public site's source.
Hugo
In a page or partial template, e.g. layouts/partials/opengraph.html:
<meta property="og:image" content="https://ogmake.com/p/k_yourkeyid/basic?title={{ .Title | urlquery }}&description={{ .Summary | urlquery }}" /> Jekyll (GitHub Pages)
In _layouts/default.html:
<meta property="og:image" content="https://ogmake.com/p/k_yourkeyid/basic?title={{ page.title | url_encode }}&description={{ page.excerpt | strip_html | url_encode }}" /> Behaves like a normal render, minus the signature
- Renders on first request, served from cache after that — same as the signed route.
- Counts against your account's monthly quota, same caps — but unlike the signed route, a public URL never gets the over-quota watermark degrade. Once your account is over its monthly cap, public URLs serve only an existing cached image or the fallback image; they never render, watermarked or not.
- Rate-limited per key and per requester IP.
- Bounded by a separate per-account public-render budget, on top of your monthly quota: up to
one fifth of your monthly sub-cap in
cache-missrenders a day and up to half your monthly cap in cache-miss renders a month, whichever is reached first — e.g. Free (100/mo) gets 10/day and 50/mo, Starter (1,000/mo) gets 100/day and 500/mo, Scale (10,000/mo) gets 1,000/day and 5,000/mo. A cache hit is always free and never counts against either budget. The budget is per account, not per key — minting more public keys doesn't multiply it. - The response is only ever the image (or a fallback image on a render failure) — it never reveals your account, or the key's bearer-secret half.
- An ordinary (non-public) key's behaviour is completely unchanged by this feature.
Anyone who copies this URL can spend your quota — it's unsigned on purpose. A per-account daily and monthly render budget (separate from, and smaller than, your monthly cap) limits how fast a copied or replayed URL can run up renders; revoke the key's public access from the dashboard at any time without touching its signed use.
Debugging a public URL that isn't working
Every refusal on this route is still a 200 image — a wrong template, a
mistyped key id, a missing required field, or a render your account can't currently afford all look
identical in the browser or the crawler's preview. Check the response headers instead
(e.g. curl -I the URL): a failed request carries an
x-ogmake-error header set to one of:
forbidden— the key id doesn't exist, is revoked, isn't marked public, or the requested template isn't in that key's allow-list.invalid_request— the request itself is malformed (a bad or missing param). Also carries anx-ogmake-error-detailheader naming the field and why.rate_limited— too many requests right now, from this key or this requester's IP; retry shortly.unavailable— the account is over its monthly cap, over its public-URL daily/monthly render budget, or a render attempt failed transiently. These are deliberately indistinguishable from each other in the response, since this route is unauthenticated and anyone holding the URL can ask — see your account's real budget/quota state on the dashboard instead.
A successful render never carries x-ogmake-error at all.