Creating openGraph images automatically for Next.js

Jan 28, 2021

  • Next.js
  • React
  • JavaScript

For static site generation with Next.js, we will build openGraph image generator.

Building a project for automatic image generation#

First of all, let's create a project for automatic image generation. Of course, you don't have to build new one if you have one. I will use Next.js here as well.

Setup#

terminal
1npx create-next-app og-image

We will use chakra-ui for styling our project. This is a great library that will make your life easier. See the official documentation to install chakra-ui to your Next.js project.

Creating a page#

jsx
1/* pages/index.js */
2
3import { chakra, Heading, HStack } from '@chakra-ui/react';
4import { useRouter } from 'next/router';
5import Image from 'next/image';
6
7export default function Home() {
8 const router = useRouter()
9 const searchParams = new URLSearchParams(router.asPath.split(/\?/)[1]);
10 const title = searchParams.get('title');
11
12 return (
13 <>
14 <chakra.div
15 position="relative"
16 display="flex"
17 flexDirection="column"
18 width={1200}
19 height={630}
20 p={16}
21 justifyContent="space-between"
22 alignItems="center"
23 borderWidth="2rem"
24 borderColor="gray.600"
25 >
26 <div/>
27 <Heading px="4rem" textAlign="center" fontSize="5rem">
28 {title}
29 </Heading>
30 <HStack spacing="1rem">
31 <chakra.div
32 position="relative"
33 width="8rem"
34 height="8rem"
35 borderRadius="50%"
36 overflow="hidden"
37 >
38 <Image src="/profile.png" layout="fill" objectFit="contain" />
39 </chakra.div>
40 <Heading fontSize="2rem">so99ynoodles</Heading>
41 </HStack>
42 </chakra.div>
43 </>
44 );
45}

We will create a UI by sending title query-string to the URL, like https://example.com/?title=TITLE. We will set the image size as 1200 x 630, you can adjust the value to optimize your image for your usage.

image_generation_project

If you access to the address localhost:3000/?title=Creating openGraph images automatically for Next.js , you can get above image. Deploy your new project somewhere like Vercel.

Changing fonts#

Feel free to change font-family for your design adjustment.

jsx
1/* pages/index.js */
2
3import GoogleFonts from 'next-google-fonts';
4
5export default function Home() {
6 ...
7 <GoogleFonts href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;500;700;900&display=swap" />
8 ...
9 <Heading fontFamily="Noto Sans" px="4rem" textAlign="center" fontSize="5rem">
10 {title}
11 </Heading>
12 ...
13}

Accessing to the project and get openGraph image on production build#

Let's write a function to generate openGraph image.

Writing a function#

js
1/* utils/openGraphImage.js */
2
3import fs from 'fs';
4import { createHash } from 'crypto';
5import { chromium } from 'playwright';
6
7export async function getOpenGraphImage(path) {
8
9 /* We will only run this function on production build */
10 if (process.env.NODE_ENV === 'development') {
11 return;
12 }
13
14 /* Change this to your project url */
15 const baseUrl = 'https://example.og.com'
16 const url = `${baseUrl}${path}`;
17 const hash = createHash('md5').update(url).digest('hex');
18
19 const ogImageDir = `./public/images/og`;
20 const imagePath = `${ogImageDir}/${hash}.png`;
21 const publicPath = `${process.env.SITE_URL}/images/og/${hash}.png`;
22
23 try {
24 fs.statSync(imagePath);
25 return publicPath;
26 } catch (e) {
27 console.log(`generating og image for ${path}`);
28 }
29
30 const browser = await chromium.launch({ headless: true });
31 const page = await browser.newPage();
32 await page.setViewportSize({ width: 1200, height: 630 });
33 await page.goto(url, { waitUntil: 'networkidle' });
34 const buffer = await page.screenshot({ type: 'png' });
35 await browser.close();
36
37 fs.mkdirSync(ogImageDir, { recursive: true });
38 fs.writeFileSync(imagePath, buffer);
39
40 return publicPath;
41}

Here's what getOpenGraphImage function does.


  1. Using playwright package, open Chrominium browser and access to the page
  2. Save the screenshot of the page to /public/images/og folder
  3. Return production url for the saved image

Use getStaticProps to generate image#

Using getOpenGraphImage at getStaticProps will help us to generate openGraph images of the blog post automatically.

jsx
1/* pages/blog/[post].js */
2
3export const getStaticProps = async ({ params }) => {
4 const { post } = params;
5 const { frontmatter, source } = await getPost(post);
6 const openGraphImage = await getOpenGraphImage(`/?title=${frontmatter.title}`);
7 return {
8 props: {
9 frontmatter,
10 source,
11 openGraphImage,
12 }
13 };
14};

Adapting SEO to your static site Next.js project#

Last but not least, we need to pass openGraph image to the SEO. next-seo package will help us to do that.

Setting SEO to your project#

terminal
1npm install next-seo
jsx
1/* pages/blog/[post].js */
2import Head from 'next/head';
3import { NextSeo } from 'next-seo';
4
5export default function BlogPost({ frontmatter, source, openGraphImage }) {
6 const { title, description, slug } = frontmatter;
7 return (
8 <Layout>
9 <Head>
10 <NextSeo
11 title={title}
12 description={description}
13 openGraph={{
14 title,
15 description,
16 url: `${process.env.SITE_URL}/${slug}`,
17 images: [{
18 url: openGraphImage
19 }]
20 }}
21 />
22 </Head>
23 {source}
24 </Layout>
25 )
26}

Well done! Redeploy your static site and see what happens.