October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan 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 Intercept Non-HTTP Requests in Puppeteer

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.

Use Chrome DevTools Protocol (CDP) when you need dependable visibility into non-HTTP traffic. Puppeteer’s page.on('request') and setRequestInterception APIs are convenient for ordinary allow, block, and mock decisions, but their documented object is an HTTPRequest. For file:, data:, other schemes, and WebSocket frames, attach a CDP Network session. When a matching request must be paused and continued, failed, or replaced, use CDP Fetch.

Choose the interception layer first

The right API depends on whether you want a simple decision, broad observation, or a paused request that you can replace.

Goal Recommended layer What it provides
Block images, fonts, media, or selected URLs page.setRequestInterception and page.on('request') Short handlers that call continue(), abort(), or respond().
Observe file:, data:, other schemes, and network lifecycle events CDP Network Protocol events for a wider set of requests and responses.
Pause, fail, or synthesize a matching response CDP Fetch Explicit paused-request state with continueRequest, failRequest, and fulfillRequest.
Inspect WebSocket messages CDP Network WebSocket events Handshake and frame events, including sent and received payloads.
Restrict broad browser network access Puppeteer ConnectOptions.allowlist/blocklist An experimental network-service guardrail, not a complete sandbox.

Browser and Chromium versions can change which schemes reach a particular layer. Test the exact browser build you deploy, especially when you need to replace a non-HTTP resource rather than merely observe it.

How Puppeteer request interception behaves

In Puppeteer 25.12.0, enabling interception changes the default control flow: “Once request interception is enabled, every request will stall unless it’s continued, responded or aborted.” Enable it before goto, reload, a click, worker creation, or any action that causes traffic.

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

Basic high-level filtering

import puppeteer from 'puppeteer';

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

await page.setRequestInterception(true);
page.on('request', request => {
  // This check must happen immediately before resolving the request.
  if (request.isInterceptResolutionHandled()) return;

  const url = request.url();
  if (url.startsWith('file:') || url.startsWith('data:')) {
    request.abort();
    return;
  }

  request.continue();
});

await page.goto('https://example.com', {waitUntil: 'networkidle2'});
await browser.close();

This is suitable for ordinary resource filtering, but do not assume every browser-internal or non-network fetch will produce a high-level HTTPRequest event. Puppeteer’s API describes HTTPRequest as an HTTP request sent by a page; CDP is the safer observation layer for broader scheme coverage.

Preventing handler races

Multiple listeners can compete to resolve one request. Check isInterceptResolutionHandled() immediately before abort, continue, or respond, and check again after every await. The check and the resolution call should remain in the same synchronous block. Puppeteer’s cooperative mode can assign numeric priorities; the highest priority wins, and ties are ordered abort, respond, then continue.

page.on('request', async request => {
  if (request.isInterceptResolutionHandled()) return;

  const shouldMock = request.url().endsWith('/config.json');
  if (!shouldMock) {
    request.continue();
    return;
  }

  // If asynchronous work is added, re-check before resolving.
  const body = JSON.stringify({feature: 'test'});
  if (request.isInterceptResolutionHandled()) return;
  request.respond({
    status: 200,
    contentType: 'application/json',
    body
  });
});

Observe file, data, and other non-HTTP requests with CDP Network

Chrome’s CDP Network domain exposes information about HTTP, file, data, and other request types. Create a CDP session, enable the domain before navigation, and inspect Network.requestWillBeSent.

import puppeteer from 'puppeteer';

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

await client.send('Network.enable');
client.on('Network.requestWillBeSent', event => {
  const {url} = event.request;
  if (!/^https?:/i.test(url)) {
    console.log('non-HTTP request', {
      type: event.type,
      url,
      requestId: event.requestId
    });
  }
});

await page.goto('file:///tmp/example.html', {waitUntil: 'load'});
await browser.close();

This listener observes traffic; it does not itself pause or replace it. Keep the session attached for the entire operation that may create the request, including frames and workers relevant to your test.

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

What observation can and cannot prove

  • A Network.requestWillBeSent event proves that Chrome exposed the request to the CDP Network domain.
  • No high-level request event does not prove that the page made no non-HTTP request; it may simply be outside Puppeteer’s HTTPRequest abstraction.
  • Seeing a URL does not give you an HTTP response to fulfill. Schemes without an HTTP response model should generally be observed rather than replaced.

Pause and mock requests with CDP Fetch

Use CDP Fetch when a matching request must stop until your code chooses an outcome. Fetch.enable accepts URL patterns and resource-type filters. Every matching Fetch.requestPaused event remains paused until you call Fetch.continueRequest, Fetch.failRequest, or Fetch.fulfillRequest. You can intercept at the request stage or response stage.

Minimal response fulfillment

import puppeteer from 'puppeteer';

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

await client.send('Fetch.enable', {
  patterns: [{
    urlPattern: 'https://example.test/*',
    requestStage: 'Request'
  }]
});

client.on('Fetch.requestPaused', async ({requestId, request}) => {
  try {
    if (request.url.startsWith('https://example.test/')) {
      const body = Buffer.from(JSON.stringify({ok: true})).toString('base64');
      await client.send('Fetch.fulfillRequest', {
        requestId,
        responseCode: 200,
        responseHeaders: [
          {name: 'content-type', value: 'application/json'}
        ],
        body
      });
    } else {
      await client.send('Fetch.continueRequest', {requestId});
    }
  } catch (error) {
    console.error('Could not resolve paused request', request.url, error);
    // A request that remains paused can hang the page. If it is still valid,
    // attempt to let it continue.
    try {
      await client.send('Fetch.continueRequest', {requestId});
    } catch {}
  }
});

await page.goto('https://example.com', {waitUntil: 'networkidle2'});
await browser.close();

Fetch.fulfillRequest models an HTTP-shaped response. It is appropriate for HTTP endpoints such as the example above. For file:, data:, or another scheme that has no HTTP response semantics, prefer CDP Network observation and verify the exact Chromium behavior before promising replacement.

Failing or continuing instead

client.on('Fetch.requestPaused', async ({requestId, request}) => {
  if (request.url.includes('/telemetry')) {
    await client.send('Fetch.failRequest', {
      requestId,
      errorReason: 'BlockedByClient'
    });
    return;
  }
  await client.send('Fetch.continueRequest', {requestId});
});

Always include a fallback continuation for requests you do not intend to modify. Also disable Fetch when the job is over if the CDP session will be reused:

await client.send('Fetch.disable');

Intercepting WebSocket traffic

A WebSocket has two distinct interception problems: the opening handshake and the frames sent after the connection is established. Chrome’s webRequest support covers the handshake, not individual messages. CDP Network exposes both handshake events and frame-level events.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const client = await page.createCDPSession();
await client.send('Network.enable');

client.on('Network.webSocketWillSendHandshakeRequest', event => {
  console.log('WS handshake', event.request.url);
});

client.on('Network.webSocketFrameSent', event => {
  console.log('WS sent frame', event.response.payloadData);
});

client.on('Network.webSocketFrameReceived', event => {
  console.log('WS received frame', event.response.payloadData);
});

You may make a handshake decision through the interception layer Chrome exposes for that request. Do not claim that page.on('request') can rewrite arbitrary post-connect WebSocket messages; inspect those with the frame events instead.

A reliable setup sequence

  1. Create the page and, when needed, a CDP session.
  2. Register Puppeteer request listeners or CDP event listeners.
  3. Enable Network or Fetch before navigation or the action that generates traffic.
  4. For every intercepted request, resolve exactly once: continue, fail, fulfill, abort, or respond.
  5. Navigate or perform the user action.
  6. Collect logs and errors, then disable Fetch and close the browser.

Registering too late is a common source of missing events. Registering multiple competing listeners is a common source of “already handled” errors and hangs.

Troubleshooting non-HTTP interception

The page hangs after interception is enabled

Cause: at least one request was left unresolved. Add request.continue() to the high-level fallback and Fetch.continueRequest to the CDP fallback. Log every Fetch.requestPaused event and ensure exceptions in the handler cannot skip resolution.

page.on('request') never sees a file: or data: URL

Cause: the request is outside Puppeteer’s HTTPRequest abstraction or the browser did not expose it at that layer. Enable CDP Network before the triggering action and inspect Network.requestWillBeSent. Browser-version differences are expected.

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.

“Request is already handled” or duplicate-resolution errors appear

Cause: more than one handler raced, often because one handler awaited a promise. Check isInterceptResolutionHandled() immediately before each resolution and again after every await; consolidate handlers when possible.

Fetch interception catches more traffic than intended

Cause: a broad URL pattern or missing resource-type filter. Narrow urlPattern, add the appropriate resource type, and log the URL before choosing an action. Keep an explicit continuation for non-matches.

Fulfillment fails for a non-HTTP scheme

Cause: Fetch.fulfillRequest represents an HTTP response and the target scheme may not have one. Use Network events for observation, or validate the behavior against the Chromium version you actually run before designing a replacement.

WebSocket frames are missing

Cause: only the handshake was observed, or Network was enabled after the socket opened. Enable Network first and subscribe to Network.webSocketFrameSent and Network.webSocketFrameReceived.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and security considerations

  • Interception adds handler work to every matched request; keep synchronous decisions cheap and avoid unnecessary awaits.
  • Fetch pauses matching requests, so slow mocks directly increase page latency and can trigger application timeouts.
  • Capture request IDs, URLs, and resolution errors in test logs so a failed navigation can be diagnosed without guessing which request stalled.
  • Use narrow patterns rather than pausing all traffic. Broad interception increases overhead and makes accidental hangs more likely.
  • The experimental allowlist/blocklist options are guardrails. Puppeteer documents limits because some browser network access and web features may bypass the network service; do not treat them as a complete sandbox.
  • Do not log authorization headers, cookies, or sensitive WebSocket payloads in shared CI output.

Or skip the browser setup

If your actual goal is a clean screenshot or PDF rather than traffic analysis, ScreenshotNeo removes the browser orchestration. It accepts a URL and returns PNG, JPEG, WebP, or PDF; its API can also wait, block resources, set headers and cookies, run custom JavaScript, and capture a selected element.

One call is enough:

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 complete parameter list and response behavior in the ScreenshotNeo documentation. 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}`);

Before capture, ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots.

Create a free ScreenshotNeo account to try 1,000 screenshots a month with no card.

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

Frequently Asked Questions

Can Puppeteer intercept a WebSocket’s messages with the request event?

No. The request event concerns the opening request abstraction; inspect post-connect traffic with CDP Network WebSocket frame events.

Should I use CDP Network or CDP Fetch for a file URL?

Use CDP Network to observe it. Fetch fulfillment is HTTP-shaped, so replacement semantics for non-HTTP schemes must be verified against the Chromium version you run.

Why must interception be enabled before navigation?

Requests can start as soon as navigation or another action begins. Enabling the listener afterward cannot recover events that already occurred.

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
Windows Errors? Fix Them Before They SpreadFree repair scan
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.