Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
CDP

How to Get Chrome DevTools Network Timing Data With Puppeteer

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

Use Puppeteer’s Chrome DevTools Protocol (CDP) session to capture Network events: enable the Network domain before navigation, then correlate request, response, and completion events by requestId. Save response.timing for phase timings such as DNS, connection, TLS, and response headers; calculate total elapsed time from the request and completion timestamps.

What you need to collect the Network timings

Puppeteer’s page-attached CDP session is the route to Chrome’s lower-level Network telemetry. The Network domain exposes request and response timing and lifecycle events (Chrome DevTools Protocol: Network). Puppeteer documents page.createCDPSession() for attaching that session (Puppeteer Page.createCDPSession) and CDPSession.send() for sending protocol commands (Puppeteer CDPSession.send).

  • Install Node.js and Puppeteer in a project that can launch Chrome or Chromium.
  • Enable Network before navigating; otherwise requests that begin before the listener is active will be missed.
  • Use requestId to join each request’s events. Do not match records only by URL: the same URL can be requested more than once.

The code below is an illustrative implementation of the documented API and protocol events; it has not been executed here. Pin your Puppeteer version in a real project and record the browser and protocol versions alongside results when comparing runs.

Capture request timing data with Puppeteer

Save this as an ES module such as timings.mjs, install Puppeteer with npm install puppeteer, then run node timings.mjs https://example.com. It logs a JSON record when each request completes or fails.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import puppeteer from 'puppeteer';

const target = process.argv[2] ?? 'https://example.com';
const browser = await puppeteer.launch();

try {
  const page = await browser.newPage();
  const cdp = await page.createCDPSession();
  const requests = new Map();

  cdp.on('Network.requestWillBeSent', event => {
    // A redirect can reuse requestId. Close the previous leg before storing
    // the new request, so each redirect hop has its own record.
    if (event.redirectResponse) {
      const previous = requests.get(event.requestId);
      if (previous) {
        previous.redirectResponse = event.redirectResponse;
        previous.redirected = true;
        console.log(JSON.stringify(previous));
      }
    }

    requests.set(event.requestId, {
      requestId: event.requestId,
      url: event.request.url,
      method: event.request.method,
      type: event.type,
      startedAt: event.timestamp,
      wallTime: event.wallTime,
      redirectResponse: event.redirectResponse ?? null,
    });
  });

  cdp.on('Network.responseReceived', event => {
    const record = requests.get(event.requestId);
    if (!record) return;
    record.status = event.response.status;
    record.mimeType = event.response.mimeType;
    record.fromDiskCache = event.response.fromDiskCache;
    record.fromServiceWorker = event.response.fromServiceWorker;
    record.timing = event.response.timing ?? null;
  });

  cdp.on('Network.loadingFinished', event => {
    const record = requests.get(event.requestId);
    if (!record) return;
    record.finishedAt = event.timestamp;
    record.totalMs = (event.timestamp - record.startedAt) * 1000;
    record.encodedDataLength = event.encodedDataLength;
    console.log(JSON.stringify(record));
    requests.delete(event.requestId);
  });

  cdp.on('Network.loadingFailed', event => {
    const record = requests.get(event.requestId);
    if (!record) return;
    record.failed = true;
    record.errorText = event.errorText;
    record.canceled = event.canceled ?? false;
    record.blockedReason = event.blockedReason ?? null;
    console.log(JSON.stringify(record));
    requests.delete(event.requestId);
  });

  await cdp.send('Network.enable');
  await page.goto(target, { waitUntil: 'networkidle0' });
} finally {
  await browser.close();
}

networkidle0 asks Puppeteer to wait for network activity to become idle, but some pages keep connections open or continually make requests. If that makes navigation wait indefinitely or longer than appropriate for your task, use a different documented page.goto() wait condition or a timeout strategy suitable for the page. The event handlers still observe requests after Network is enabled.

What each handler records

  • Network.requestWillBeSent starts the record, including URL, method, resource type, and a monotonic timestamp.
  • Network.responseReceived adds response status and MIME type, plus response.timing when Chrome supplies it.
  • Network.loadingFinished records completion and encoded response size. Its timestamp minus the request timestamp, multiplied by 1,000, gives total elapsed milliseconds.
  • Network.loadingFailed retains failures instead of silently dropping them. A failed network load and an HTTP error response are not the same: HTTP 404 or 503 responses can complete successfully at the HTTP transport level.

Redirects need separate legs

For a redirect, Chrome reports the prior response on a subsequent requestWillBeSent event, and the request continues as a new leg. The example emits the previous record when that happens, then starts a fresh record for the next URL. A full waterfall should show each leg separately rather than treating a redirect chain as one request (Puppeteer HTTPRequest lifecycle).

The redirect response is attached to the prior leg in this example. If your report needs every redirect response’s status, headers, and timing fields in the same schema as ordinary responseReceived events, enrich that leg from event.redirectResponse before emitting it.

Read the timing fields correctly

response.timing is not a set of independent durations. Its requestTime is a baseline in seconds; most phase values are millisecond offsets relative to that baseline. For a phase, subtract its start offset from its end offset. For example, dnsEnd - dnsStart is the DNS phase duration when both values are available. The protocol defines the fields and their meanings (Network.ResourceTiming).

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.
Fields What they describe How to use them
proxyStart, proxyEnd Proxy-related phase, when applicable. Subtract start from end only when both are meaningful.
dnsStart, dnsEnd DNS lookup phase. dnsEnd - dnsStart.
connectStart, connectEnd Connection establishment phase. connectEnd - connectStart.
sslStart, sslEnd TLS handshake phase, when applicable. sslEnd - sslStart.
sendStart, sendEnd Sending the request. sendEnd - sendStart.
receiveHeadersStart, receiveHeadersEnd Receiving response headers. The start is useful as a protocol-level waiting/TTFB measurement; the pair also shows the header-receive interval.

Worker-related timing fields may also appear. Preserve missing or negative values rather than converting them to zero: cache hits, reused connections, proxies, service workers, and protocol behavior can make some phases inapplicable or unavailable. A zero means a measured zero-duration phase; a missing value means the phase was not supplied, which is materially different.

Relate CDP measurements to the DevTools Timing tab

Chrome DevTools’ Network panel presents a request list, waterfall, total duration, latency, and a Timing tab. The Timing view groups work into request sent, waiting (TTFB), and content download; content download is the time spent reading the response body (Chrome DevTools Network reference). CDP exposes machine-readable events and timing fields underlying these measurements, while the UI’s labels are presentation groupings. The panel records requests while DevTools is open, and selecting a request exposes its Timing tab (Chrome DevTools Network panel reference).

Do not assume one CDP field will have an identical label or boundary to every UI grouping. Keep the raw fields in your output, document your derived calculations, and compare the same request and run conditions.

Choose which traffic belongs in your report

A page can generate more than its main document request. Depending on the question, you may want all observed traffic or a narrower slice. Record event.type and filter later, or filter as events arrive by type, URL, or frame. Decide explicitly whether the report includes:

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.
  • Cached responses and service-worker responses, which may not have ordinary network phases.
  • Preflight requests, worker traffic, and WebSocket activity.
  • Third-party scripts, analytics, images, and other subresources in addition to the document.

For reproducible comparisons, record the target URL, browser version, Puppeteer version, protocol version, run date, and relevant network conditions that you configured. A page’s timing changes with cache state, connection reuse, geographic location, server behavior, and background activity; a single capture is not a universal performance benchmark.

Handle extra-info events without assuming an order

Network.responseReceivedExtraInfo can provide additional response details, but it is not emitted for every request and can arrive before or after responseReceived. If you consume it, buffer it by requestId and merge when the matching record exists rather than relying on event order (Chrome DevTools Protocol: Network events).

The core example does not require extra-info events, which keeps the timing capture simpler. Add them only when you need their additional response data and can tolerate missing or reordered events.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common problems

No requests appear before navigation

Confirm that await cdp.send('Network.enable') completes before page.goto(), and attach listeners before navigating. A request already in progress when monitoring starts may not have a matching start record.

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

A record has no timing object

Keep timing: null when response.timing is absent. Do not infer DNS, TLS, or TTFB values from unrelated fields. The timing object is available only on responses that carry timing data.

Some phase values are missing or negative

This can be legitimate for cached responses, reused connections, proxies, service workers, or phases that do not apply. Preserve the raw values and avoid reporting a computed duration unless both endpoints are valid for that phase.

The request seems to disappear on HTTP 404 or 503

Check the loadingFinished handler, not just loadingFailed. HTTP error statuses still represent received responses and can finish normally; reserve the failed path for a loading failure and retain the status from responseReceived.

Redirect chains show only the final URL

Handle redirectResponse on requestWillBeSent before replacing the record for that request ID. Emit the previous leg, then start a new record. This preserves the waterfall sequence instead of collapsing the chain.

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

Navigation never reaches network idle

Some sites poll, stream, or keep connections open. Choose a navigation wait condition aligned with your capture goal rather than assuming all pages become idle. You can collect Network events while the page is active, then apply a bounded capture duration in your own script if the workload requires one.

Results differ between runs

Check that browser and Puppeteer versions, cache state, network conditions, target page state, and the inclusion filters are consistent. Keep raw timestamps and protocol fields so you can distinguish capture differences from changes introduced by your calculations.

Or skip the browser setup

If you need a clean page screenshot rather than a machine-readable request waterfall, ScreenshotNeo takes a screenshot or PDF from one GET request. Its capture can accept cookie or consent banners and remove 60+ known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, with the response identifying the page verdict and billing status in headers. ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.

Here is the cURL form; replace the example URL with the page you want to capture. See the ScreenshotNeo API documentation for the request options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan. These are screenshot captures, not a substitute for Puppeteer CDP timing records.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.