back button Back to blog

Generate OG Images Dynamically for Your Blog Posts

How I integrated the @vercel/og package into my blog to automatically build a unique OG image for every post.

Noah MatsellJanuary 6, 2023
Copy URL
Contents

Custom OG images make social link sharing more engaging. If you're using Next.js, setting up dynamic OG images should be a quick and familiar process. It takes advantage of api routes and Vercel Edge Functions.

Here's the high-level setup:

  • Install the @vercel/og package
  • Create a component under the api route /api/og.tsx
  • Return an ImageResponse from that route
  • Use this new endpoint (/api/og) for your blog's og:image meta tags

For the full setup details go here: Full Guide

The rest of this guide goes over how I used this setup to generate dynamic images with titles, metadata, and images from blog posts.

Dynamic Content in Your Images

Unique Post data

  • The dynamic data highlighted below will change for each blog post, while everything else will remain static: dynamic og image data

  • Blog posts are created as markdown files, and each file has frontmatter data that looks like this:

    ---
    title: 'Build a Mailchimp Subscribe Form in Next.js'
    description: 'Create and embed a simple Mailchimp subscription form on your Next.js site to build your audience list.'
    author: 'Noah Matsell'
    coverImgUrl: '/blog/cover/mailchimp.png'
    publishDate: '2023-01-04'
    date: '2022-12-28'
    tags:
      - nextjs
      - mailchimp
    categories: 
      - tutorials
    ---
    

og.tsx API Route Component

  • Start with a basic component setup seen here
  • Inside the component, get your URL parameter data and render them in a component passed to a new ImageResponse:
...
try {
  const { searchParams } = new URL(req.url);

  const postTitle = searchParams.get("title");
  const publishDate = searchParams.get("publishDate");
  const readTime = searchParams.get("readTime");
  const coverImgUrl = searchParams.get("coverImgUrl");

  if (!postTitle || !publishDate || !readTime || !coverImgUrl) {
    throw new Error();
  }
  // Build component response below
  return new ImageResponse(
    (
      <div>
        <p>{postTitle}</p>
        <p>{publishDate}</p>
        <p>{readTime}</p>
        <img src={coverImgUrl} />
      </div>
    ),
    {
      width: 1200,
      height: 630,
      fonts: [],
    }
  )
...
  • The above throws an error if any of the query parameters aren't defined. In these cases, we catch the error and return a generic fallback ImageResponse instead:
...
} catch (e) {
  // Build fallback component response below
  return new ImageResponse(
    (<div><h1>Fallback Content</h1></div>),
    {
      width: 1200,
      height: 630,
      fonts: [],
    }
  )
...

See my full, non-simplified og.tsx here.

Your dynamic image is now live! Take a look at either localhost:3000/api/og or in production at yourdomain.com/api/og. Add query parameters to these URLs to test out the dynamic values passed in.

Update Your Meta Tags

  • The meta tags in my app are contained in an SEO component, which returns a Head component from the next/head package.
  • Here the buildOgImageUrl utility builds the OG image URL with a hostname (based on environment) and url parameters.
...
const buildOgImageUrl = ({
title = "",
publishDate = "",
readTime = "",
coverImgUrl = "",
}: {
  title?: string;
  publishDate?: string;
  readTime?: string;
  coverImgUrl?: string;
}) => {
  const hostname =
    process.env.NODE_ENV === "development"
      ? "http://localhost:3000"
      : "https://www.noahmatsell.ca";

  const params = `title=${encodeURIComponent(
    title
  )}&publishDate=${encodeURIComponent(
    publishDate
  )}&readTime=${encodeURIComponent(
    readTime
  )}&coverImgUrl=${encodeURIComponent(
    coverImgUrl
  )}`;

  return `${hostname}/api/og?${params}`;
};
...
  • Finally, inside the SEO component build the full URL and pass it to the og:image meta tag
...
const ogImgUrl = buildOgImageUrl({
  title,
  publishDate,
  readTime,
  coverImgUrl,
});

return (
  <Head>
    <title>{`${title} // A Dev's Blog`}</title>
    <meta name="author" content={author} />
    <meta name="description" content={description} /> 
    {/* update og:image with dynamic URL */}
    <meta name="og:image" content={ogImgUrl} />
    <meta property="og:image:type" content={ogImageType} />
    <meta property="og:image:width" content={ogImageWidth} />
    <meta property="og:image:height" content={ogImageHeight} />
  </Head>
);
...

See my full SEO.tsx file here.

Gotchas

If you're having issues or seeing errors, check that:

Wrapping Up

That's all you need to dynamically generate OG images for your site! Once set up, you can rest assured that your links will look good when shared socially.


Like this post?

Sign up and get notified when new posts are published!



Comments