Tutorial·2026-02-26·6 min read

How to Add Dynamic OG Images to Your Next.js App in 5 Minutes

How to Add Dynamic OG Images to Your Next.js App in 5 Minutes

Dynamic OG images ensure every page on your site has a unique, branded social preview. Instead of designing hundreds of images manually, you generate them on-the-fly from page data.

This tutorial shows you how to integrate ogimg.xyz with Next.js -- both the App Router (Next.js 13+) and the Pages Router. By the end, every page on your site will have a custom OG image generated automatically from its title and metadata.

Step 1: Understand the Meta Tag Basics

Social platforms read OG images from HTML meta tags in your page's :

``html `

The og:image tag points to the image URL. The width and height tags help platforms render the preview without downloading the full image first. Twitter also recognizes these tags, but you can add Twitter-specific tags for more control:

`html `

The summary_large_image card type tells Twitter to display the full-width image preview rather than a small thumbnail.

Step 2: Construct the ogimg.xyz API URL

The ogimg.xyz API generates images from URL parameters. The base endpoint is:

` https://ogimg.xyz/api/og `

You pass your content as query parameters:

` https://ogimg.xyz/api/og?title=My+Blog+Post&description=A+deep+dive+into+React+patterns&template=default `

Available parameters:

  • title -- The main heading text (required)
  • description -- Secondary text below the title (optional)
  • template -- The design template to use (optional, defaults to default)
  • theme -- Light or dark mode (optional)
The API returns a 1200x630 PNG image ready for use as an OG image. Images are cached at the edge, so subsequent requests for the same parameters are served instantly.

Important: URL-encode your parameter values. Spaces become + or %20, special characters need proper encoding. In Next.js, use encodeURIComponent() for this.

Step 3: Add OG Images in Next.js App Router

The App Router (Next.js 13+) uses the metadata export or generateMetadata function to define meta tags.

Static Metadata

For pages with fixed content, export a metadata object:

`typescript // app/about/page.tsx export const metadata = { title: 'About Us', description: 'Learn about our team and mission.', openGraph: { title: 'About Us', description: 'Learn about our team and mission.', images: [ { url: 'https://ogimg.xyz/api/og?title=About+Us&template=default', width: 1200, height: 630, type: 'image/png', }, ], }, twitter: { card: 'summary_large_image', images: ['https://ogimg.xyz/api/og?title=About+Us&template=default'], }, }; `

Dynamic Metadata

For pages where the content varies (blog posts, product pages), use generateMetadata:

`typescript // app/blog/[slug]/page.tsx import { getPost } from '@/lib/posts';

export async function generateMetadata({ params }) { const post = await getPost(params.slug);

const ogImageUrl = https://ogimg.xyz/api/og?${new URLSearchParams({ title: post.title, description: post.excerpt, template: 'blog', }).toString()};

return { title: post.title, description: post.excerpt, openGraph: { title: post.title, description: post.excerpt, images: [ { url: ogImageUrl, width: 1200, height: 630, type: 'image/png', }, ], }, twitter: { card: 'summary_large_image', images: [ogImageUrl], }, }; } `

Using URLSearchParams handles encoding automatically -- no need to manually replace spaces or escape characters.

Helper Function (Recommended)

If you use OG images across many pages, create a reusable helper:

`typescript // lib/og-image.ts export function getOgImageUrl(params: { title: string; description?: string; template?: string; }) { const searchParams = new URLSearchParams({ title: params.title, ...(params.description && { description: params.description }), template: params.template || 'default', });

return https://ogimg.xyz/api/og?${searchParams.toString()}; } `

Then use it in any page:

`typescript import { getOgImageUrl } from '@/lib/og-image';

const ogImage = getOgImageUrl({ title: post.title, description: post.excerpt, template: 'blog', }); `

Step 4: Add OG Images in Next.js Pages Router

If you are using the Pages Router, add OG meta tags via the next/head component:

`tsx // pages/blog/[slug].tsx import Head from 'next/head';

export default function BlogPost({ post }) { const ogImageUrl = https://ogimg.xyz/api/og?${new URLSearchParams({ title: post.title, description: post.excerpt, template: 'blog', }).toString()};

return ( <> {post.title}

{/ post content /}
); }
`

For a shared layout pattern, you can create a reusable SEO component:

`tsx // components/seo.tsx import Head from 'next/head'; import { getOgImageUrl } from '@/lib/og-image';

interface SEOProps { title: string; description: string; template?: string; }

export function SEO({ title, description, template }: SEOProps) { const ogImage = getOgImageUrl({ title, description, template });

return ( {title} ); } `

Then every page becomes a one-liner:

`tsx `

Step 5: Test Your OG Images

Before pushing to production, verify your OG images render correctly using these platform debuggers:

Common issues and fixes:
  • Image not showing: Ensure the og:image URL is absolute (starts with https://), not a relative path.
  • Old image cached: Social platforms aggressively cache OG images. Use the debugger tools to force a re-fetch, or append a cache-busting parameter like &v=2 to the image URL.
  • Image cropped incorrectly: Stick to 1200x630 dimensions. Keep important text centered with padding -- some platforms crop edges slightly.
  • Slow loading preview: If the preview takes too long to render, the platform may time out. ogimg.xyz caches images at the edge, but the first request for a unique parameter set takes slightly longer.

Quick Checklist

Before you ship, verify:

  • Every page has an og:image meta tag with an absolute URL
  • The og:image:width and og:image:height tags are set to 1200 and 630
  • The twitter:card tag is set to summary_large_image`
  • Your image URL works when opened directly in a browser
  • At least one platform debugger shows the correct preview
That is it. Five minutes of setup, and every page on your Next.js site now has a unique, professional OG image that drives more clicks from social shares.