I have a few websites which I keep up to date, and one of the things that caused me a recurring headache was remembering to update my open graph meta tag preview images every time I made a change. Reshooting preview images with my old flow was cumbersome; I'd have to fire up my local dev server, set my localStorage data stores to get the display elements to look correct, scale the browser window to just the right dimensions, then finally attempt to capture the screen down to the exact pixel (which usually took a few attempts).
In my ongoing effort to automate all the things, I spent some time with Puppeteer and relieved myself of this grunt work.

Configuration Steps
1. Install Puppeteer
First we'll install Puppeteer into our project, using the --save-dev
flag since we'll only need to use this marionette in development.
npm install puppeteer --save-dev
2. The Script
My script happens to live at /src/utils/marketingFunctions.js
, but anywhere under /src
should be just fine.
Once you have a home for our new script, let's flesh it out with some functionality. If you don't have any fresh JavaScript, store-bought is fine:
const puppeteer = require("puppeteer");
/* SETUP VARIABLES */
const CURRENT_SEASON_NUMBER = 16;
const DEVELOPMENT_URL = "http://localhost:3000/coded/gotahopuphere/";
/* END SETUP */
(async () => {
// 1. Launch the (headless) browser
const browser = await puppeteer.launch({
defaultViewport: {
width: 1200,
height: 630,
},
args: [
"--no-sandbox",
// any other puppeteer arguments you may need go here
],
});
// 2. Build the display data object
const tempData = {
seasonalAchievedLevel: new Array(CURRENT_SEASON_NUMBER).fill(null),
seasonalTreasurePacks: new Array(CURRENT_SEASON_NUMBER).fill(null),
seasonalPacks: [],
seasonalQuestPacks: new Array(CURRENT_SEASON_NUMBER).fill(null),
};
tempData.seasonalTreasurePacks.push(32);
tempData.seasonalQuestPacks.push(32);
// 3. Open a new page
const page = await browser.newPage();
// 4. Navigate to URL
await page.goto(DEVELOPMENT_URL);
// 5. Load the temp localStorage data
await page.evaluate((tempData) => {
localStorage.setItem("heirloomData", JSON.stringify(tempData));
localStorage.setItem("player-rank", '{"tier":"Silver","division":"IV"}');
}, tempData);
// 5a. Reload to display updated data model
await page.goto(DEVELOPMENT_URL);
// 6. Take screenshot #1
await page.screenshot({
path: "./public/gotahopuphere-dot-com.jpg",
type: "jpeg",
quality: 90,
});
// 7. Load dark localStorage data
await page.evaluate(() => {
localStorage.setItem("color-scheme", '"dark"');
});
// 7a. Reload to display updated data model
await page.goto(DEVELOPMENT_URL);
// 8. Take screenshot #2
await page.screenshot({
path: "./public/gotahopuphere-dot-com-dark.jpg",
type: "jpeg",
quality: 90,
});
// 9. Alert the console
console.log("Done!");
// 10. Finish up
await browser.close();
})();
4. Wire it Up
Finally, our last configuration step is to take our shiny new script and hook it into our package.json for ease of use. Head into your project's package.json and find the "scripts"
object, and add a command which calls our new marketing function:
...
},
"scripts": {
...
"screenshot": "node ./src/utils/marketingFunctions.js"
},
...
5. Try It!
The time is time, pop open a new terminal tab with your project running and run:
npm run screenshot
After a few moments, you should have freshly updated screenshots that look correct according to the data model you set up, dropped into place in your project ready for your next deploy.
Wrapping Up
This was yet another step in my quest of automating "all the things," and it seems like a great future opportunity to wire in this screenshot step into my GitHub CI/CD pipeline.
Automating away Open Graph metadata screenshots has saved me a ton of time - and frustration. I encourage you on every project to dive deeply (and infrequently!) into automation to push away little tasks like this over to the robots. Happy generating!