What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use network interception before navigation, identify requests whose browser resource type is image, and call abort() for images you do not need. Every intercepted request must be resolved with continue(), abort(), or a synthetic response; leaving even one unresolved can make a page appear to hang. Puppeteer uses a request event, while Playwright uses page.route() or a browser-context route.
What image-request interception does
Headless Chrome still loads pages through the normal browser network stack. Interception inserts your code between the browser and each outgoing request, so you can inspect or change the request before it is sent. Chrome for Developers describes this as DevTools Protocol network interception.
Enable interception before calling goto(). Then classify each request. The most general test is the browser-provided resource type: image. This catches image requests even when the URL has no .png, .jpg, or similar suffix. URL and extension rules are useful when you need a narrow exception, such as blocking only a particular image host.
Choose an outcome for every request
- Abort: stop downloading the image. Use this to reduce transferred data or prevent image rendering.
- Continue: send the original request unchanged.
- Respond or fulfill: return your own status, headers, and bytes when a test needs deterministic image content instead of the real asset.
Blocking images can affect layout, lazy-loading behavior, and scripts that expect an image to finish. Keep stylesheets, fonts, scripts, documents, XHR, and fetch requests unless your test explicitly requires a stricter resource policy.
#1 Best Overall
Intercept and abort images with Puppeteer
Basic Puppeteer implementation
Puppeteer enables interception with page.setRequestInterception(true). Once enabled, every request stalls until a handler resolves it, so the non-image branch must call request.continue().
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
if (request.isInterceptResolutionHandled()) return;
if (request.resourceType() === 'image') {
request.abort();
} else {
request.continue();
}
});
try {
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
// Run assertions or extract the image-free page here.
} finally {
await browser.close();
}
The isInterceptResolutionHandled() guard matters when another listener or a package also handles requests. Check it immediately before resolving the request and do not put an await between the check and abort(), continue(), or respond(); another handler could resolve the request during that pause.
Block only selected image URLs
Resource type is the right default for all images. For an exception list, inspect the URL as well:
page.on('request', request => {
if (request.isInterceptResolutionHandled()) return;
const isImage = request.resourceType() === 'image';
const isAllowedLogo = request.url().includes('/brand/logo');
if (isImage && !isAllowedLogo) {
request.abort();
} else {
request.continue();
}
});
This combines a browser classification with a URL predicate. URL matching alone is less reliable for sites that serve extensionless assets or generate image URLs dynamically.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Use an allowlist when the page must be lightweight
Chrome for Developers demonstrates the inverse policy: continue only document, script, xhr, and fetch, and abort other resource classes such as images, stylesheets, and media. That can reduce the browser workload, but it may leave an unusable page if CSS or fonts are required.
const allowed = new Set(['document', 'script', 'xhr', 'fetch']);
page.on('request', request => {
if (request.isInterceptResolutionHandled()) return;
if (allowed.has(request.resourceType())) {
request.continue();
} else {
request.abort();
}
});
Adapt the set to the page under test. For a visual screenshot, keep stylesheets and usually fonts. For an API-oriented scrape, you may need only the document and the requests that populate its data.
Return a replacement instead of aborting
When deterministic bytes are required, use Puppeteer’s request.respond() for the image branch. Supply a successful status, an image content type, and the test bytes; continue all other requests. This preserves the page’s image element while removing dependence on a remote asset. The same interception-resolution guard still applies.
Intercept images with Playwright
Glob-based blocking
Playwright’s direct route API is concise when your assets follow known extensions:
Free tools Windows power users keep installed
One-click scans. No signup required.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
await page.goto('https://example.com');
await browser.close();
Glob rules are easy to read but do not match an image URL that has no listed extension. They also need updating when a site adds formats such as WebP or serves images through a query-only URL.
Resource-type matching
For general image blocking, route every request and inspect route.request().resourceType():
Rank #3
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.route('**/*', route => {
if (route.request().resourceType() === 'image') {
return route.abort();
}
return route.continue();
});
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await browser.close();
Playwright standardizes resource types including document, stylesheet, media, font, script, xhr, fetch, eventsource, websocket, manifest, image, and other.
Service Workers and popup pages
page.route() does not intercept requests handled by a Service Worker. When complete interception is required, create the context with serviceWorkers: 'block':
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →const context = await browser.newContext({ serviceWorkers: 'block' });
Use a browser-context route when popups are possible. The first request of a popup is not intercepted by a route installed only on the original page. A context route covers pages created in that context, including popup pages.
Fulfill a synthetic image
Instead of aborting, Playwright routes can fulfill the request with deterministic status, headers, and body data. This is useful for visual tests that need a stable placeholder. Continue every non-image route and make sure the replacement has the content type expected by the page.
Which matching strategy should you use?
| Strategy | Best for | Limitation |
|---|---|---|
resourceType() === 'image' |
Blocking or replacing all browser-classified images | Requires interception of every request |
| Extension or glob pattern | Small, known asset sets such as *.png |
Misses extensionless or differently formatted URLs |
| URL predicate | Allowing a logo, blocking one host, or targeting a route | Depends on site-specific URL conventions |
| Allowlist of resource types | Strict network budgets or highly controlled tests | Can accidentally remove CSS, fonts, media, or required requests |
Why interception hangs and how to fix it
| Symptom | Likely cause | Fix |
|---|---|---|
goto() never finishes |
An intercepted request was not resolved | Call continue(), abort(), or a response method on every branch, including non-images. |
| Random “already handled” errors | Multiple listeners resolved the same request | Check Puppeteer’s isInterceptResolutionHandled() synchronously before resolving; coordinate handlers when several packages are installed. |
| Images still load in Playwright | A Service Worker handled them outside page routing | Create the browser context with serviceWorkers: 'block'. |
| Popup images are not blocked | The route exists only on the opener page | Install the route on the browser context so popup requests are covered. |
| Some images remain | Matching by extension missed extensionless URLs, or the request was not classified as image |
Log request URLs and resource types, then use a targeted URL rule or adjust the policy for that resource. |
| Page structure changes unexpectedly | Scripts or layout depend on image dimensions or load events | Continue selected images, fulfill a fixed placeholder, or preserve the page’s CSS and font requests. |
Performance, reliability, and measurement
Aborting image downloads can reduce transferred data and browser work, and Chrome for Developers notes that excluding non-DOM resources can potentially speed prerendering. No universal percentage applies: the result depends on image count, image size, caching, JavaScript behavior, and the page’s other requests.
Rank #4
Measure your own workload. Run the same URL with interception enabled and disabled, record navigation timing and transferred bytes, and repeat across representative pages. Do not infer a speed gain from a single page or from the number of blocked requests alone.
Install handlers before navigation, keep the interception callback synchronous, and close the browser in a finally block. If you use networkidle0 or networkidle, remember that those conditions concern the remaining network activity; long-lived analytics, WebSockets, or application polling can still prevent an idle condition even after images are aborted.
Puppeteer versus Playwright for this task
| Area | Puppeteer | Playwright |
|---|---|---|
| Interception API | setRequestInterception(true) plus a request event |
page.route() or a context route |
| Typical image test | request.resourceType() === 'image' |
route.request().resourceType() === 'image' |
| Actions | abort(), continue(), or respond() |
abort(), continue(), or route fulfillment |
| Multiple handlers | Guard with isInterceptResolutionHandled(); coordinate priorities when handlers must cooperate |
Use one clear routing policy and context scope where popup coverage matters |
| Special coverage issue | Every intercepted request must be resolved | Service Workers bypass page routes; popup first requests need context routing |
Choose based on the automation library already used by your test suite. The blocking rule itself is the same: identify the image, choose abort or replacement, and resolve everything else.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your goal is a clean screenshot rather than a custom browser test, ScreenshotNeo provides a website screenshot API and MCP server. It accepts the consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
One GET request returns PNG, JPEG, WebP, or PDF output:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchcurl -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 API documentation for parameters and response details. The same call from Python is:
Best Value
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo also has an MCP server with 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 with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account to get an API key.
Frequently Asked Questions
Can interception modify a request instead of blocking it?
Yes. The interception APIs support continuing a request or supplying a synthetic response, so tests can preserve an image element while replacing remote bytes with deterministic content.
What should I inspect when only a few images evade the rule?
Log each request URL together with its browser resource type. Extension rules can miss extensionless assets, and routing scope can exclude Service Worker or popup requests.
Does aborting images guarantee a faster run?
No. It can reduce work, but the effect depends on the target page and its remaining network activity; measure representative URLs with and without interception.
Quick Recap
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.

