Generate dynamic OG images with Next.js and vercel edge functions
Published: 2022-10-16 08:52:26

## First of all for those of you who don't know let's answer the question, what are OG (Open Graph) tags?

> Open graph was the brainchild of Facebook and was launched in 2010. What it does is that it promotes integration between other websites and Facebook. It allows other websites to become rich “graph” objects having the same functionality as other Facebook objects. Website masters can control the information that the website passes to Facebook via OG Meta tags. These tags are inserted in the portion of the code of the website.

> After seeing the popularity of social media tags on Facebook, all the other major social media sites like Twitter, LinkedIn, and Google+, started to recognize meta OG tags. To harness the power of Facebook Graph Meta tags, learning this skill is vital for webmasters. Using these tags can have a huge impact on click-through rates and conversion. Social media sites become the major driver of website traffic. Adding OG tags will not affect the on-page SEO, but it will influence the performance on social media.
[Source](https://smallseotools.com/open-graph/)

Look at the [Open Graph protocol](https://ogp.me/) for more details.

## Why are Open Graph tags important?
People gonna more likely  see and click shared content with optimized OG tags, which means more social media traffic to your website.
Check out this website for more [insights](https://www.agorapulse.com/social-media-lab/link-tweet-with-an-image-vs-tweet-with-twitter-cards-does-it-really-matter/) on the stats.

There are some reasons for this:

- They make content more eye-catching in social media feeds.

- They tell people what the content is about at a glance.

- They help Social Media giants like Facebook, and Twitter .. understand what the content is about, which can help increase your brand visibility through search.

So basically Powerful OG tags are like the [Holy grail](https://en.wikipedia.org/wiki/Holy_Grail) for your Marketing Manager.

Now here's the thing since these are part of the [meta](https://www.w3schools.com/tags/tag_meta.asp) tags, and The image shown in the tags are ... well! images, making them dynamic is a bit tricky. generating images isn't a menial task that just every web server can do ... it's resource intensive, time-consuming and all the other nightmares. and making it part of your dynamic web app is another ball game altogether. So what's new? 
well, [@vercel/og](https://github.com/vercel/og-image) is, this library lets you build image content from HTML/React that too insanely fast, like really fast . and you can pair this with any edge network like AWS Lambda on the edge, Cloudflare workers, etc to make it even faster. 

Right now this has first-class integration with Next.js and Vercel Edge functions (Which is obvious)

Vercel OG also supports the following features:

- Support for basic CSS layout, styling, and typography

- Support for use in any framework or frontend application

- Support for downloading font and emoji subsets from Google Fonts and other CDNs

Vercel OG automatically adds the correct Cache-Control headers to ensure the image is cached at the Edge after it’s been generated.

```bash
'content-type': 'image/png'
'cache-control': 'public, immutable, no-transform, max-age=31536000'
```
and since the library uses [Satori](https://github.com/vercel/satori) under the hood, it can run in virtually any environment [modern browsers, Node.js (any node compatible runtime), and Web Workers ] using webassembly.

For those utility-first folks out there it supports [Tailwind](https://tailwindcss.com/) as well.

For today's Demo, I'm using a Next.js application but you can give it a try with anything else.

## Creating the serverless endpoint to generate my OG image

I'm creating an API route in my next app named **/api/og**

```typescript
// /pages/api/og.tsx

import { ImageResponse } from '@vercel/og';
import { NextRequest } from 'next/server';

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

const  OgImageHandler = async (req: NextRequest)=> {
    const { searchParams } = new URL(req.url);
    const title = searchParams.get('title')||'Mate'
    // const data = await fetch('https://jsonplaceholder.typicode.com/todos/1')
    // const jsonData = await data.json()
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          textAlign: 'center',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        Hello there! {title}
      </div>
    ),
    {
      width: 1200,
      height: 600,
    },
  );
}

export default OgImageHandler;
```

I know this is a very basic example that just takes the title query param from the URL and displays it, but this is just for learning purposes, you can go crazy with the HTML and css later.
Do keep in mind to export the config with experimental-edge runtime to make sure this runs on the edge.

Right now if I run my application and visit the route 
**http://localhost:3000/api/og?title=Akashdeep**

I get this 

![Example OG image card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1gk3q88v4hv4az3f9xw.png)

without any delay !! that's insane (If you inspect the element it's an image and not HTML).

Now to demo how the dynamic OG would work for your web pages let's build a page for our app with the route /og-image

```typescript
import type { GetServerSideProps, InferGetServerSidePropsType, NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import { useRouter } from 'next/router'
import styles from '../styles/Home.module.css'

export const getServerSideProps: GetServerSideProps = async (context) => {
  return {
    props:{
      title: context.query?.title??' Mate'
    }
  }
}
const Home: NextPage = ({title}:InferGetServerSidePropsType<typeof getServerSideProps>) => {

  return (
    <div className={styles.container}>
      <Head>
        <title>Hello There! {title} </title>
        <meta property="og:image" content={`https://next-dynamic-og-image.vercel.app/api/og?title=${title}`} />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Next.js!</a>
        </h1>

        <p className={styles.description}>
          Get started by editing{' '}
          <code className={styles.code}>pages/index.tsx</code>
        </p>

        <div className={styles.grid}>
          <a href="https://nextjs.org/docs" className={styles.card}>
            <h2>Documentation &rarr;</h2>
            <p>Find in-depth information about Next.js features and API.</p>
          </a>

          <a href="https://nextjs.org/learn" className={styles.card}>
            <h2>Learn &rarr;</h2>
            <p>Learn about Next.js in an interactive course with quizzes!</p>
          </a>

          <a
            href="https://github.com/vercel/next.js/tree/canary/examples"
            className={styles.card}
          >
            <h2>Examples &rarr;</h2>
            <p>Discover and deploy boilerplate example Next.js projects.</p>
          </a>

          <a
            href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
            className={styles.card}
          >
            <h2>Deploy &rarr;</h2>
            <p>
              Instantly deploy your Next.js site to a public URL with Vercel.
            </p>
          </a>
        </div>
      </main>

      <footer className={styles.footer}>
        <a
          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{' '}
          <span className={styles.logo}>
            <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
          </span>
        </a>
      </footer>
    </div>
  )
}

export default Home

```

Now if you look at my OG tag , I've added the image URL as a deployed version, because remember your OG image source needs to be a web service that's deployed somewhere and not localhost , so I first deployed my initial code to vercel to get the production endpoint **https://next-dynamic-og-image.vercel.app/**


Now this page is gonna be SSR driven since I want to make sure the title is available before my page component is executed [Don't be confused that's just how Next.js works, it first runs the page at build time without any client info and after hydration, it executes the client code on the browser, we'll talk about it on another day ]

and now after I deploy my page I can check this page with any title query param and it'll instantly display my dynamic Image in the OG information 

Try it out yourself 
[**https://next-dynamic-og-image.vercel.app/og-image?title=AnyText**](
https://next-dynamic-og-image.vercel.app/og-image?title=AnyText)


![Demo OG tag example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9gefo9zekotp15tryvq.png)



I'm using [https://smallseotools.com/open-graph/](https://smallseotools.com/open-graph/) for testing the OG tags 


## Beware this still has some limitations and is still an experimental build try to read the [usage doc](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation#usage) for more details.






## The code for this demo is at

 [https://github.com/Akashdeep-Patra/next-dynamic-og-image](https://github.com/Akashdeep-Patra/next-dynamic-og-image)


Feel free to follow me on other platforms as well

- [Linkedin](https://www.linkedin.com/in/akashdeep-patra-632428122/)

- [Github](https://github.com/Akashdeep-Patra)

- [Instagram](https://www.instagram.com/mr_mornin_star/)