Open Graph images in Next.js without building them yourself
· 4 min read
In Next.js an Open Graph image is just a URL you return from generateMetadata. It doesn't have to be an image you render: point it at OGsmith and every page gets its own card.
One page
Build the card URL from the page's data and return it as the Open Graph image. Keep the key in an environment variable.
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const { slug } = await params;
const post = await getPost(slug);
const og = new URL("https://ogsmith.app/api/og");
og.searchParams.set("key", process.env.OGSMITH_KEY);
og.searchParams.set("title", post.title);
og.searchParams.set("subtitle", post.excerpt);
og.searchParams.set("site", "example.com");
return {
openGraph: { images: [{ url: og.toString(), width: 1200, height: 630 }] },
twitter: { card: "summary_large_image" },
};
}Setting width and height lets Facebook show the image on the very first share, and summary_large_image is what makes X show it wide instead of as a small square.
Every page, without passing a title
If your pages already have a title and description, you don't need to repeat them. Pass the page's own address with url and OGsmith reads its tags and builds the card from them.
const og = new URL("https://ogsmith.app/api/og");
og.searchParams.set("key", process.env.OGSMITH_KEY);
og.searchParams.set("url", `https://example.com/blog/${slug}`);Pages are read once and cached for a day, so a card that's fetched a thousand times reads your page once.
Why not render it in your own app?
Next.js can render images itself with an opengraph-image file. That works, and for one layout it may be all you need. What you take on with it:
- Fonts, layout limits and edge cases in your own code.
- No way to change a card that platforms have already cached.
- A deploy for every design change, and no A/B test between two.
Is the key safe in the page?
Image URLs have to be public, because crawlers need to fetch them. If you'd rather not show the key, use a signed URL: the signature covers the exact parameters, so nobody can reuse it for other content.