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).
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 :
{{#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
...
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 :
<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 :
// ./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 🤣
Top comments (1)
by the way if you want to deploy this on heroku, you need to do the following fix : stackoverflow.com/a/55090914
which involves :
vs.
Cheers,
Alex