Creating Auto Dynamic OG Images for Your Next.js Application with Serverless Functions
Tags: nextjs, webdev, javascript, socialmedia
Published: 2023-01-06 21:41:04

> 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](https://devtomars.vercel.app/post/creating-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 `serverless `function.

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
```
Install the `@vercel/og` package:

```
npm install @vercel/og
```

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:

```javascript
import { ImageResponse } from '@vercel/og';
```
Next, we'll set the runtime for the serverless function to "edge" in the config object:

```javascript
export const config = {
  runtime: 'edge',
};
```

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:

```javascript
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,
    });
  }
}

```
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:

```jabascript
const { searchParams } = new URL(req.url);
```

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

```javascript
const hasTitle = searchParams.has('title');
```
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":

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

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

```javascript
const mainTopics = searchParams.get('mainTopics').split(",")
```
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:

```javascript
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>

```
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. :


```javascript
...
<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>
...
```
Finally, we pass an option object to create an **OG** image with a width of 1200 pixels and a height of 630 pixels:

```javascript
return new ImageResponse(
  // JSX element here
  {
    width: 1200,
    height: 630,
  },
);
```


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
```

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:

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


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!