- Published on
Dynamically Generated OG Images in NextJS
- Authors
- Name
- James Shopland
- @jollyshopland
Open Graph (OG) images provide visual representations for content when it's shared on social media platforms. It adds extra visual appeal to a posted link, helps with branding and can entice more clicks.
Today I'm going to show you how we can generate these dynamically in NextJS 13. This means that every time we post a blog for example, we don't have to make the image ourselves, it can be done for us. It also allows us to easily change the style later if wanted.
Example
For my site I have this setup. If I share a link to twitter for one of my posts, it looks like this.
Generating the Image
1. Create the API route
The first thing we need to do is create our API route. This will be called each time a platform request the OG image and will return it.
For the app router, create the following file /app/api/og/route.tsx
Within this file we are going to import the ImageResponse
which makes this all work.
We are also going to need to tell NextJS that this api route will use the "edge" runtime.
If you are using the pages router, you will need to install and import this from @vercel/og
.
2. Return an Image
Now that we have our route, how do we make and return an image.
To do this we simply need to define an async function called GET, and return a simple image for now.
Now if you navigate to https://localhost:3000/api/og
you should see a simple image with the text hello in it.
3. Pull in dynamic data
To be able to use things such as the blog title, we will want to send some search params to the route to tell it what to render. So if I request the link /api/og?title="Hello"
, we can render the text Hello.
To do this, we will need to get the requested URL, and check if the searchParams has a title defined.
This example checks for the titles existence, if it isn't provided use a default one, if it is ensure its not longer than 100 chars (you don't need this bit if you don't want it)
Now if we go to the url https://localhost:3000/api/og?title=Hello%20World
, we will see the words Hello World in our image. Now lets style this!
4. Styling
To style this image, we can use inline styles as you would in react by adding the style prop, or we can use Tailwind.
In order to use tailwind, we don't use className
as you may be used to. Instead you want to pass the prop tw
to your elements instead.
Now we have a nice OG image styled to suit our needs, but it doesn't have a nice font, lets change that!
5. Custom fonts
In order to use a custom font, we are going to want to have the font we want to use saved as a file. For example, I have added the font Inter-bold.ttf
in the following folder /assets/fonts
To use this font, we need to do something that will look a little odd. We want to send a fetch request to this file, and then turn the response into an array buffer.
With the array buffer, we will want to add it to the ImageResponse configuration in a section called fonts, giving it a name and a style (normal or italic)
Now if you go to your route, you should see your custom font loaded into the image as well. Next we will look at some options you have for using emojis.
6. Using emojis
When you use an emoji, it will be rendered based on the device you are using. For example this 👋 will look different per device, depending on their emoji set.
When we make our image, we want to be able to tell the route what emoji set to use, as we wont know the device of the viewer.
To do this we can add a config option emoji
and set it to an emoji provider. The available providers are: twemoji, blobmoji, noto, openmoji, fluent and fluentFlat
7. Using local or external images
Similar to custom fonts, we have to load these by fetching and then getting an array buffer.
Then to use it, we can simply use a standard html image tag where we want it
Using the Image
To use the image, you have 2 options. Static metadata, or dynamic metadata. You will most likely want dynamic as this is the main purpose of an OG route.
In the route that you want the OG image to be for, so for my example its the blog post page, located at /app/blog/[...slug]/page.tsx
In here, I have a function called generateMetadata
. You can view the documentation on this here.
What the above is doing is taking in the visited page param, in my case this is just the post slug. Fetching the post based on that slug, and then building the OG image url with the search parameters we can use.
Now whenever this page's link is posted, it will fetch the image from that URL.