In the App Router, return the image URL from generateMetadata so every route gets its own card. The API returns a 1200×630 PNG, cached at the edge.
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const { slug } = await params
const post = await getPost(slug)
const og = `https://og.sadana.app/api/og?` + new URLSearchParams({ title: post.title, subtitle: post.description, site: 'yourblog.dev' })
return { openGraph: { images: [{ url: og, width: 1200, height: 630 }] }, twitter: { card: 'summary_large_image', images: [og] } }
}Next.js can also render images itself with next/og ImageResponse; use a URL API when you deploy static exports or don’t want to maintain JSX templates and fonts.
title required, up to 200 chars subtitle optional site optional footer text theme light | dark (Pro) key Pro license key (removes watermark)
After deploying, paste a URL into a card validator (e.g. opengraph.xyz) or share it in a private Slack/Discord channel. Social crawlers cache images, so change the URL (e.g. add &v=2) to force a refresh.
Next.js · Astro · Hugo · WordPress · Ghost · SvelteKit · Nuxt · Eleventy (11ty) · Jekyll · Docusaurus · plain HTML