In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.
Puppeteer Performance Monitoring with Inspector
In this article I'll show you how to monitor performance and errors of a browser automation script written with Puppeteer.
Most things that you can do manually in the browser can be done programmatically using Puppeteer! But implementing browser automations in a server-side script makes it difficult to understand the resource consumption and performance implications of any step of the automation.
I’m Valerio, software engineer and CTO at Inspector, a tool that helps you find bugs and bottlenecks in your applications automatically. Before your customers stumble onto the problem.
One of the most useful things when it comes to monitoring is the ability to monitor not only the general execution performance, but build the timeline of all the individual tasks that make up the automation script.
To configure a new project create a new directory and run the init command inside it:
mkdir puppeteer-performance & cd puppeteer-performance & 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.
After completing the init process a package.json
file will be generated and placed in the current directory.
Run the command below to install Puppeteer in your project:
npm install puppeteer
During the installation process Puppeteer also automatically downloads a recent version of Chromium that will be used behind the scene to execute browser commands.
Now we can create the index.js file in the project directory. This is where we put the code to make screenshots with Puppeteer.
// Include Puppeteerconst puppeteer = require("puppeteer");
(async () => { // Create a browser instance const browser = await puppeteer.launch();
// Create a new page const page = await browser.newPage();
// Set viewport width and height await page.setViewport({ width: 1280, height: 720 });
// Open a URL await page.goto("https://screenshotone.com", { waitUntil: "networkidle0" });
// Capture screenshot await page.screenshot({ path: "screenshot.jpg" });
// Close the browser instance await browser.close();})();
Execute the code by running node index.js in your terminal and you should see the new file “screenshot.jpg” appearing in the project directory.
We are ready to integrate performance monitoring.
Run the command below to install the Inspector nodejs module:
npm install @inspector-apm/inspector-nodejs
As recommended in the official documentation, you should initialize the module at the beginning of the script. Before requiring any other module.
To get an Ingestion Key you have to register an account on Inspector and create a new project.
Other than the initializing the module I start the transaction at line 15. This line tell Inspector to start monitoring.
/* * ------------------------------------------- * Initialize Inspector with the Ingestion Key. * ------------------------------------------- */const inspector = require("@inspector-apm/inspector-nodejs")({ ingestionKey: "9cd5715238227ada16ed0f0e2e5323434ce1437b",});
// Include Puppeteerconst puppeteer = require("puppeteer");
(async () => { // Start a transaction let transaction = inspector.startTransaction("puppeteer");
// Create a browser instance const browser = await puppeteer.launch();
// Create a new page const page = await browser.newPage();
// Set viewport width and height await page.setViewport({ width: 1280, height: 720 });
// Open a URL await page.goto("https://inspector.dev", { waitUntil: "networkidle0" });
// Capture screenshot await page.screenshot({ path: "screenshot.jpg" });
// Close the browser instance await browser.close();
transaction.setResult("success");})();
After running the script you should see the new transaction coming in your dashboard:
Now we are aware that the execution of the script takes 4.5 seconds and uses 18MB of memory. But… What is the impact of each statement inside the script?
The inspector library has a really simple API to add custom segments during a transaction. You can wrap any line of codes you write into the addSegment()
method to monitor the impact they have within the execution flow.
Here is the script with segments:
/* * ------------------------------------------- * Initialize Inspector with the Ingestion Key. * ------------------------------------------- */const inspector = require('@inspector-apm/inspector-nodejs')({ ingestionKey: 'xxxxxxxxxxxxxxxxxxx'});
// Include Puppeteerconst puppeteer = require('puppeteer');
(async () => { // Start a transaction let transaction = inspector.startTransaction("puppeteer");
// Create a browser instance const browser = await inspector.addSegment(segment => { return puppeteer.launch(); }, 'launch');
// Create a new page const page = await inspector.addSegment(async segment => { console.log('Create a new page'); return await browser.newPage(); }, 'new-page');
// Set viewport width and height await page.setViewport({width: 1280, height: 720});
// Open a URL await inspector.addSegment(async segment => { await page.goto('https://screenshotone.dev', {waitUntil: 'networkidle0'}); }, 'goto', 'https://screenshotone.com
// Capture screenshot await inspector.addSegment(async segment => { await page.screenshot({path: 'screenshot.jpg'}); }, 'screenshot', true);
// Close the browser instance await browser.close();
transaction.setResult('success');})();
Execute the script again running the command node index.js in your terminal.
Now you can explore the execution details of each task in the script. And you will immediately see that the most impactful task is the opening of the URL.
It would be even more useful to receive alerts in case an exception is thrown at runtime and execution fails. The tool and the library should allow you to catch these events.
Inspector detects unhandled errors by default. You can try adding a throw
statement to simulate an error making the screenshot.
/* * ------------------------------------------- * Initialize Inspector with the Ingestion Key. * ------------------------------------------- */const inspector = require('@inspector-apm/inspector-nodejs')({ ingestionKey: '9cd5715238227ada16ed0f0e2e5323434ce1437b'});
// Include Puppeteerconst puppeteer = require('puppeteer');
(async () => { // Start a transaction let transaction = inspector.startTransaction("puppeteer");
// Create a browser instance {...}
// Create a new page {...}
// Set viewport width and height {...}
// Open a URL {...}
// Capture screenshot (Throw Error) throw new Error('Unable to write file.');
{...}})();
You will immediately receive an alert via email and a complete report will be available in project dashboard.
I hope the code snippets have been helpful for you to better understand what performance monitoring is in practical terms.
You can use this script to compare the performance of different headless browsers for example (like, Puppeteer or Selenium) and make a better decision about which one to use in your scripts.
If you want learn more about Inspector, visit the official website—inspector.dev.
Interviews, tips, guides, industry best practices, and news.
Puppeteer allows blocking any outgoing requests while loading the page. Whether you want to block ads, tracking scripts, or different types of resources, it is relatively easy to do with Puppeteer.
Making screenshots of the websites with Puppeteer can be tricky. A lot of pitfalls wait for us. Let's examine Puppeteer on a set of "screenshotting" problems and tackle arising pitfalls.
Join me in exploring how to find the ideal wait time or event of when to take the page screenshot with Puppeteer.
Exhaustive documentation, ready SDKs, no-code tools, and other automation to help you render website screenshots and outsource all the boring work related to that to us.