Auto-generate OG images in Astro

Astro components run at build time in Node, so you can compute a signed ogsmith URL right in your layout's frontmatter and bake it into the static HTML. No integration package, no render endpoint, no client JavaScript.

Example Open Graph image for a Astro site rendered by ogsmith

1. Get a key

Grab a free key from the homepage and add it to .env:

OGSMITH_KEY_ID=ab12cd34
OGSMITH_SIGNING_SECRET=…

2. Add a helper

Create src/lib/og.js (build-time only — the secret is never shipped to the browser):

import { createHmac } from "node:crypto";

const KID = import.meta.env.OGSMITH_KEY_ID;        // from POST /v1/keys
const SECRET = import.meta.env.OGSMITH_SIGNING_SECRET;

// Strict RFC 3986 encoding — encodeURIComponent plus the five chars it skips.
const enc = (s) =>
  encodeURIComponent(s).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());

export function ogImage(params) {
  const p = { template: "article", ...params, kid: KID };
  const canonical = Object.keys(p).sort().map((k) => enc(k) + "=" + enc(p[k])).join("&");
  const sig = createHmac("sha256", SECRET).update(canonical).digest("hex");
  return "https://api.ogsmith.dev/v1/og?" + new URLSearchParams({ ...p, sig });
}

3. Use it in your layout

---
// src/layouts/BlogPost.astro
import { ogImage } from "../lib/og.js";
const { frontmatter } = Astro.props;
const og = ogImage({ title: frontmatter.title, description: frontmatter.description, site: "yoursite.dev" });
---
<head>
  <meta property="og:title" content={frontmatter.title} />
  <meta property="og:image" content={og} />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:image" content={og} />
</head>

Because the URL is computed at build time, a fully static Astro site gets dynamic-looking OG images with zero runtime dependencies.

Frequently asked questions

Does this work with SSR (Astro on Node/Vercel/Netlify adapters)?

Yes, identically — the helper runs wherever the page renders. For content collections, call ogImage() with data from each entry.

Why signed URLs instead of an API key?

The og:image URL ends up in your public HTML, where anyone can read it. A signed URL exposes no secret: the HMAC signature covers every parameter, so changing the title (or anything else) invalidates it. A leaked signed URL can only ever render that exact image.

Does every page view burn my quota?

No. Images are served through CloudFront with immutable caching, and cache hits don't count against your quota. A given og:image URL renders once; every crawler and preview after that is a free edge hit.

Templates available: basic, gradient, split, article, minimal, code — try them in the playground. Full parameter list in the docs.

Add OG images to your Astro site now

Free key, 250 images a month, no card. One GET request and every page has a social card.

Get a Free API KeyTry the Playground