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.
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'sog: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:
-
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 thenext/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:
- Node 16+ is installed locally
- Next version > v12.2.3 is installed
- The correct runtime config is set in the
og.tsx
file - Valid and supported CSS is used in
og.tsx
.
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.