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.

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.

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

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.

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

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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():

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':

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

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.

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

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.Support on Ko-Fi

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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 API documentation for parameters and response details. The same call from Python is:

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.

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

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.

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.