Cutting Page Load Times with Puppeteer Request Interception
Learn how to use Puppeteer's request interception to block images, fonts, and trackers, significantly reducing page load times and resource consumption during automation.
25 Jun 2026, 08:11 UTC

The Cost of Unnecessary Assets
When automating a browser with Puppeteer, the default behavior is to load every asset the page requests: high-resolution images, heavy CSS frameworks, and third-party tracking scripts. If your goal is to scrape data, generate a PDF, or run an automated test, downloading a 2MB hero image or a marketing pixel is a waste of CPU, memory, and bandwidth.
The solution is Request Interception. By treating the browser's network layer as a middleware, you can programmatically decide which requests are essential and which should be dropped before they ever leave the browser.
How Request Interception Works
Puppeteer allows you to enable a hook that pauses every network request. Once a request is intercepted, the browser waits for a signal from your Node.js script to either continue() the request or abort() it. This happens at the Chrome DevTools Protocol (CDP) level, meaning you can block assets based on their URL, resource type, or headers.
The Resource Type Filter
The most effective way to optimize is by filtering by request.resourceType(). Common types include:
image: Visual assets that rarely impact data extraction.stylesheet: CSS files (useful to block if you only need the DOM).font: Web fonts that slow down the initial render.script: JavaScript files (caution: blocking these may break SPA functionality).
Implementation Example: Blocking Media and Trackers
The following example demonstrates how to block images and common tracking domains to speed up a page load. This script assumes you are using Puppeteer v20+ and have Node.js installed.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Step 1: Enable interception
await page.setRequestInterception(true);
page.on('request', (request) => {
const resourceType = request.resourceType();
const url = request.url();
// Block images and fonts to save bandwidth
if (resourceType === 'image' || resourceType === 'font') {
request.abort();
}
// Block known tracking domains
else if (url.includes('google-analytics.com') || url.includes('doubleclick.net')) {
request.abort();
}
// Allow everything else
else {
request.continue();
}
});
try {
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log('Page loaded with optimized assets.');
} catch (err) {
console.error('Navigation failed:', err);
}
await browser.close();
})();
Execution Details
- Where to run: Run this in your Node.js environment using
node script.js. - Permissions: No special OS permissions are required beyond the ability to execute the Chromium binary.
- Expected Result: The
page.gotocall should complete significantly faster, and the network traffic will show(blocked:devtools)for images. - Risk: If you forget to call
request.continue()for a required script, the page may never finish loading, causing your script to timeout.
The Performance Trade-off
While blocking assets reduces bandwidth, request interception introduces a new bottleneck: the Node.js event loop. Because every single request must travel from the browser to your Node.js process to be evaluated, a page with hundreds of small requests can actually experience increased latency due to the communication overhead between the browser and the script.
Additionally, interception can interfere with Service Workers or complex WebSocket connections, as these often bypass standard request hooks or require specific handling to avoid breaking the application state.
Verifying the Results
To verify that your interception logic is working, run your script in non-headless mode (headless: false) and open the Chrome DevTools Network tab. You should see the targeted resources listed as "blocked" or failing to load. For a quantitative measure, wrap your page.goto call in a timer:
const start = Date.now();
await page.goto(url);
console.log(`Load time: ${Date.now() - start}ms`);
Compare the results with setRequestInterception(false) to determine the actual time saved for your specific target site.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.