Signed URLs
Instead of embedding your API key, you can sign each URL with your account's signing secret (dashboard → Signed URLs). The signature binds the exact parameters, so a leaked URL can't be modified or reused for other content, and your secret never appears in markup.
Signature: take every query parameter except sig (including acct), percent-encode each name and value with encodeURIComponent, sort pairs by name, join as name=value with &, and HMAC-SHA256 it with your secret (hex output).
import { createHmac } from "crypto";
function signedOgUrl(params, accountId, secret) {
const p = new URLSearchParams(params);
p.set("acct", accountId);
const msg = [...p.entries()]
.map(([k, v]) => [encodeURIComponent(k), encodeURIComponent(v)])
.sort(([a, x], [b, y]) =>
a === b ? x.localeCompare(y) : a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join("&");
p.set("sig", createHmac("sha256", secret).update(msg).digest("hex"));
return `https://ogsmith.app/api/og?${p}`;
}
signedOgUrl({ title: "My post", template: "split" }, ACCOUNT_ID, SECRET);