October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
browser automation

How to Capture Background Requests and Responses in Puppeteer

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

Capture background traffic by attaching request, response, requestfinished, and requestfailed listeners to the Puppeteer Page before navigation or the action that triggers the call. Use waitForRequest() or waitForResponse() when you need one matching exchange. Request interception is not required for observation; enable it only when you must alter, block, or fulfill traffic.

Log every request and response

A page-level listener sees fetch, XMLHttpRequest, image, script, stylesheet, document, and other browser requests. Install the listeners before page.goto(), a click, a form submission, or any JavaScript action that can issue the request. A listener cannot recover events that happened before it was registered.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless: true});
  const page = await browser.newPage();

  page.on('request', request => {
    console.log('REQUEST', request.method(), request.resourceType(), request.url());
  });

  page.on('response', response => {
    console.log('RESPONSE', response.status(), response.url());
  });

  page.on('requestfinished', request => {
    console.log('FINISHED', request.method(), request.url());
  });

  page.on('requestfailed', request => {
    console.error('FAILED', request.method(), request.url(), request.failure());
  });

  await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
  await page.click('#load-data');
  await browser.close();
})();

request fires when the page issues a request. response provides the HTTP response once headers are available. requestfinished means the response body has downloaded and the exchange is complete. requestfailed indicates a transport-level failure such as a refused connection or timeout.

Filter the stream

Logging everything can become noisy on modern pages. Filter by URL, method, resource type, or a predicate while retaining the complete event order when needed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.on('request', request => {
  const url = request.url();
  if (request.method() === 'POST' && url.includes('/api/')) {
    console.log({
      url,
      method: request.method(),
      type: request.resourceType(),
      headers: request.headers(),
      initiator: request.initiator()
    });
  }
});

page.on('response', async response => {
  if (!response.url().includes('/api/')) return;
  console.log('API response', response.status(), response.headers());
});

The request object exposes URL, method, headers, resource type, initiator, and a link to its response. For request payloads, postData() is deprecated and may be undefined even when a POST body exists; use fetchPostData() when your installed Puppeteer version provides it.

Wait for one background request or response

Persistent listeners are best for a stream. For a single API call, create the wait promise before triggering the action. This ordering prevents a fast response from winning a race against your code.

Wait for a request

const requestPromise = page.waitForRequest(request =>
  request.url().includes('/api/search') && request.method() === 'GET'
);

await page.click('#search');
const request = await requestPromise;
console.log('Sent:', request.url(), request.headers());

Wait for a response

const responsePromise = page.waitForResponse(response =>
  response.url().includes('/api/search') && response.status() === 200
);

await page.click('#search');
const response = await responsePromise;
console.log('Received:', response.status(), response.url());

// Read a body only when the endpoint returns a format you understand.
const contentType = response.headers()['content-type'] || '';
if (contentType.includes('application/json')) {
  console.log(await response.json());
}

These helpers use Puppeteer’s default 30-second timeout. Change the default with page.setDefaultTimeout(milliseconds), or supply a cancellation signal where supported by the version you use. A predicate should be specific enough to avoid matching an unrelated request to the same host.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Choose the right synchronization method

Goal Use Important behavior
Record ongoing traffic page.on('request') and page.on('response') Listeners remain active until removed or the page closes.
Wait for one outgoing call page.waitForRequest() Register before the action; match URL, method, or a predicate.
Wait for one server reply page.waitForResponse() Match status and URL; inspect the body according to its content type.
Wait for completed download requestfinished HTTP errors such as 404 and 503 still finish normally.
Detect transport failure requestfailed Does not replace status-code checks for HTTP errors.
Wait for quiet traffic page.waitForNetworkIdle() A synchronization heuristic that waits at least the configured idle time, not proof that every delayed call has occurred.

Understand status codes, redirects, and failures

HTTP errors are still responses

A 404, 401, 500, or 503 is an HTTP exchange. The request generally emits response and then requestfinished; classify it by response.status(). Do not expect requestfailed merely because the server returned an error status.

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

Redirects create multiple requests

A redirect finishes the original request and causes another request to the destination. If you need the final URL, inspect the response chain or match the destination explicitly rather than assuming one request represents the whole exchange.

Capture useful records

const records = new Map();

page.on('request', request => {
  records.set(request, {
    url: request.url(),
    method: request.method(),
    type: request.resourceType(),
    startedAt: Date.now()
  });
});

page.on('response', response => {
  const record = records.get(response.request());
  if (record) Object.assign(record, {
    status: response.status(),
    responseHeaders: response.headers(),
    responseAt: Date.now()
  });
});

page.on('requestfailed', request => {
  const record = records.get(request);
  if (record) record.failure = request.failure();
});

Keep body collection selective. Bodies can be large, binary, compressed, or consumed by page behavior, and not every response is text or JSON. Save only endpoints and content types your diagnostic requires.

Request interception: only when you must change traffic

Observation listeners do not stall the browser. Calling page.setRequestInterception(true) changes that: each request pauses until a handler continues, responds, or aborts it (subject to browser-cache behavior). Every intercepted request must be resolved.

await page.setRequestInterception(true);

page.on('request', request => {
  if (request.url().endsWith('.png')) {
    request.abort();
  } else {
    request.continue();
  }
});

Use interception for blocking ads, injecting a response, rewriting headers, or simulating failures—not for ordinary logging. If another listener or package may already have handled a request, guard every resolution. After an asynchronous operation, check again immediately before acting because the state can change while you await.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.on('request', async request => {
  if (request.isInterceptResolutionHandled()) return;
  const shouldBlock = request.url().includes('/tracking');
  // If real asynchronous work is added above, check the flag again here.
  if (request.isInterceptResolutionHandled()) return;
  if (shouldBlock) request.abort();
  else request.continue();
});

Service workers and network-idle diagnostics

Service workers can handle requests without exposing the same path as a normal page fetch. page.setBypassServiceWorker(true) toggles bypassing the service worker for each request. Treat this as a diagnostic comparison, not a prerequisite for event logging. Puppeteer’s page.workers() lists dedicated WebWorkers and does not include ServiceWorkers.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
await page.setBypassServiceWorker(true);
await page.goto('https://example.com');

Use waitForNetworkIdle() when an application has a known quiet period, but choose the idle window deliberately. Analytics, polling, WebSockets, lazy loading, and delayed timers can make “idle” differ from “all application work is complete.” A response predicate tied to the actual API is more deterministic.

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

Common problems and fixes

The request never appears

  • Register listeners or waiters before navigation or the triggering action.
  • Confirm the action actually runs; wait for the button to be visible and enabled.
  • Check whether a service worker, cache, or browser extension changes the path. Compare with service-worker bypass only as a diagnostic.
  • Broaden the filter temporarily and print every URL, then narrow it after identifying the real endpoint.

waitForResponse times out

  • Match the exact URL, including query parameters and redirects.
  • Do not require status 200 if the endpoint legitimately returns another success status.
  • Ensure the promise is created before the click or navigation.
  • Raise the timeout only after fixing a bad predicate or premature action.

You see 503 but no failure event

This is expected for an HTTP response. Record the status from the response event and treat requestfailed as a separate transport signal.

The page hangs after enabling interception

At least one request was left unresolved, or two handlers competed. Resolve every request, avoid unnecessary asynchronous work in the interception handler, and use isInterceptResolutionHandled() before continue(), abort(), or respond().

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

The body is unreadable

Check the response content type and status first. Handle JSON, text, images, downloads, and empty responses separately; do not call response.json() on an arbitrary response.

Performance, reliability, and security

  • Filter early and avoid logging complete headers or bodies in production; authorization and cookie headers can contain secrets.
  • Use a bounded in-memory queue or write records incrementally when pages generate thousands of events.
  • Capture timestamps, status, method, resource type, and failure reason so logs remain useful without retaining sensitive payloads.
  • Close listeners or pages between tests to prevent duplicate logs and memory growth.
  • Use deterministic predicates instead of a long idle delay whenever the application exposes a stable API response.
  • Pin or record the Puppeteer version. The current API references identified for this topic are for version 25.12.0, while behavior can vary across installed versions.

Or skip the browser setup

If your goal is a clean image or PDF of a page rather than debugging its network traffic, ScreenshotNeo provides a single HTTP call. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing result in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for all options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can Puppeteer capture fetch and XMLHttpRequest calls without interception?

Yes. Page-level request and response events observe those calls; interception is needed only to modify, block, or fulfill them.

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.

Which event tells me that the response body finished downloading?

Use the requestfinished event. Check the associated response status separately because HTTP error statuses can still finish successfully at the transport level.

How can I avoid missing a response caused by a click?

Create the waitForResponse promise first, then perform the click and await the promise.

Does page.workers() include service workers?

No. Puppeteer documents page.workers() as returning dedicated WebWorkers, not ServiceWorkers.

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.

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

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
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

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.