13 min read

How to Make a Custom Open Graph Image Using Puppeteer

Make use of Puppeteer’s screenshot functionality and create an Open Graph image generator to show custom social sharing images on Twitter, Facebook, and other social media.

by Josephine Loo · August 2022
How to Make a Custom Open Graph Image Using Puppeteer
How to Make a Custom Open Graph Image Using Puppeteer

Contents

    Have you ever shared your Github repo on social media and wondered how they display your repo statistics like contributors, issues, stars, etc. on the social sharing image?

    The social sharing image is also known as the Open Graph image or OG image. Creating a custom Open Graph image for your website not only makes your post stand out but can also help your audience to understand the context better when you display additional info on the image.

    In this tutorial, I will show you how to create an Open Graph image generator using Puppeteer so that a unique image can be created for different pages automatically when you share your website on social media like Twitter and Facebook.

    What is Puppeteer

    Puppeteer is a Node library that is open source and maintained by Google. It is developed to provide a high-level API to control Chrome or Chromium over Chrome DevTools Protocol.

    Puppeteer is commonly used by developers to automate the browser to run website tests. It is also often used to generate screenshots and PDFs of pages, crawl web pages, automate form submission, etc.

    Here are some articles that show how to use Puppeteer to do some of the jobs above:

    How Does the Open Graph Image Generator Work

    Making a custom Open Graph image using Puppeteer relies on Puppeteer’s screenshot functionality.

    To make a custom Open Graph image using Puppeteer, we will need to set the content of the page launched by Puppeteer using HTML.

    class Page {
      setContent(html: string, options?: WaitForOptions): Promise<void>;
    }
    

    We will need to create an HTML template of the Open Graph image design with some variables so that the text and the featured image can be set dynamically.

    For example, you can create some variables and set their values to the title and description of your web page. When you share different pages of your website, their respective titles and descriptions will be displayed on the Open Graph image.

    Puppeteer will launch a new page, render the HTML code and take a screenshot of the whole page.

    Screenshot 2022-08-20 at 6.17.17 PM.png

    This will be the result of the screenshot:

    Now that you know how you can use Puppeteer to create a custom Open Graph image, let’s get started!

    Pre-requisites

    To use Puppeteer, you need to have these installed:

    For reference, these are the versions used in this tutorial:

    • Node.js - 18.6.0
    • npm - 8.13.2

    You can refer to the official documentation to check your version compatibility.

    Getting Started

    We will run a backend service using Express in Node.js to launch Puppeteer in headless mode to render the custom Open Graph image and take a screenshot.

    Step 1. Create a new Node.js Project

    Create a new folder for your project and go to the directory.

    mkdir puppeteer-open-graph
    cd puppeteer-open-graph
    

    Init a new Node.js project in the folder.

    npm init
    

    It will prompt you for input for a few aspects of the project, just press enter if you want to use the default values.

    Once you run through the npm init steps above, a package.json file will be generated and placed in the current directory.

    Step 2. Install and Import Required Packages

    Run npm i <package> to install the following packages:

    You should see a recent version of Chromium which is guaranteed to work with the Puppeteer downloaded when you install the puppeteer package.

    Screenshot 2022-06-13 at 3.35.46 PM.png

    After you have done installing the packages, create a new file named index.js and import express and cors inside the file.

    const express = require('express');
    const cors = require('cors');
    

    We will import puppeteer in another file later.

    Step 3. Enable CORS

    If your frontend is running on a different domain, you need to configure your Express server to allow the frontend from another origin to access the backend service.

    const corsOptions = {
      origin: 'http://localhost:3000', //replace this with your frontend domain
      optionsSuccessStatus: 200
    };
    
    const app = express();
    app.use(cors(corsOptions));
    

    ❗️ Note : You might run into an error if you skip this step. To understand more about CORS, you can read "What is a CORS Error and How to Fix It (3 Ways)".

    Step 4. Start the Express Server

    Paste the following code in index.js and run node index.js in the terminal/command line.

    const port = 8000;
    app.listen(port, () => {
      console.log(`Example app listening on port ${port}`)
    });
    
    app.get('/', (req, res) => {
      res.send('Hello World!')
    });
    

    You should see the server running at http://localhost:8000/.

    a screenshot of Express server running

    Creating the Puppeteer Screenshot Service

    Step 1. Prepare an HTML Template

    Create a new file named template.js and add a function that will return the HTML template of the Open Graph image design.

    The values of the variables in the template (title, description, and img) will be set from the function’s parameter and make every image generated unique.

    template.js

    exports.getHtml = function (title, description, img) {
    
      var css = `
        html, body {
          height: 100%;
          width: 100%;
        }
        
        .title {
          font-family: 'DM Serif Display', serif;
          font-size: 55px;
        }
        
        .description {
          font-size: 25px;
          color: #676565
        }
        
        .image-text{
          width: 80%
        }
        
        .bg {
          background-image: url(${img});
          background-size: 1200px 630px;
          background-repeat: no-repeat;
          display: block;
          width:60%;
          height:100%;
        }`
    
      return `
      <!doctype html>
      <html lang="en">
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Bootstrap demo</title>
          <link rel="preconnect" href="https://fonts.googleapis.com">
          <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
          <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display&display=swap" rel="stylesheet">
          <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
        </head>
        
        <body class="d-flex align-items-center">
          <div class="m-5 image-text">
            <div class="title">${title}</div>
            <p class="description mt-3">${description}</p>
          </div>
          <div class="bg"></div>
        </body>
        <style>${css}</style>
      </html>`
    };
    

    Step 2. Create a Service Endpoint

    In index.js, add an endpoint for the Puppeteer screenshot service.

    const puppeteer = require('./puppeteer');
    
    app.get('/og-image', puppeteer.generateImage);
    

    The endpoint will receive the title, description, and image from the URL query parameters. We will pass these values to puppeteer.generateImage to generate an image with the values.

    https://www.your-domain.com/og-image?title={title}&description={description}&img={img}
    

    Step 3. Screenshot Using Puppeteer

    Create a new file named puppeteer.js and create a callback function generateImage() that will receive title, description, and img from the GET request parameter.

    These values will be inserted into the HTML template. Then, Puppeteer will render the HTML and take a screenshot with the viewport size set to 1200x630, which is the size of a common Open Graph image.

    puppeteer.js

    const template = require('./template');
    const puppeteer = require('puppeteer');
    
    exports.generateImage = async function (req, res) {
    
      const { title, description, img } = await req.query;
    
      const browser = await puppeteer.launch();
    
      const page = await browser.newPage();
    
      await page.setViewport({ width: 1200, height: 630 });
    
      await page.setContent(template.getHtml(title, description, img));
    
      const image = await page.screenshot({ type: 'jpeg' });
    
      res.statusCode = 200;
      res.setHeader('Content-Type', `image/jpeg`);
      res.setHeader('Cache-Control', `public, immutable, no-transform, s-maxage=31536000, max-age=31536000`);
      res.end(image);
    };
    

    Step 4. Testing the Service

    You can test the service by sending a sample GET request to the endpoint.

    http://localhost:8000/og-image?title=Test%20Title&description=Test%20Description&img=https://images.unsplash.com/photo-1492619193369-af2352531443?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1464&q=80
    

    The values sent in the parameter should be displayed on the image generated.

    the result of sending a sample request to the Puppeteer Open Graph image generator

    To use the service to generate custom Open Graph images for your website, you need generate URLs to the service dynamically for your pages and use them in the meta tag og:image.

    a screenshot of the og:img meta tag

    💻 You can check out the full code of this project from this Github repo.

    Pros vs. Cons

    Using Puppeteer to create custom Open Graph images for your website dynamically is one of the simplest solutions. However, there are some pros and cons:

    ✅ Pros

    • Free and open source
    • Easy to implement
    • A great number of community members (>79.5k)

    ❌ Cons

    • Puppeteer screenshots can be slow
    • Need to convert the image design to HTML
    • Need to render the HTML to preview the design

    For developers who are proficient at frontend coding, Puppeteer is a good option to generate dynamic Open Graph images for a website. However, creating the image template in HTML could be a hurdle if you are bad at frontend coding.

    Using Bannerbear

    If you find creating an image template in HTML difficult, there's another solution. Instead of writing HTML and CSS, you can create an image template using a drag-n-drop interface by using Bannerbear to generate the custom Open Graph images.

    You can see how it works by following these tutorials:

    Happy hacking!

    Josephine Loo
    Josephine is an automation enthusiast. She loves automating stuff and helping people to increase productivity with automation.

    Follow the Journey

    Hello I'm Jon, the founder of Bannerbear — every 2 weeks I send a newsletter with updates from the Product, Marketing and Business sides of my startup, subscribe below to receive it!