Auto-generate OG images in Next.js

Add dynamic Open Graph images to a Next.js App Router site in about ten lines — no @vercel/og render function to design, deploy, or maintain. You build a signed image URL in generateMetadata; ogsmith renders and caches the PNG.

Example Open Graph image for a Next.js site rendered by ogsmith

1. Get a key

Grab a free key (250 images/mo) from the homepage form or the API — you'll get a keyId and a signingSecret. Put them in .env.local:

OGSMITH_KEY_ID=ab12cd34
OGSMITH_SIGNING_SECRET=…

2. Add a URL builder

Create lib/og.js. This runs server-side only (node:crypto), so the secret never reaches the client:

import { createHmac } from "node:crypto";

const KID = process.env.OGSMITH_KEY_ID;        // from POST /v1/keys
const SECRET = process.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 generateMetadata

// app/blog/[slug]/page.js
import { ogImage } from "@/lib/og";

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  return {
    title: post.title,
    openGraph: {
      images: [{ url: ogImage({ title: post.title, description: post.excerpt, site: "yoursite.dev" }), width: 1200, height: 630 }],
    },
    twitter: { card: "summary_large_image" },
  };
}

That's the whole integration. Every post now has a designed, cached, retina-capable social card.

Why not @vercel/og?

If you're on Vercel and enjoy designing cards in JSX, use it — it's good (ogsmith uses the same satori engine). The hosted API saves you the template design, font pipeline, emoji handling, and cache configuration, and works the same when you move a project off Vercel.

Frequently asked questions

Does this work with the Pages Router?

Yes — build the same signed URL in getStaticProps or getServerSideProps and put it in your as og:image and twitter:image meta tags.

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 Next.js 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