Meta tags are critical elements that must be done for every page to ensure great discoverability on search engines. Some meta tags are texts and others are image links. Text meta are easy to automatically populate but images can be a pain. Developers might have to create or receive the image, upload it somewhere and add the link to the image ofn the page.

This process is time consuming and doesn’t work when the pages don’t exist yet (in case of a blog post that isn’t published yet). Being able to automatically generate an image would be a life savior, right?

Here comes Vercel OG

That’s exactly what the Vercel OG package does. It offers an easy way to automatically generate and host (on a CDN) meta images. Having automatically generated images is a simple as using an API.

Once the project is hosted (on Vercel or somewhere else), it’s as simple as adding a link to the endpoint in the page as meta image tag.

<head>
  <title>The post's title</title>
  <meta
    property="og:image"
    content="https://my-og-img.vercel.app/api/og?title=my post title"
  />
</head>

You can see in the above screenshot that the image has a title in the query prams, this is how you can pass parameters to the image thus making it dynamics.

There are no limits on how many parameters can be passed and this can even be used to have variants of an image. Using query strings (https://my-og-img.vercel.app/api/og?title=${post.title}) makes the image fully automatic, new blog posts published on a website will automatically have an image generated. No need to open Figma or Photoshop anymore!

Why Meta Tags Are Important

Meta tags are parts of a set of tools developers (and marketers) have at their disposal to help rank a webpage in the top Google results. Those techniques can be grouped under SEO (Search Engine Optimization).

SEO is a vast topic and it won’t be covered in this article. Search Engine will use many metrics to determine which page to recommend to whom. Developers have an impact on some of those metrics such as web vitals, page structure, sitemap and meta tags.

Meta tags are quite simple to put in places and are tags that helps web crawlers to determine what the page is about. There are plenty of meta tags that can be used. The W3 website has some basic examples (HTML meta tag).

Meta tags are placed at the head of a page and looks like this:

<head>
  <meta charset="UTF-8">
  <meta name="description" content="Free Web tutorials">
  <meta name="keywords" content="HTML, CSS, JavaScript">
  <meta name="author" content="John Doe">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

This very basic example shows how meta tags can be used.

I remade my portfolio yesterday from scratch and got inspired…
Photo by Caspar Camille Rubin / Unsplash

What makes Vercel OG great

As I said before, Vercel OG can generate images on the fly. Using the library is as simple as making a GET request on an endpoint. It’s very easy and is something every web developer is used to.

Edge and Global CDN

Besides that, hosting the project on Vercel offers some benefits. Mainly when it comes to hosting and availability. The code that generates the image is run on the edge. This means quick cold boot and code that run as close as the end user as possible.

Generated images are small SVG and are hosted on the global Vercel CDN. Vercel CDN is great and will ensure a fast landing from anywhere in the world.

Images are greeted once somewhere in the world and then hosted on several servers throughout the world.

Update the design

Generated images are coached, its near-instant loading thanks to Vercel global CDN. This is great for static images but it can get even better. Redeploying the projects will invalidate the cache, no images will be deleted but the new one will be generated on user requests.

This means that updating the design of the meta image. Let’s say by adding the blog post author. It will be available for every page already present on the website. The URLs might need to be updated but this can be very quick if the pages are generated using query strings since the change should be only once.

<head>
  <title>The post's title</title>
  <meta
    property="og:image"
	  {/*Before the change*/}
    content={`https://my-og-img.vercel.app/api/og?title=${post.title}`}
	  {/*After the change*/}
    content={`https://my-og-img.vercel.app/api/og?title=${post.title}&author=&{post.author.fullName}`}
  />
</head>

Images are automatically generated and updated in case of change. No need for any human intervention once the code is updated.

Cost Saving

Automatically generate images means less human interaction. Once the meta image is converted into the project, the designer doesn’t have to generate new images or intervene when a new page is added on the website. Designers will have more time to focus on part of the project where they provide real value.

Besides that, images are automatically generated and hosted. Vercel free tier is quite generous and can replace the need for a storage bucket or FTP server. Thus reducing some infrastructure costs.

Architecture Simplification and Process Streamline

Generating the image with code means that some part of the architecture could be removed or simplified. No need for a micro service that is used only to generate and host the meta images, the code can be integrated in any NextJS project.

This can result in the suppression of some services, the fewer services the easier the maintenance and the less prone to error you are.

There are many cases where a human still needs to generate an image for the meta tag. In those cases the process of page publication can be simplified since one of the blocking elements (the human generating the image) can be removed.

No need to wait for someone to publish a new landing page anymore, the process is faster and more consistent.

Infinite number of variations

There is no limitation when it comes to the number of endpoints that can be used to generate images. This means that you could have one endpoint to generate blog post images, one for landing pages and another endpoint for a special Black Friday offer.

There is no limitation and having multiple endpoints will definitely be easier to maintain that one endpoint that generates dozens of images variants.


Generating Images for Static Pages Was a Pain

I used to work for an agency that had some time dedicated for internal projects. One of the projects was called Cedille and is still maintained and worked on. Cedille is a service that proposes, thanks to GPT, skills that generates texts. There are skills that help to generate product description, summarize texts,… a wide range of services are offered.

In the past, we wanted to have a custom meta images when users shared a text on their social accounts. We wanted to show the text the user entered and what the AI returned.

It wasn’t possible to generate all the text combination since its user-generated content. So we needed to be a bit creative.

Since we stored all generated content, it was possible to use the ID on the Supabase database as an identifier of the meta image and the content. When pressing the “Share” button a modal showing what the meta image will look like was opened. This modal was used to take a screenshot of the component and upload it to Supabase.

Next, we had a meta tag on the page that was looking for a query pram (the identifier of the image) and was populated with the parameter if present. This was our way of displaying a meta image that looked good and was unique to each generation.

I have to admit, this was a bad solution. Users had to open a modal for us to generate an image, we had to look at query prams instead of having some unique URLs for every generation.

We should have spent a bit more time designing the feature and look for online services or ways of generating the image on the server.

Regardless of the technical choices of the time, the feature was scrapes with the last redesign of the application. It provided very little value for users and shouldn’t have been implemented in the first place.

Vercel OG announcement

How Vercel OG simplifies the whole process

Vercel OG didn’t exist at the time, but if the feature needed to be reimplemented I would definitely use it.

The whole process would have been way simpler, we simply needed to get the texts that were entered by the user and the response from the AI from the server. Those two texts are all we need to generate the image, the endpoint would accept both texts and would generate the image for us.

If some parameters are critical (of if we want to hide some parameters), we could even encrypt the parameter before sending them to make sure we don’t leak things we don’t want.

Everything would be implemented and tested in about one day instead of the days it took in the past to implement.

The developer experience is improved, the resulted code is simpler and less dependent on hacks. Using Vercel OG would be a no-brainer.


How to Use Vercel OG

Using Vercel OG is pretty simple, the following example will use a NextJS project and Tailwind. I won’t go through the project setup in this article.

💡
You can find the code on my GitHub: GitHub - flavienbonvin/blog-meta-og-image. Or look at a live demo

1. Install the package

Install the package with your favorite package manager:

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

2. Create an endpoint

The endpoint will be used to generate the image. I decided to call mine /api/og but feel free to name it as you want.

Once your endpoint is created, you can fill it with the following information.

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

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

export default function () {
  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,
    },
  );
}

3. Create your image and get dynamic data

Once you have created your endpoint, you’re basically done and are ready to create your image. That’s where you reproduce the design your designer created or you get creative and create your own image.

Creating an image is fine but you’ll probably need to get some dynamic parameters. Without those parameters your image will be the same.

Here is how I did it in my project:

const { searchParams } = new URL(req.url)
const title = searchParams.get(“title”) ?? “Some title”
const subtitle = searchParams.get("subtitle") ?? "Some sub"
const publicationDate = searchParams.get("publicationDate") ?? "Some date"
const tags = searchParams.get("tags") ?? "Some date"

The whole process is quite simple and I decided to put some default value (since I know that all are required). Feel free to leave them empty if you don’t need them.

4. Deploy to Vercel

There is no need to deploy the project to Vercel. Deploying on Vercel is dead simple and it will work out of the box, this is why I recommend hosing everything on it.

Besides that, there is no need to have this code inside the rest of your project. You can isolate the meta image generation on Vercel and have your application hosed somewhere else if you have some business limitation.

People seem to have deployed some projects on Netlify here is some discussion about it: How to deploy og-image on Netlify? · Issue #172 · vercel/og-image · GitHub

5. Add in your project

Once your code is hosted online you can start using the images in your project. This can be either in the same project or anywhere you need to generate a meta image.

To do so simply change the meta for the image on your project from the static image you had to the new URL with all the parameters you might need.

The following example comes from the project linked above and show how it could be used in a NextJS project.

<head>
  <title>The post's title</title>
  <meta
    property="og:image"
    content={`http://localhost:3000//api/og?title=${title}&subtitle=${subTitle}&publicationDate=${publicationDate}&tags=${tags}`}
  />
</head>

Subscribe to the newsletter to get articles in your inbox

Subscribe to the newsletter

6. Add custom fonts

Using custom fonts is critical for many businesses. It’s possible to use custom fonts with the library. You’ll need the .ott file and store it somewhere on your project.

It’s the possible to load the fonts on the endpoints add them on the config and load them in the components.

const alata = fetch(new URL("../../assets/Alata.ttf", import.meta.url)).then(
  (res) => res.arrayBuffer()
)

...

export default async function (req: NextRequest) {
  const alataData = await alata
	...

  return new ImageResponse(
    (
      <OGCard
        title={title}
        subtitle={subtitle}
        publicationDate={publicationDate}
        tags={tags}
      />
    ),
    {
      width: 1200,
      height: 630,
      fonts: [
        {
          name: "alata",
          data: alataData,
          style: "normal",
        }
      ],
    }
  )
}

Here is the documentation: OG Image Examples – Vercel Docs

7. Use Tailwind

Tailwind is experimentally supported by Vercel OG. Using requires no additional configuration, the only change you have to do is to use tw instead of className.

It’s very simple and you can speed the development process by doing the design first in standard tailwind and then change all the className in your component with  tw.

Some styles might not work as intended and you might have to do some inline styling. That’s what I had to do on my project as you can see in the following code snippet:

  return (
    <div
      tw="flex h-[630px] w-[1200px] items-center justify-center"
      style={{
        background:
          "linear-gradient(133deg, rgba(255,107,107,1) 0%, rgba(255,230,109,1) 35%, rgba(78,205,196,1) 100%)",
      }}>
  ...
  )

Here is the documentation for Tailwind: OG Image Examples – Vercel Docs

Some limitations

Vercel OG is perfectly useable in the current state. However, the package isn’t stable yet, the current version is 0.0.21 and was updated last month.

Besides some breaking changes that might occur in the future, there are some elements worth considering before using the library.

Vercel dependency

The first point, there is some discussion online when it comes to Vercel role in the current JavaScript ecosystem. Some find that Vercel is too present and current tools depends too much on the company.

The recent release of open next (OpenNext) is an indicator that some wants to avoid being too much dependent on Vercel. Putting too many eggs in one basket is bad and it’s fair for people to look for alternatives.

Theo addressed this in one of his last videos. He argues that Vercel is pushing innovation and that this comes at the cost of “lock in”. This also means that Vercel can introduce breaking changes (with the middleware changes in NextJS for example). Other actors can use what’s considered stable and avoid those unpleasant situations.
YouTube

Works on edge, browser API only

To be fast Vercel OG cannot use a typical Node JS API. Cold boots would be way too long and it would result in a suboptimal experience for the end user.

That’s why Vercel OG leverage the power of the Edge network. This ensures blazing fast image generation. Besides that, the code is hosted on Vercel global Edge network. This means that the code is deployed around the globe for an experience similar regardless of the location of the user.

Using the Edge is great and is getting more popular. This comes at a cost tho, not all Node JS APIs are available on the Edge.  Some libraries you might be used to won’t be present and you’ll have to resort to using alternative.

Nearly everything that is available on a standard browser is available on the edge. This leaves you plenty of options to make your code work but it can require some getting used to.

You can find the documentation related to Edge Functions limitations here: Edge Functions Limitations – Vercel Docs

Size limitation

To make sure that the code runs fast and close to the end user on the Edge is a requirement. Another way to make sure that the code runs fast is to limit the size of the code that can be hosted.

Having to run 10 MB of JavaScript would reduce the benefits of the edge down to zero. This is why Vercel has some limitation when it comes to the edge.

Here is a list of limitations to keep in mind:

  • Max 128MB  of RAM
  • Max 1 MB of code for hobby plan (2 MB for Pro and 4 MB for enterprise)
  • 5 KB of environment variables (compared to the 64 KB otherwise)

You can find the documentation related to Edge Functions limitations here: Edge Functions Limitations – Vercel Docs

No control over cache

Vercel gives no control over the cache. This is probably because the wants to keep a control over how and when images or pages are hosted but it can be an issue in some cases where you might want to rebuild a page.

I had this exact issue in the past. We had dynamic pages that were displaying data coming from an ERP. Due to technical decision, we didn’t use typical NextJS incremental static regeneration (which would have allowed us to manually rebuild a page). The only solution we had was to redeploy the website when changes were critical (this is fine since it only happens on few occasions).

Having little control over the cache is fine in most cases. However, you miss that control in tricky scenarios and you have to find a workaround.

Caching on Vercel is tied to a deployment. This means that redeploying your project will invalidate the cache. Generated images might be regenerated and this could cause an issue depending on the changes you did.

Besides that, running code that isn’t required is a waste of energy (even if this only represent a small amount of computing).

Not full Tailwind

Finally, Tailwind support is currently in beta. This means that not every class works properly and you might have some warnings on your console when running the code.

For example, gradients are not fully supported yet. I found this the hard way and had to convert some of the gradients I had in my post to inline styling to avoid rebuilding everything.

Most of the classes are supported and a simple design won’t cause any issue but more complex classes aren’t there yet and you might have to do inline styling or plain CSS.


Conclusion

💡
You can find the code on my GitHub: GitHub - flavienbonvin/blog-meta-og-image. Or look at a live demo

Vercel OG is absolutely amazing when it comes to the image generation. It can be used in any JavaScript frontend or on other websites where you can create dynamic URLs.

Besides that, there are some alternative used that can be useful. I personally use it to generate the images for my blog articles. I’m using Ghost to publish my articles and it’s not possible to put a link for meta images.

I decided to use Vercel OG regardless of this since it’s easier for me to update the design in CSS than on Figma as it was done before.

You should definitely give Vercel OG a try. Keep in mind that some of its features are in beta and the library hasn’t got its first v1 release. There might be some breaking changes in the future but that’s a risk I’m willing to take!