How to generate dynamic OG image using new NextJs with App directory

OG or opengraph images are important tool for improving website SEO. Most of the time we use a static image generally placed inside the ‘public’ directory and link it to the index.html or jsx if we are using React or NextJs.

<head>
<title…


This content originally appeared on DEV Community and was authored by TITAS MALLICK

OG or opengraph images are important tool for improving website SEO. Most of the time we use a static image generally placed inside the 'public' directory and link it to the index.html or jsx if we are using React or NextJs.

<head>
  <title>Hello world</title>
  <meta
    property="og:image"
    content="https://domainname.tld/fieName.jpg"
  />
</head>

But sometime it is required to dynamically generate this og images. Use cases may include dynamic routes or dynamic product pages for an ecommerce site. If you are building your app using NextJs and planned to host that in Vercel, then vercel has a very good tool to cover you. 'Vercel Open Graph (OG) Image Generation', it does the same, it allows you to use an Api endpoint to fetch data if required and then dynamically create the og image at request time.
But the vercel documentation covers it's implementation using NextJs with older 'Page' or 'src/pages' folder structure. Where there is an dedicated 'Api' folder to handle api requests.
But it still doesn't covers how to implement the same feature using newly announce 'App' folder that replaces the older 'Pages' folder in version 13. In NextJs Beta Docs it is clearly mentioned that '/Api' is not supported inside the 'App' directory, though NextJs allows you to incrementally update to the newer structure and 'Pages' directory will be supported alongside the 'App' directory, it is good to know how to implement og image generation when using NextJs v13 or above using only 'App' directory.
Start with creating a new NextJs project.

npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app

Select the following options

? Would you like to use `src/` directory with this project? »** No** / Yes
? Would you like to use experimental `app/` directory with this project? » No / **Yes**

Now locally run your project using npm run dev and open the vscode using code ..
You will be represented with the 'App' directory instead of the 'Pages' or 'src/Pages' directory. And obviously there is no 'Api' directory inside the 'App' directory.
the 'layout.js' handles the layout obviously and 'page.js' is where you will write the codes for the index page of your app.
Please look into the NextJs Beta documentation to understand how the actual routing works in the new NextJs.
Now while 'Api' is gone, we now have 'route.js'. It can be present inside any route. But that route must not contain any 'Page.js'. Say for example create a folder, name it 'ogimage' inside the 'App', and place 'route.js' inside the folder. The 'route.js' acts as the route handler for that particular route. Please look into the route handler section in the NextJs Beta Docs. This route handler is now accessible through:

http://localhost:3000/ogimage

The 'route.js' inside a directory, here 'App/ogimage/route.js' receives the request from the client and send responses.
Where 'page.js' returns the rendered html the 'route.js' is supposed to send responses in form of json or other formats just like the api used to do.
Write the following code to test your route handler:

export async function GET(request) {
    return new Response('Hello, World!');
}

Refresh your browser, you will se 'Hello, World!' coming from your route handler.
Now install the vercel og image library to your project.

npm i @vercel/og
or
yarn add @vercel/og 
or
pnpm i @vercel/og 

import the library in your 'route.js'.

export async function GET(request) {
   return  new ImageResponse(
      (
        <div
          style={{
            fontSize: 128,
            background: 'white',
            width: '100%',
            height: '100%',
            display: 'flex',
            textAlign: 'center',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          Hello world!
        </div>
      ),
      {
        width: 1200,
        height: 600,
      },
    );
}

Here you are returning an ImageResponse instead of the Response, alternatively you can also extend the request and response web api using 'NextRequest' and 'NextRespone', to do that you can import them using import { NextResponse, NextRequest } from 'next/server';, though for this example it is not required. Now if you refresh your browser you will get an image generated by your 'route.js' at request time.
Well we are almost done. You can render whatever dynamic data in your image you want and customize your image using og playground, you can even generate 'SVG' on request as the og image.
For this example we will fetch a random number from random.org api, then we will use that number as an id and fetch an image from Lorem Picsum, with the same image url we will fetch the description for the image from the Alt Image Generator and generate an image on request with the image that we fetched and the description we have fetched and use it in a design to create the og image. Kind of like that.

Image description

So first inside our async GET function we generate a random id:

//Inside 'App/ogimage/route.js'
let randomdid;
    const getRandom = await fetch(
      'https://www.random.org/integers/?num=1&min=0&max=1083&col=1&base=10&format=plain',
      { mode: 'no-cors', next: { revalidate: 10 } },
    );
    const numbget = await getRandom.json();
    randomdid = numbget || Math.floor(Math.random() * 1083);

We are fetching a random integer between 0 - 1083 (as we found lorem picsum provides 1084 images), the 'revalidate: 10' is to tell the server to revalidate the fetch in every 10 seconds if another request is received.
Now we will fetch the image from the lorem picsum by using the random id as the photo id.

var = URL;
 const imagef = await fetch(`https://picsum.photos/id/${randomdid}/info`, {
      next: { revalidate: 10 },
    });
    const imageD = await imagef.json();
    URL = `https://picsum.photos/id/${imageD.id}/300`;

We could have fetched the whole image and could have used the method 'await res.blob()' but we found it unnecessarily slows the process. So this step can be skipped.
Now, we will fetch the description of the image from Alt Text Generator by passing the image url as a parameter like the following.

var fetchdesc;
const res = await fetch(
      `https://alt-text-generator.vercel.app/api/generate?imageUrl=https://picsum.photos/id/${randomdid}/300`,
      { mode: 'no-cors', next: { revalidate: 10 } },
    );
    fetchDesc = await res.json();

We will wrap the whole fetching thing inside a 'try catch' block and handle any error.
Now we have the url of the image that we want to show, as well as the description.
Now We will construct the og image inside the returned ImageResponse like the following:

return new ImageResponse(
    (
      <div
        style={{
          height: '100%',
          width: '100%',
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#fff',
          fontSize: 32,
          fontWeight: 600,
        }}
      >
        <div
          style={{
            left: 42,
            top: 42,
            position: 'absolute',
            display: 'flex',
            alignItems: 'center',
          }}
        >
          <span
            style={{
              width: 24,
              height: 24,
              background: 'black',
            }}
          />
          <span
            style={{
              marginLeft: 8,
              fontSize: 20,
            }}
          >
            Extend Alt Text
          </span>
        </div>
        <img height={300} width={300} src={URL} />
        <div
          style={{
            fontSize: '20px',
            marginTop: 40,
            background: 'black',
            color: 'white',
            padding: '25px',
            width: '300px',
          }}
        >
          {fetchDesc}
        </div>
      </div>
    ),
    {
      width: 1200,
      height: 600,
    },
  );

We are done. We have now a dynamically generated og image.
The whole 'route.js' will now look like the following:

import { ImageResponse } from '@vercel/og';

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

export async function GET(request) {
  console.log(request);
  //Setting the image url
  var URL;
  //Fetch the Alt Text Generator
  let fetchDesc;
  try {
    // Generating random id between 0 - 1083 to get the image
    // let randomdid = Math.floor(Math.random() * 1083);
    let randomdid;
    const getRandom = await fetch(
      'https://www.random.org/integers/?num=1&min=0&max=1083&col=1&base=10&format=plain',
      { mode: 'no-cors', next: { revalidate: 10 } },
    );
    const numbget = await getRandom.json();
    randomdid = numbget || Math.floor(Math.random() * 1083);
    //Fetching the alt text linked to id
    const res = await fetch(
      `https://alt-text-generator.vercel.app/api/generate?imageUrl=https://picsum.photos/id/${randomdid}/300`,
      { mode: 'no-cors', next: { revalidate: 10 } },
    );
    fetchDesc = await res.json();
    //fetching the actual image based on id
    const imagef = await fetch(`https://picsum.photos/id/${randomdid}/info`, {
      next: { revalidate: 10 },
    });
    const imageD = await imagef.json();
    URL = `https://picsum.photos/id/${imageD.id}/300`;
  } catch (error) {
    //Using Fallback to narrow error boundary
    URL = '/fallbackog.jpg';
    fetchDesc = 'Extend Alt Text Can Generate Descriptions';
  }

  return new ImageResponse(
    (
      <div
        style={{
          height: '100%',
          width: '100%',
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#fff',
          fontSize: 32,
          fontWeight: 600,
        }}
      >
        <div
          style={{
            left: 42,
            top: 42,
            position: 'absolute',
            display: 'flex',
            alignItems: 'center',
          }}
        >
          <span
            style={{
              width: 24,
              height: 24,
              background: 'black',
            }}
          />
          <span
            style={{
              marginLeft: 8,
              fontSize: 20,
            }}
          >
            Extend Alt Text
          </span>
        </div>
        <img height={300} width={300} src={URL} />
        <div
          style={{
            fontSize: '20px',
            marginTop: 40,
            background: 'black',
            color: 'white',
            padding: '25px',
            width: '300px',
          }}
        >
          {fetchDesc}
        </div>
      </div>
    ),
    {
      width: 1200,
      height: 600,
    },
  );
}

Now refresh your browser you will see newly generated og image each time. Simply made a git commit and let it built on the vercel.
use the link of the route and place it in the

section of your 'layout.js' and your website now has an dynamically generated og image.
<meta
    property="og:image"
    content="https://domainname.vercel.app/directoryName"
  />

You can test it here.
As the route.js here is not handelling the incoming request you can send random request parameter to genarate og images in the hosted environment.

Refreshing http://localhost:3000/ogimage will generate new og image each time.

But refreshing https://extend-alt-text.vercel.app/ogimage will not generate new og image each time, as it is remaining as cache in the edge, refreshing is not an unique request.

Passing a request param like https://extend-alt-text.vercel.app/ogimage?=[anything_Random_here] will be treated as unique request and will generate new og image. Now this newly generated image can be cached for 10 second. Sending same parameter again will prompt the cached version of the og image.
Frequently changing og image can influence the SEO, but it is absolutely okay to create Og images dynamically or for dynamic routes.
Handelling request and request.param to get the passed value can be used to dynamically add text in the og image by using {request.param} while structuring SVG in the returned imageResponse.
You can clone our project from our github repo. Our project is called Extend Alt Text and it takes the vercel Alt Text Generator and extends its functionality. It let users upload multiple files at once and generate alt texts in bulk. We can describe how we did that in a separate article.
Thanks for Now.


This content originally appeared on DEV Community and was authored by TITAS MALLICK


Print Share Comment Cite Upload Translate Updates
APA

TITAS MALLICK | Sciencx (2023-03-29T18:20:17+00:00) How to generate dynamic OG image using new NextJs with App directory. Retrieved from https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/

MLA
" » How to generate dynamic OG image using new NextJs with App directory." TITAS MALLICK | Sciencx - Wednesday March 29, 2023, https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/
HARVARD
TITAS MALLICK | Sciencx Wednesday March 29, 2023 » How to generate dynamic OG image using new NextJs with App directory., viewed ,<https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/>
VANCOUVER
TITAS MALLICK | Sciencx - » How to generate dynamic OG image using new NextJs with App directory. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/
CHICAGO
" » How to generate dynamic OG image using new NextJs with App directory." TITAS MALLICK | Sciencx - Accessed . https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/
IEEE
" » How to generate dynamic OG image using new NextJs with App directory." TITAS MALLICK | Sciencx [Online]. Available: https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/. [Accessed: ]
rf:citation
» How to generate dynamic OG image using new NextJs with App directory | TITAS MALLICK | Sciencx | https://www.scien.cx/2023/03/29/how-to-generate-dynamic-og-image-using-new-nextjs-with-app-directory/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.