DEV Community

ayka.code
ayka.code

Posted on

Creating Auto Dynamic OG Images for Your Next.js Application with Serverless Functions

For clear an better UI you can read this blog post on my personal blog: Creating Auto Dynamic OG Images for Your Next.js Application with Serverless Functions

If you have a blog or website, you may want to create open graph (OG) images to use when sharing your content on social media platforms. OG images are displayed when someone shares your content on social media, and they help to give context to the shared content and make it more visually appealing.

In this tutorial, we'll look at how to create dynamic OG images in a Next.js application using a serverless function. We'll use the @vercel/og package to create the OG image within the serverlessfunction.

Before we get started, you'll need to have a Next.js application set up. If you don't already have one, you can create a new Next.js project by running the following command:

npx create-next-app
Enter fullscreen mode Exit fullscreen mode

Install the @vercel/og package:

npm install @vercel/og
Enter fullscreen mode Exit fullscreen mode

Now that we have the necessary packages installed, we can create the serverless function that will generate the OG image. To do this, create a og.js in the api folder of your Next.js project and import ImageResponse class at the top of the file:

import { ImageResponse } from '@vercel/og';
Enter fullscreen mode Exit fullscreen mode

Next, we'll set the runtime for the serverless function to "edge" in the config object:

export const config = {
  runtime: 'edge',
};
Enter fullscreen mode Exit fullscreen mode

This will ensure that the function is executed on the edge network, which is required for creating OG images.
Now, let's define the main handler function for the serverless function:

export default function handler(req) {
  try {
    const { searchParams } = new URL(req.url);
    // code for generating the OG image goes here
  } catch (e) {
    return new Response(`Failed to generate the image`, {
      status: 500,
    });
  }
}

Enter fullscreen mode Exit fullscreen mode

This function takes a request object as an argument and returns an OG image response. If an error occurs while generating the image, it returns a response with a status of 500 and an error message.

Now let's start adding the code for generating the OG image. First, we'll parse the search parameters from the request URL:

const { searchParams } = new URL(req.url);
Enter fullscreen mode Exit fullscreen mode

Then, we'll check if the title search parameter is present in the query string:

const hasTitle = searchParams.has('title');
Enter fullscreen mode Exit fullscreen mode

If the title parameter is present, we slice it to a maximum of 100 characters and assign it to the title variable, If the title parameter is not present, we set the title variable to the default value of "DevToMars":

const title = hasTitle
  ? searchParams.get('title')?.slice(0, 100)
  : 'DevToMars';

Enter fullscreen mode Exit fullscreen mode

Next, we retrieve the mainTopics search parameter from the query string and split it into an array using the split method:

const mainTopics = searchParams.get('mainTopics').split(",")
Enter fullscreen mode Exit fullscreen mode

This allows us to pass multiple main topics as a comma-separated list in the query string.

Now that we have the title and mainTopics variables, we can use them to render the OG image. To do this, we use the ImageResponse class from the @vercel/og package, which allows us to create an OG image from a React component.

We pass a simple div element with some inline styles applied to it to the ImageResponse class as the React component . The styles specify the layout and appearance of the OG image:

return new ImageResponse(
      (
        <div
          style={{
            backgroundColor: 'black',
            backgroundSize: '150px 150px',
            height: '100%',
            width: '100%',
            display: 'flex',
            textAlign: 'center',
            alignItems: 'center',
            justifyContent: 'center',
            flexDirection: 'column',
            flexWrap: 'nowrap',
            padding: "65px",
          }}
        >
   {/* The Body of the Image */}
</div>

Enter fullscreen mode Exit fullscreen mode

As you can see, we are displaying the div as a flex because Next.js requires this for every element with more than one child. You can use Tailwindcss for styling, but I don't recommend it because it is not stable and it is not fully supported for generating images with Next.js.

Our image will contain a title that fills up 75% of the image width with some padding and a margin-top of 30px, a logo with a brand name, and a list of main topic tags. :

...
<div style={{
                fontSize: 60,
                fontStyle: 'normal',
                letterSpacing: '-0.025em',
                color: 'white',
                marginTop: 30,
                padding: '0 100px',
                lineHeight: 1.4,
                whiteSpace: 'pre-wrap',
                height: "75%",
                fontWeight: 700,
                textTransform: "capitalize"
            }} className="w-10 capitalize">
                {title}
            </div>
            <div style={{ display: "flex", flexDirection: "row", gap: "10px", alignItems: "center" }} >
                <div style={{ width: "70px", height: "70px", display: "flex" }}>
                    <img 
                        src="https://media.graphassets.com/gncWvSEqRFaBSUPZGoTP"
                        width={70}
                        height={70}
                        alt="devtomars blog"
                    />
                </div>

                <div style={{
                    backgroundClip: "text",
                    color: "transparent",
                    backgroundImage: "linear-gradient(to right, #ec4899, #8b5cf6)",
                    fontWeight: 700,
                    fontSize: 30
                }} >DevToMars</div>


                <div style={{ display: "flex", flexDirection: "row", justifyContent: "flex-end", justifyItems: "center",width: "75%" }}>
                    {
                        mainTopics.map((topic, i) => (
                            <div key={i} style={{ color: "black",  fontSize: 20, padding: "5px", margin: "3px", backgroundColor: "white", borderRadius: "8px" }}>{topic}</div>
                        ))
                    }
                </div>
            </div>
...
Enter fullscreen mode Exit fullscreen mode

Finally, we pass an option object to create an OG image with a width of 1200 pixels and a height of 630 pixels:

return new ImageResponse(
  // JSX element here
  {
    width: 1200,
    height: 630,
  },
);
Enter fullscreen mode Exit fullscreen mode

And that's it! You now have a serverless function that can generate dynamic OG images for your Next.js application. To use the function, simply make a request to the function's URL with the desired title and mainTopics query parameters. For example:

https://your-next-app.vercel.app/api/og?title=My Blog Post&mainTopics=nodejs,javascript,react
Enter fullscreen mode Exit fullscreen mode

This will generate an OG image with the title "My Blog Post" and the main topics "nodejs", "javascript", and "react".
You can then use the generated OG image in your social media sharing tags, like so:

<meta property="og:image" content="https://your-next-app.vercel.app/api/og?title=My Blog Post&mainTopics=nodejs,javascript,react" />
Enter fullscreen mode Exit fullscreen mode

That's it! You now know how to create dynamic OG images for your Next.js application using a serverless function. I hope this tutorial was helpful!

Top comments (0)