Raul CariniFull Stack Developer

Dynamic Social Images with Next.js

December 19, 2024 (25 days ago)

Ever shared a link and wished it had a better preview image? Those eye-catching images you see on social media are often powered by Open Graph (OG) tags. In this article, we'll explore how to create these OG images dynamically in Next.js, making your shared links stand out.

Why Dynamic Social Images?

While static images are okay for general branding, they're not great for showcasing specific content. Imagine sharing a blog post - wouldn't it be better if the shared image included the post's title or a relevant graphic? That's where dynamic image generation comes in. It allows you to create custom social media images on the fly.

Next.js to the Rescue

Next.js makes dynamic social image generation easy thanks to its routing system and recent features. You can create images directly within your application using JavaScript, TypeScript, or JSX - no extra services needed. You have two main approaches: using a special file or creating an API route. You can learn more about Next.js routing here.

Method 1: The Magic of opengraph-image.js (or .ts/.tsx)

The first approach uses a special file called opengraph-image.js (or its TypeScript versions). By placing this file in a route segment, you tell Next.js: "Generate the Open Graph image for this specific page here." It's a simple idea that gives you a lot of control over specific page images. You can read more about Next.js file conventions here.

Method 2: Generating Images Through an API Route

Alternatively, you can create an API endpoint dedicated to generating images. This approach is useful if you want to create more complex images or reuse the image-generating logic across different parts of your application. You could create an API route in the app/api folder, for example, /api/dynamic-image. You can read more about Next.js API Routes here.

How It Works: A Quick Overview

Using opengraph-image.js:

  1. Create the File: Make an opengraph-image.js, .ts, or .tsx file within your desired route. For example, for blog posts, the file would be located at app/posts/[slug]/opengraph-image.jsx.
  2. Export a Function: Inside the file, you need to export a default function. This function generates your image.
  3. Use ImageResponse: The easiest way to create your image is using ImageResponse from next/og. It lets you use JSX to define the image's layout and content. Think of it as writing HTML, but it renders an image. You can find more info about the next/og library here.
  4. Dynamic Content: The function receives the route's parameters via a params prop. You can use these to personalize the image with data.
  5. Metadata: Export things like alt (alt text), size, and contentType to add meta tags to your HTML. You can see how Open Graph meta tags work in general.

Using an API Route:

  1. Create the API Route: Create the route.js inside your app/api folder, creating the /api/dynamic-image endpoint.
  2. Export a GET Function: Export an async function called GET that will handle the request and generate the image.
  3. Use ImageResponse: Similar to the opengraph-image approach, use ImageResponse to create your image with JSX.
  4. Access Query Parameters: You can access query parameters passed to the API route using request.url and URLSearchParams. You'll need to pass the slug to the API route via query parameters in this case.

A Simple Example

Let's look at examples for both approaches.

Example 1: Using opengraph-image.jsx

import { ImageResponse } from "next/og";

export const runtime = "edge";

export const alt = "Blog Post Image";
export const size = {
  width: 1200,
  height: 630,
};
export const contentType = "image/png";

export default async function Image({ params }) {
  const post = await fetch(`https://your-api.com/posts/${params.slug}`).then(
    (res) => res.json()
  );

  return new ImageResponse(
    <div style={{ fontSize: 48, background: "white" }}>{post.title}</div>,
    {
      ...size,
    }
  );
}

Example 2: Using an API Route (app/api/dynamic-image/route.js)

import { ImageResponse } from "next/og";
export const runtime = "edge";

export async function GET(request) {
  const { searchParams } = new URL(request.url);
  const slug = searchParams.get("slug");

  const post = await fetch(`https://your-api.com/posts/${slug}`).then((res) =>
    res.json()
  );

  return new ImageResponse(
    <div style={{ fontSize: 48, background: "white" }}>{post.title}</div>,
    {
      width: 1200,
      height: 630,
    }
  );
}

Important Note: To use the API route example effectively, you would need to modify your meta tags in your blog post template to point to the API route, passing the slug as a query parameter, like this:

<meta property="og:image" content={`/api/dynamic-image?slug=${slug}`} />

Things to Keep in Mind

In Conclusion

Next.js provides two powerful ways to create dynamic social media images: the opengraph-image file and API routes. Both methods use the ImageResponse API and allow for the creation of personalized and visually engaging previews for shared links. Choosing the right approach depends on your specific needs and the complexity of the images you need to generate. This flexibility makes Next.js a great tool for improving your social media presence.