nuuklu blog

How to add dynamic ogimages to Next.js

December 12, 2023

In my previous article, I explained how you can add a static card to Next.js

Having a dynamic card of the content we share will attract more attention on social media thus It will allow us to get more traffic to our site. In this article, I will write how you can add your ogimages that are created dynamically for your Next.js App Router application.

I recommend you to check Next.js' documentation on the subject

If you need a dynamic structure, you are most likely requesting an api. For this example, let’s send a request to jsonplaceholder site and create the opengraph image of our site according to the response

I will show through example

Link of the GitHub Repo

Let me show you the file structure

├── src/
    └── app/
    │   └──users/
    │        └──[id]/
    │            └──opengraph-image.tsx
    │            └──page.tsx
    └──lib/
        └──userFunctions.ts

I wrote the part where I made the API request in a different file. user Functions.ts

//src/lib/userFunctions.ts
import { User, Users } from "@/types/user";
export const getAllUsers = async (): Promise<Users> => {
  let allUsers = await fetch("https://jsonplaceholder.typicode.com/users");
  let allUsersJson = await allUsers.json();
  return allUsersJson;
};

export const getUserByID = async (id: string): Promise<User> => {
  let users = await getAllUsers();
  let user = users.find((user) => user.id.toString() == id);
  if (!user) throw new Error("no user found with this id: ");
  return user;
};

By reading the Next.js documentation, I made both the ‘alt’ description on the photos and the text on my social card dynamic.

// generatedynamicogimages/src/app/users/[id]/opengraph-image.tsx
import { ImageResponse } from "next/og";
import { getUserByID } from "@/lib/userFunctions";

export const runtime = "edge";
export const size = {
  width: 1200,
  height: 630,
};

export async function generateImageMetadata({
  params,
}: {
  params: { id: string };
}) {
  const user = await getUserByID(params.id);

  return [
    {
      alt: user.address.city,
      contentType: "image/png",
    },
  ];
}

export default async function Image({ params }: { params: { id: string } }) {
  const user = await getUserByID(params.id);
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 48,
          background: "white",
          width: "100%",
          height: "100%",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        {user.phone}
      </div>
    ),
    {
      ...size,
    }
  );
}