Generate your social share images automatically in expressjs.
Tags: showdev, node, express, puppeteer
Published: 2020-03-30 20:26:50

---
title: Generate your social share images automatically in expressjs.
published: true
description: In this article I will show you how to quickly generate dynamic images using puppeteer, nodejs, and express.js.
tags: showdev, nodejs, expressjs, puppeteer
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/x1h9knedcuyxamcvvfjx.png
---

I wanted to do exactly as my cover image shows. I wanted to add an image to my social media cards and I wanted this image to be generated on the fly. I used [twitter's] card preview feature to test my implementation. 

In my express.js app I wanted to see if I could generate images of a web page. So, I went with the idea of taking web page screenshot and, then, using this screenshot as my social media card. This is done by setting the two image properties in my meta tags (just as I show you below).

![`"og:image"` and `"twitter:image"` meta tags](https://dev-to-uploads.s3.amazonaws.com/i/9dye18f0b2i53uc3pxb8.png)

The two SEO image tags that I needed to be dynamic were : `"og:image"` and `"twitter:image"`. I adjusted the express.js project by going into my [handlebarsjs] layout template and adding an if statement. 

The if statement simply looks for the presence of `page_image` variable as one of the attributes passed on to the template. If the variable exists, then simply populate its content wherever we need it. Or, in other words :

```js
 {{#if page_image}}
  <meta name="og:image" content="{{page_image}}">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:image" content="{{page_image}}">
  {{else}}
  <meta name="twitter:card" content="summary">
  {{/if}}
```

From above, `page_image` variable holds just a simple string that show the location to my dynamic image generation function. The string is a combination of simply taking a residence slug and adding `/image` to it. 

So, if we are rendering the following page `https://12313200.ngrok.io/residences/elim-village-british-columbia-reviews`, then the image url will be `https://12313200.ngrok.io/residences/elim-village-british-columbia-reviews/image`. This string is just passed on as data to the template.


For example, the following code 

```js

...

res.render(`template`,{
page_image : `https://12313200.ngrok.io/residences/elim-village-british-columbia-reviews/image`
});

...

```

would translate to the if statement above evaluating to true, in the [handlebarsjs] template, and the attached html code of the block was : 

```html
<meta name="og:image" content="https://12313200.ngrok.io/residences/elim-village-british-columbia-reviews/image">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://12313200.ngrok.io/residences/elim-village-british-columbia-reviews/image">
```

Perfect, now our routes are dynamic just like I wanted. Now, I needed to implement the actual `router.get('/image')` function. We go to our terminal and type in the following to install puppeteer and add it to our project

```
npm install puppeteer --save
```

then we just code the end point that we want above. Mine looked like this :

```js
// ./routes/residences.js
const express = require('express');
const puppeteer = require('puppeteer');

const router = express.Router();

...

// equivalent to :
// https://12313200.ngrok.io/residences/:slug/image
router.get('/:slug/image', async (req, res, next) => {
  const { slug } = req.params; 
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(`https://12313200.ngrok.io/residences/${slug}`);
  const screenshot = await page.screenshot({
    type: 'png',
    encoding: 'binary'
  });
  await browser.close();
  res.send(screenshot);
});

...

module.exports = router;
```

Woot! Added a new `get /image` route that sends a dynamic screenshot image of the webpage. Just as the cover image shows, the newly created dynamic image adds a bit more value to the existing social cards. Your cards now show to the user exactly what the page looks like before they think of clicking on the social card to view it. If they click on the card and go to the actual page, then they view a familiar UI that was presented to them in the social card.

There you have it. Have you tried something similar? Do you have suggestions or improvements to my code? Please let me know =)

Thanks,
Alex

PS: I used [ngrok] for this experiment so don't try to actually access the url 🤣

[handlebarsjs]: https://handlebarsjs.com/
[ngrok]: https://ngrok.com/
[twitter's]:https://cards-dev.twitter.com/validator