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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Playwright’s routing API: register a handler with page.route() for one page, or browser_context.route() for pages in a browser context. In the handler, inspect route.request.resource_type, call route.abort() for requests to block, and explicitly continue requests that should load. The examples below show both synchronous and asynchronous Python, how to choose the route’s scope, and the edge cases that can make a route appear not to work.

Block a resource type on one page

A route matches requests, not rendered elements. Match all URLs with **/*, check the browser-reported resource type, and abort only the category you want to block. Continue everything else; a matching request waits for the handler to resolve it.

Synchronous Python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()

    page.route(
        "**/*",
        lambda route: route.abort()
        if route.request.resource_type == "image"
        else route.continue_(),
    )

    page.goto("https://example.com")
    browser.close()

This aborts image requests from that page and allows other matched requests to proceed. Register the route before navigating so it can handle requests triggered by the navigation.

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

Asynchronous Python

import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()

        async def handle_route(route):
            if route.request.resource_type == "image":
                await route.abort()
            else:
                await route.continue_()

        await page.route("**/*", handle_route)
        await page.goto("https://example.com")
        await browser.close()

asyncio.run(main())

In asynchronous code, the handler must await the route action. The key behavior is the same in either API: abort the selected category and resolve the remaining requests with continue_().

Other resource categories

Change "image" to the category that fits your test. Playwright’s request resource types include stylesheet, media, font, script, xhr, and fetch, among others. For example, to block fonts only, use route.request.resource_type == "font". Blocking scripts or stylesheets can substantially change page behavior and appearance, so do it only when that altered page is what your test is meant to examine.

Choose page scope or browser-context scope

Route location Coverage Popup behavior When to use it
page.route() Requests made by that page Does not intercept a popup page’s first request Use when the policy applies to one page and popup initial navigation does not need coverage.
browser_context.route() Requests made by pages in that browser context Covers popup requests, including the popup’s initial request Use when the policy should apply across pages or must cover popup startup.

Register a context route before creating or navigating pages that should be covered:

context.route(
    "**/*",
    lambda route: route.abort()
    if route.request.resource_type == "image"
    else route.continue_(),
)
page = context.new_page()
page.goto("https://example.com")

If a page route and context route both match, the page route takes precedence. If more than one route on the same page matches a request, the most recently registered route takes precedence. Keep those precedence rules in mind when a broad blocking rule seems to override a narrower one—or vice versa.

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

Match by resource type or URL

Use route.request.resource_type when the rule is about what the browser is loading, such as images or fonts, regardless of the URL used to serve it. Use a URL pattern when the rule is about a particular path or filename pattern; the Playwright API examples include matching image extensions. A URL pattern is not the same as a resource-type test: one targets an address pattern, the other the browser’s classification of the request.

Both approaches use a route handler that must resolve matching requests. With a URL-specific rule, continue requests that match the pattern but should not actually be blocked; with a broad pattern such as **/*, explicitly allow every category outside your blocking condition.

Important routing behavior and caveats

Service workers can bypass routing

Page and context routing does not intercept requests intercepted by a service worker. If routes or expected network events appear to be missing, Playwright documents creating the context with service_workers="block" as a mitigation:

context = browser.new_context(service_workers="block")

Use that setting only when disabling service workers fits the test objective. If the application’s behavior with its service worker active is what you are testing, keep that environment intact and account for the documented routing limitation instead. See Playwright’s service worker guidance.

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.

Redirects are not all routed independently by a page route

For redirects, a page route handler is called only for the first URL in the redirect chain. If a test depends on handling a later destination as a separate routed request, do not assume the page route will run again for it.

Routing disables the HTTP cache

Enabling routing disables the HTTP cache. A routed test can therefore behave differently from an otherwise similar test without routes, especially when you compare timings or repeat page loads. Treat that as a property of the test setup rather than assuming that the resource rule alone explains a timing difference.

Every matched request must be resolved

A request that matches a route stalls until its handler takes an action. The handler can continue it, abort it, or fulfill it. The examples here use an explicit allow path with continue_(); omitting that path can leave requests waiting rather than letting them reach the network. See the official Playwright Python network guide and the BrowserContext, Page, and Request API references.

Troubleshoot a route that does not behave as expected

  • The page still loads images or another targeted category. Confirm the condition uses the exact resource type you intend, and that the route was registered before navigation or the request. Check whether a service worker is intercepting the requests; consider service_workers="block" only if it is appropriate for the test.
  • The popup’s first page request was not blocked. A route registered with page.route() does not intercept that initial popup request. Register the rule with browser_context.route() instead.
  • The page hangs or requests appear stalled. Ensure every matching request takes an action. Keep an explicit continue_() branch for requests that should proceed.
  • A later redirect destination did not trigger the page handler. A page route handles only the first URL in a redirect chain; account for that limit when designing the test.
  • Page-load timings changed after adding a route. Routing disables the HTTP cache. Compare like-for-like setups and avoid treating routed and unrouted runs as identical cache conditions.
  • A newly registered rule appears to override another. Check both scope and registration order: page routes take precedence over context routes, and among matching routes on the same page the most recently registered takes precedence.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and test design

Blocking requests can make a test exercise a deliberately reduced version of a page, but it also changes what the page can render or execute. For example, blocking images changes visual output; blocking scripts may change application behavior; blocking stylesheets or fonts may change layout. Choose a resource category because it supports a specific test goal, not simply because it is available to block.

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

For stable results, register routes at the narrowest scope that covers the pages under test, make the allow path explicit, and account for service workers, redirects, and cache behavior. Do not compare a routed run’s load time directly with an unrouted run without noting that routing disables the HTTP cache. The documentation establishes these behavioral constraints, but does not provide a general speed improvement or performance figure for blocking resources.

Or skip the browser setup

If your goal is to get a clean screenshot rather than test which browser requests an application makes, ScreenshotNeo offers a website screenshot API and MCP server. It accepts a URL and returns a PNG, JPEG, WebP, or PDF. Its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. AI agents can use its MCP server tools take_screenshot, get_page_info, and capture_pdf.

Python example (see the ScreenshotNeo documentation):

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Equivalent one-request examples:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free 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

Does aborting an image request remove an image element from the page?

No. Routing aborts the network request; it does not remove or rewrite the page’s HTML. The page may still contain an image element whose resource failed to load.

Can I use request routing to test what happens when a resource fails?

Yes. Aborting a selected request lets the test exercise the page with that request unavailable. Keep the test’s purpose in view: the result reflects the intentionally altered network behavior, not an unmodified page load.

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.