Open Graph & Social Cards
Set openGraph metadata so links unfurl with a rich preview on social platforms.
Syntax
metadata.openGraph = { title, description, images }The openGraph field of your metadata controls how a link looks when shared on social media and chat apps — the title, description, and preview image. Fill it in for pages you expect to be shared.
Key openGraph fields
titleanddescription.images— the preview image(s).type,url,siteName.
Example
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Our Launch',
openGraph: {
title: 'Our Launch',
description: 'We just shipped something big.',
images: ['https://example.com/og.png'],
type: 'website',
},
};When to use it
- A blog post includes an OG image and title so sharing it on Twitter generates a rich card with the article thumbnail.
- A product page sets og:type to 'product' and includes the price so Facebook displays structured product previews.
- A developer generates og:image dynamically per page using Next.js ImageResponse to create personalised social cards.
More examples
Open Graph metadata object
The openGraph key maps directly to og: meta tags that social platforms read when a URL is shared.
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'How to use Next.js',
openGraph: {
title: 'How to use Next.js',
description: 'A complete guide to the App Router.',
url: 'https://acme.com/blog/nextjs-guide',
images: [{ url: 'https://acme.com/og/nextjs-guide.png', width: 1200, height: 630 }],
},
};Twitter card metadata
The twitter key adds twitter: meta tags for X/Twitter's card system, separate from Open Graph.
// app/page.tsx
import type { Metadata } from 'next';
export const metadata: Metadata = {
twitter: {
card: 'summary_large_image',
title: 'Acme Corp',
description: 'Building the future.',
images: ['https://acme.com/og-home.png'],
},
};Dynamic OG image with ImageResponse
ImageResponse renders JSX to a PNG at the edge, enabling per-page dynamic social cards without a design tool.
// app/og/route.tsx
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
export async function GET(req: NextRequest) {
const title = req.nextUrl.searchParams.get('title') ?? 'My Site';
return new ImageResponse(
<div style={{ fontSize: 60, background: 'black', color: 'white', width: '100%', height: '100%', display: 'flex', alignItems: 'center', padding: 40 }}>
{title}
</div>,
{ width: 1200, height: 630 }
);
}
Discussion