Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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

  1. Open Chrome and press F12 (or choose More tools → Developer tools).
  2. Select the Performance panel.
  3. Use the panel’s load/open control to choose trace.json.
  4. 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does 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.

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.