The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →The reliable way to benchmark Puppeteer is to measure one precisely defined browser task under a fixed environment, repeat it, report a distribution, and use tracing and page.metrics() to explain outliers. A single page.goto() time is not a universal Puppeteer score: it changes with readiness criteria, cache state, network, browser build, machine load, and whether diagnostics are enabled.
1. Define exactly what “performance” means
Start with a question that has one start boundary, one end boundary, and one representative workload. Examples include:
- Navigation: elapsed time from issuing
page.goto()until a named application-ready selector appears. - Interaction: elapsed time from clicking a control until the resulting UI reaches a stable state.
- Rendering: browser work and visual activity during a defined interval, diagnosed with a trace.
Do not compare a run that ends at the load event with one that ends when an application-specific selector appears. Those are different experiments. Write down whether the result represents website work, the automation workflow, or both. Keep navigation, waits, interactions, and output generation identical in every comparison.
2. Pin and record the test environment
Within a comparison, hold the environment constant and record it beside every result. Puppeteer releases are tightly bundled with browser revisions to preserve protocol compatibility; replacing the bundled browser is done at the user’s risk. Record the exact Puppeteer package version and browser version rather than saying only “Chrome.”
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
- Create a mix using audio, music and voice tracks and recordings.
- Customize your tracks with amazing effects and helpful editing tools.
- Use tools like the Beat Maker and Midi Creator.
- Work efficiently by using Bookmarks and tools like Effect Chain, which allow you to apply multiple effects at a time
- Use one of the many other NCH multimedia applications that are integrated with MixPad.
- Operating system, CPU and memory class, and whether other CPU-heavy jobs are running.
- Puppeteer and browser versions (including the browser revision used by Puppeteer).
- Headless or headful mode, viewport dimensions, device scale factor, and any device emulation.
- Network path, proxy, DNS conditions, and whether CPU or network throttling is active.
- Concurrency: number of browser processes, pages, workers, and other tests sharing the host.
- Cache and storage policy: cold first visit, warm repeat visit, or a deliberately reset profile.
Chrome guidance notes that extensions can add noise. Use a clean profile unless extensions are part of the workload. Clearing storage models first-visit behavior; preserving storage models repeat visits. Decide whether warm-up runs are excluded before looking at the results, and apply that rule to every variant. DevTools CPU throttling is relative to the host computer, not an exact simulation of a phone’s processor, so report the setting and do not label it as a specific mobile device.
3. Build a repeatable Node.js harness
The following script measures an application-ready navigation, captures supporting browser metrics, and writes one JSON record per run. Replace the URL and selector with the task you actually want to compare.
const puppeteer = require('puppeteer');
const URL = 'https://example.com';
const READY_SELECTOR = 'body';
const RUNS = 10;
(async () => {
const browser = await puppeteer.launch({ headless: true });
const results = [];
try {
for (let i = 0; i < RUNS; i++) {
const page = await browser.newPage();
await page.setViewport({ width: 1365, height: 768, deviceScaleFactor: 1 });
const start = process.hrtime.bigint();
await page.goto(URL, { waitUntil: 'domcontentloaded', timeout: 90000 });
await page.waitForSelector(READY_SELECTOR, { visible: true, timeout: 90000 });
const end = process.hrtime.bigint();
const metrics = await page.metrics();
results.push({
run: i + 1,
elapsed_ms: Number(end - start) / 1e6,
metrics
});
await page.close();
}
} finally {
await browser.close();
}
console.log(JSON.stringify(results, null, 2));
})();
process.hrtime.bigint() is a monotonic Node-side clock, suitable for end-to-end elapsed time. The timed interval includes navigation and the readiness wait, so it answers “how long did this automated task take?” It does not claim to isolate page rendering from Puppeteer orchestration.
If the task is an interaction, place the start clock immediately before the action and the end clock after the stable-state condition. Avoid arbitrary sleeps when a selector, application signal, or network-idle rule can express readiness. If a delay is genuinely part of the user workflow, keep it identical in all runs.
4. Use page.metrics() as diagnostics, not a speed score
Puppeteer’s metrics API reports cumulative browser values for the sampled page. Depending on the browser revision, fields can include:
Rank #2
| Metric | What it helps answer | Important limitation |
|---|---|---|
TaskDuration |
How much browser task time accumulated | Not wall-clock test duration |
ScriptDuration |
How much JavaScript execution accumulated | Interpret with the workload and trace |
LayoutDuration and RecalcStyleDuration |
How much layout and style recalculation accumulated | Do not identify the responsible code by themselves |
Documents, Frames, Nodes, JSEventListeners |
Structural complexity during the sample | Counts are not direct measures of perceived speed |
JSHeapTotalSize and JSHeapUsedSize |
JavaScript heap size at collection time | Values depend on page state and garbage collection |
LayoutCount and RecalcStyleCount |
How often layout or style recalculation occurred | Frequency alone does not establish user impact |
The Timestamp value is monotonic seconds from an arbitrary point, not a wall-clock date. Durations are browser-reported cumulative values; compare like with like and keep the exact sampling point consistent. A high TaskDuration with a high ScriptDuration suggests scripting work worth investigating. High layout or style values suggest rendering work, but a trace is needed to locate the cause.
5. Repeat runs and summarize the distribution
Run enough repetitions to reveal variability, then publish the run count, raw observations when practical, a median, and a spread measure such as minimum–maximum or percentile values. There is no official Puppeteer rule that prescribes a particular repetition count or statistic, so state your methodology instead of presenting one as a standard.
Do not report only the fastest run. A slow run may reflect contention, a cache miss, a transient network delay, or a real page problem. Define invalid-run rules before examining results: for example, treat a navigation timeout as a failed run and report its count rather than silently deleting it. If you exclude an initial warm-up, say how many were excluded and apply that choice to every candidate.
A small Node summarizer for the JSON produced above can calculate median and range:
function median(values) {
const sorted = [...values].sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
return sorted.length % 2
? sorted[middle]
: (sorted[middle - 1] + sorted[middle]) / 2;
}
const times = results.filter(r => Number.isFinite(r.elapsed_ms))
.map(r => r.elapsed_ms);
console.log({
runs: times.length,
median_ms: median(times),
min_ms: Math.min(...times),
max_ms: Math.max(...times)
});
Keep the raw data with the report. A median without the number of runs, environment, readiness condition, and cache policy cannot be reproduced or fairly compared.
6. Trace a separate diagnostic run
When timings change, tracing shows where browser activity occurred. Keep profiled runs separate from headline timing runs because collecting detailed diagnostics can alter the workload. Puppeteer permits one active trace per browser and can write trace bytes to a file.
const fs = require('fs');
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: 1365, height: 768, deviceScaleFactor: 1 });
await page.tracing.start({
path: 'puppeteer-trace.json',
screenshots: false,
categories: ['devtools.timeline', 'disabled-by-default-devtools.timeline']
});
await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 90000
});
await page.waitForSelector('body', { visible: true, timeout: 90000 });
await page.tracing.stop();
await browser.close();
console.log('Trace written to puppeteer-trace.json');
})();
Open the trace in Chrome DevTools or a compatible timeline viewer. Look for long scripting, rendering, network, or idle intervals and correlate them with your task boundaries. The DevTools Performance panel also supports User Timing marks and measures, runtime recordings, and throttling. Add marks around meaningful phases when a single elapsed number is not enough to explain a regression.
Recommended Free Tools
7. Compare the right cases
| Comparison | Hold constant or disclose | Question it can answer |
|---|---|---|
| Cold versus warm | Profile reset and storage policy | First-visit or repeat-visit behavior? |
| Unthrottled versus throttled | Exact CPU/network settings and host hardware | How does the workflow react to constrained conditions? |
| Headless versus headful | Browser build, viewport, and all waits | Does display mode alter this workload? |
| Automation stacks | Same task, readiness condition, browser, and host | Which orchestration fits this workload, not which is universally faster? |
| Raw versus profiled | Whether tracing or other instrumentation is enabled | What changed, and what diagnostic overhead was introduced? |
Puppeteer’s stated design principle is “almost zero performance overhead over an automated page.” That is a project goal, not a measured guarantee for every workload; do not turn it into an overhead percentage without your own controlled experiment. Likewise, a local synthetic benchmark describes your selected machine and conditions, not all real users. Where available, compare laboratory findings with field data rather than treating one as a substitute for the other.
8. Troubleshooting slow or unstable benchmarks
Every run times out
Check that the URL is reachable from the benchmark host, raise the timeout only when the task legitimately needs it, and verify that the readiness selector exists in the tested state. Log the navigation error and classify the run as failed instead of converting it to an unusually large duration.
Results vary widely
Look for concurrent jobs, background updates, shared browser processes, changing cache state, extensions, proxy variance, and network contention. Use a clean profile, isolate the host, and separate cold and warm experiments.
Metrics look high but elapsed time is normal
Metrics are cumulative browser diagnostics, not wall-clock duration. Confirm that you sampled at the same boundary, then use a trace to determine whether scripting, layout, style recalculation, or repeated tasks explain the values.
Free tools Windows power users keep installed
One-click scans. No signup required.
Headless and headful numbers disagree
That is a different experiment. Keep mode fixed for a focused comparison, or report the mode change explicitly along with viewport, display environment, and browser version.
Tracing fails to start
Only one trace can be active per browser. Stop an existing trace before starting another, and ensure the output path is writable. Keep tracing out of the headline timing loop if it changes results.
A throttled test does not resemble a phone
DevTools throttling scales relative to the current host and cannot reproduce a phone’s processor architecture. Report the host and throttle settings, and avoid claiming device-equivalent results.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.9. Automate reporting and preserve evidence
Store each run’s elapsed time, success or failure, browser and Puppeteer versions, environment settings, cache policy, and diagnostic metrics. Record the exact script, URL revision or test data, readiness condition, and concurrency. A useful report lets another engineer rerun the same workload and distinguish a page regression from host noise. When comparing browser versions or environments, either keep the rest fixed or label the environment change as part of the experiment.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Best Value
Or skip the browser setup
If your goal is repeatable website captures rather than measuring Puppeteer itself, ScreenshotNeo provides a single HTTP request that returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
See the ScreenshotNeo API documentation for all options. A minimal cURL call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The equivalent Python request is:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
And Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also includes an MCP server so Claude, Cursor, and other MCP clients can call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account to try it.
FAQ
Is there an official number of Puppeteer runs I must perform?
No. Official documentation does not prescribe a universal repetition count or summary statistic. Choose enough repetitions to expose variability and document the choice.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsCan page.metrics() replace a trace?
No. Metrics summarize cumulative browser values; tracing supplies a timeline that can locate the activity responsible for a change.
Should I benchmark with the browser bundled by Puppeteer?
For a controlled comparison, yes, or document any replacement precisely. Puppeteer bundles browser revisions for protocol compatibility, and substituting another browser is at the user’s risk.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

