Use Puppeteer’s tracing API: call page.tracing.start() immediately before the navigation or interaction you want to measure, then call page.tracing.stop() afterward. Give start() a file path and Puppeteer writes a trace that opens in Chrome DevTools’ Performance panel or Chrome’s timeline viewer.
This guide shows a complete Node.js workflow, explains screenshots and trace categories, covers file size and privacy decisions, and includes recovery steps for common failures.
Record a timeline in Puppeteer
Install Puppeteer in a Node.js project, launch Chromium, create a page, start tracing, perform the workload, stop tracing, and close the browser. The trace should surround only the activity you want to inspect; recording browser startup or unrelated teardown makes the timeline harder to interpret.
Prerequisites
- A current Node.js installation with permission to launch Chromium.
- A project containing Puppeteer:
npm install puppeteer. - A URL that your test environment can reach.
- Enough disk space for the trace and any optional screenshots or embedded resources.
Minimal trace script
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.tracing.start({ path: 'trace.json' });
await page.goto('https://www.google.com');
await page.tracing.stop();
await browser.close();
Run the file as an ES module (for example, save it as trace.mjs and execute node trace.mjs). The resulting trace.json is the artifact you load into DevTools.
#1 Best Overall
A practical page-load profile
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.tracing.start({
path: 'trace.json',
screenshots: false,
});
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
// Put the interactions or additional navigation you want to profile here.
await page.tracing.stop();
await browser.close();
waitUntil: 'networkidle0' waits until there are no active network connections for the settling period used by Puppeteer. Pages with analytics, polling, WebSockets or other long-lived connections may never reach that condition; use a different readiness signal or an explicit timeout in those cases.
Choose what the trace contains
Output path and in-memory output
path selects the file Puppeteer writes. If you omit it, tracing.stop() returns the trace bytes as a Uint8Array. This is useful when your application uploads the result, stores it in object storage, or applies its own naming and retention policy.
await page.tracing.start({ screenshots: false });
// ... workload ...
const traceBytes = await page.tracing.stop();
// traceBytes is a Uint8Array
Capture screenshots in the timeline
Tracing screenshots defaults to false. Set screenshots: true when you need visual frames aligned with main-thread activity:
await page.tracing.start({
path: 'trace-with-frames.json',
screenshots: true,
});
Frames add diagnostic context and can increase the artifact’s size. They are not a substitute for a dedicated screenshot: they represent frames emitted during tracing and are intended for timeline correlation.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Categories
The default category set includes DevTools timeline data, V8 execution, frame and stack data, top-level activity, console and user-timing events, latency information, and the disabled-by-default V8 CPU profiler. With screenshots enabled, Puppeteer adds the disabled-by-default DevTools screenshot category. You can pass a categories array to include or exclude tracing categories when you need a narrower or specialized recording.
Rank #2
Trace buffer considerations
When no buffer size is specified (or it is zero), the Chromium/Puppeteer tracing documentation describes a 200 MB (200,000 KB) default. That is a configuration default, not a benchmark or a guarantee that every trace can grow to that size. Long recordings, verbose categories and screenshots can still create large files, so keep captures focused and monitor disk usage.
Keep the lifecycle correct
Only one trace can be active at a time per browser. Starting a second recording while one is active is rejected by Puppeteer. Use one start/stop pair for each measured segment, and always stop tracing before starting another segment.
await page.tracing.start({ path: 'checkout.json' });
await page.goto('https://example.com/checkout');
await page.click('#pay');
await page.tracing.stop();
await page.tracing.start({ path: 'confirmation.json' });
await page.waitForSelector('.confirmation');
await page.tracing.stop();
For reliable cleanup when a navigation or interaction throws, put the stop and browser close operations in a finally block. If stopping itself fails because tracing never started, guard that call with a flag.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
let tracing = false;
try {
await page.tracing.start({ path: 'run.json' });
tracing = true;
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.click('body');
} finally {
if (tracing) await page.tracing.stop();
await browser.close();
}
Open and inspect the saved timeline
- Open Chrome and press
F12(or choose More tools → Developer tools). - Select the Performance panel.
- Use the panel’s load/open control to choose
trace.json. - Inspect the main-thread track, event timing, frames (if enabled), user-timing marks and related tracks.
Puppeteer’s tracing output can also be opened in Chrome’s timeline viewer. Keep the trace with the test commit, URL, browser version and run conditions that produced it; otherwise a later comparison may mix application changes with environment changes.
Privacy, compression and sharing
A DevTools-saved recording can include annotations, resource content, source maps and gzip compression. Resource content embeds HTML, JavaScript and CSS so the Sources panel can display those files. Source maps can reveal authored source names and mappings. For private applications, treat such traces as sensitive artifacts.
- Need the smallest, least revealing file? Leave resource content and source maps out when exporting from DevTools.
- Need source-level debugging? Include them, but restrict access and retention.
- Need to upload or archive traces? Compression reduces disk usage and transfer time. Chrome’s current documentation says gzip compression is the default from Chrome 142.
- Need plain-text inspection? An uncompressed file is easier to inspect directly, at the cost of size.
Profile a specific interaction
Start tracing directly before the action, not minutes earlier. Add User Timing marks so the event is easy to locate in the Performance panel:
await page.tracing.start({ path: 'search.json', screenshots: true });
await page.evaluate(() => performance.mark('search-start'));
await page.fill('#search', 'puppeteer');
await page.click('#submit');
await page.waitForSelector('.results');
await page.evaluate(() => performance.mark('search-end'));
await page.tracing.stop();
The marks appear alongside browser events and help distinguish your intended interval from framework, advertisement or background activity.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteWhen Puppeteer tracing is not the best export path
Puppeteer is strongest when navigation and interactions must be automated in the same script that records them. DevTools’ own recording workflow is better when a person needs to annotate a session, choose resource and source-map inclusion interactively, and share a recording from the browser UI. Both approaches produce timeline data; they differ mainly in automation, export controls and how much content travels with the artifact.
Or skip the browser setup
If you only need a clean image or PDF of a URL rather than a Chrome performance timeline, ScreenshotNeo is a direct API option. It accepts 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, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
Use the API documentation at https://screenshotneo.com/docs/ for parameters and authentication. A one-call image request looks like this:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same request in Python:
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 in 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 includes full-page and element capture, device presets and custom viewports, retina scale, dark mode, PDF controls, HTML/CSS rendering, custom JavaScript and CSS, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation. It also supports transparent backgrounds, resizing, configurable caching, signed links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 shots. Yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to begin.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting
No trace file appears
Confirm that tracing.start() completed, that the process reached tracing.stop(), and that the path is writable relative to the process’s current working directory. Log process.cwd() when running from a test runner or CI system.
“Tracing already started”
A prior recording is still active. Stop it before starting another, and avoid parallel trace sessions on the same browser instance.
The trace is empty or ends too soon
Start tracing before navigation or the interaction under test. Await every action and stop only after the final event has completed.
Free tools Windows power users keep installed
One-click scans. No signup required.
Navigation never finishes
networkidle0 is unsuitable for pages with persistent connections or polling. Use domcontentloaded, load, a specific selector, or an explicit application-ready condition.
Best Value
DevTools rejects the file
Make sure the file is the bytes returned by Puppeteer’s stop operation or the complete path output, rather than a log file or partially uploaded artifact. Re-run with a shorter capture and verify that the process exits after tracing stops.
The file is too large or exposes private code
Disable screenshots unless visual frames are needed, narrow categories, shorten the measured interval, and omit resource content or source maps when exporting from DevTools. Compress before transfer and protect access to the artifact.
Frequently Asked Questions
Can I record more than one trace in a Puppeteer test?
Yes, but only sequentially on each browser instance: stop the first recording before calling tracing.start() again.
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 reinstallDoes tracing automatically create screenshots?
No. The screenshots option defaults to false; set screenshots: true when timeline frames are useful.
What does tracing.stop() return without a path?
It returns the trace data as a Uint8Array, allowing your code to upload or store it without writing a local file.
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.

