ScreenshotNeo

BlogHow-to

How to Identify Request Resource Types in Puppeteer

Use Puppeteer’s request event and resourceType() to classify page requests without enabling interception. See runnable examples, type distinctions, and fixes for common issues.

By the ScreenshotNeo team4 October 20267 min read

Listen for the page’s request event and call request.resourceType() on each HTTPRequest. Puppeteer returns the resource category as perceived by the rendering engine. For passive classification, request interception is unnecessary.

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

This guide uses Puppeteer’s documented API shape. Check the Puppeteer and browser versions installed in your project before relying on a definitive list of resource type values.

1. Observe request resource types

Register the listener before navigating so it can observe requests made during the initial page load. The callback receives a request object; call resourceType() to read its classification and url() to identify the requested address.

const puppeteer = require('puppeteer');

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

    page.on('request', request => {
      console.log(`${request.resourceType()}\t${request.url()}`);
    });

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

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Save this as inspect-requests.cjs, install Puppeteer in the project with npm install puppeteer, then run node inspect-requests.cjs. The listener logs requests as they are issued; requests triggered later by scrolling or interaction may appear later as well.

Filter for a specific type

Compare the returned value directly. For example, to report only images:

page.on('request', request => {
  if (request.resourceType() === 'image') {
    console.log('Image request:', request.url());
  }
});

This checks the browser’s classification, not whether the URL ends in an image file extension. A URL can have no extension or a misleading extension and still be classified according to how the rendering engine treats that request.

Collect a summary

For diagnostics, count observed requests by type. This keeps the listener passive and avoids changing the page’s network behavior.

const counts = new Map();

page.on('request', request => {
  const type = request.resourceType();
  counts.set(type, (counts.get(type) || 0) + 1);
});

await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log(Object.fromEntries(counts));

2. What resource types mean

Puppeteer defines ResourceType as the lowercase form of the DevTools Protocol’s Network.ResourceType. The category describes how the rendering engine perceived the resource. It is not a file-extension lookup.

A practical set of values encountered in Puppeteer documentation and historical project discussion includes:

  • document
  • stylesheet
  • image
  • media
  • font
  • script
  • texttrack
  • xhr
  • fetch
  • eventsource
  • websocket
  • manifest
  • other

Treat that as a practical list, not a promise that every Puppeteer and browser version will expose exactly the same values. For the current behavior, inspect the API documentation and the versions in your own lockfile and runtime.

Resource type is not navigation status

request.resourceType() classifies the resource. request.isNavigationRequest() separately indicates whether a request drives navigation of its frame. A document request is commonly associated with navigation, but use the navigation method when that is the question you need to answer.

Resource type is not request success

A request’s type does not tell you whether it succeeded. Puppeteer’s requestfailed event represents a failed request lifecycle. An HTTP response such as 404 or 503 is still an HTTP response and can complete through requestfinished; check the response status when you need to detect HTTP errors.

3. When to enable interception

Use the request event alone to inspect types. Enable interception only if you need to modify, block, or fulfill requests. Once interception is enabled, each request stalls until it is continued, aborted, responded to, or completed from browser cache.

Example: block images while allowing other requests to proceed:

await page.setRequestInterception(true);

page.on('request', request => {
  if (request.resourceType() === 'image') {
    void request.abort().catch(error => {
      console.error('Could not abort request:', error);
    });
  } else {
    void request.continue().catch(error => {
      console.error('Could not continue request:', error);
    });
  }
});

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

Every intercepted request must be resolved exactly once. If several handlers can act on the same request, coordinate them so one handler does not try to continue a request another handler has already handled. Keep asynchronous work in interception handlers short; an unresolved request can hold up page loading.

4. Other runnable ways to inspect Puppeteer traffic

Node.js with an ES module

If the project uses ES modules, the same API works with import syntax:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  page.on('request', request => {
    console.log(request.resourceType(), request.url());
  });
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });
} finally {
  await browser.close();
}

Python and cURL for the resulting screenshot

Puppeteer is a Node.js library, so the request listener itself runs in Node.js. If your goal is to inspect a rendered page visually rather than classify individual browser requests, ScreenshotNeo provides a screenshot API. These examples capture a page; they do not expose Puppeteer resource-type events.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo API documentation for request options and response details.

5. Or skip the browser setup

If you need a page image rather than per-request diagnostics, ScreenshotNeo returns a screenshot from one GET request. Its capture can accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

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

ScreenshotNeo is a website screenshot API and MCP server made by Yorker Media. Read more at ScreenshotNeo, review the docs, or sign up for 1,000 free screenshots a month with no card.

6. Troubleshooting

Symptom Likely cause Fix
No requests are logged The listener was attached after navigation, or the page is not making new requests. Register page.on('request', ...) before goto(). Trigger the interaction or scroll that causes later requests.
The type does not match the URL suffix The method reports the rendering engine’s classification, not a file extension. Use resourceType() for browser classification. Check URL patterns separately only when extension-based matching is explicitly what you want.
Navigation appears stalled after enabling interception An intercepted request was not resolved, or multiple handlers attempted to handle it. Ensure every intercepted request is continued, aborted, or responded to exactly once; review all handlers and error paths.
A 404 or 503 is not reported as requestfailed HTTP error statuses are responses, not necessarily failed request lifecycles. Inspect the response status to identify HTTP errors; reserve requestfailed for failed lifecycle events.
A type in production is missing from an assumed list The published enumeration or browser behavior may differ from the installed version. Check the Puppeteer API and DevTools Protocol references for the versions actually installed and running.
Code errors that resourceType is not a function The callback value may not be a Puppeteer HTTPRequest, or the wrong event/API object is being used. Attach to the Puppeteer page’s request event and call the method on the event argument.

7. Performance and reliability notes

  • Passive observation does not enable interception, so it does not impose interception’s requirement to resolve every request.
  • Keep request callbacks lightweight. Logging every URL can generate substantial output on pages with many requests; filter by type or aggregate counts when that is enough.
  • Attach listeners before navigation to avoid missing early requests. For requests initiated by later interactions, keep the listener attached while those interactions run.
  • Use explicit navigation timeouts and close the browser in a finally block so errors do not leave a browser process running.
  • Request classification is useful for diagnostics and filtering, but it does not establish that the response succeeded or that the content matches the URL suffix.

8. FAQ

Do I need request interception to read a resource type?

No. Listen to the page’s request event and call resourceType(). Interception is for changing how requests are handled.

Does resourceType() return MIME types?

No. It returns a resource category perceived by the rendering engine. A MIME type is a separate piece of response metadata.

Can I use this to tell which request navigated a frame?

Use isNavigationRequest() for that question. Resource category and navigation status are separate properties.

Should I block requests by resource type?

Only if the page can function without them and you deliberately want to change loading behavior. For passive analysis, leave interception off.