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

Use Chrome DevTools Protocol (CDP) Network events to see whether JavaScript and CSS requests received HTTP responses, finished loading, or failed in the browser. In Selenium Python, enable Network instrumentation before navigating, then collect and correlate events by requestId. The example below uses Chrome’s performance log as its event-capture adapter; the CDP events and their meanings are defined by the CDP Network domain.

What Selenium can tell you about JavaScript and CSS requests

A page-load success does not prove that every script or stylesheet loaded. A browser can render a page while an optional script fails, or an asset can receive an HTTP error even though navigation itself succeeds. Network instrumentation lets your test inspect individual requests.

For each request, the useful lifecycle events are Network.requestWillBeSent, Network.responseReceived, Network.loadingFinished, and Network.loadingFailed. Network.requestServedFromCache adds cache context. Match these events using their CDP requestId, rather than treating each event as an unrelated record. The Network protocol reference defines the available fields.

  • responseReceived provides the response status, URL, MIME type, and response metadata.
  • loadingFinished indicates the transfer completed; it may include encoded data length.
  • loadingFailed indicates a browser-level failure and can provide an error text, cancellation flag, or blocked reason.
  • requestServedFromCache indicates cache involvement and should be retained in the report.

These are distinct outcomes: an HTTP 404 is still a received HTTP response, whereas a network error may produce no HTTP status at all. A completed request is not necessarily a successful application-level resource; use the status and completion data together.

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

Enable Network events before navigation

With Selenium 4 and Chrome, driver.execute_cdp_cmd(command, arguments) sends CDP commands. Selenium documents this method in its Python WebDriver API. A practical collection path is to turn on Chrome performance logging, enable the CDP Network domain, navigate, and parse the log entries.

  1. Create Chrome options and enable the performance log.
  2. Start the driver and send Network.enable before calling get().
  3. Navigate to the page whose assets you want to inspect.
  4. Read the performance log, decode each message, and keep the relevant Network events.
  5. Correlate records by request ID and apply an explicit policy for which failures should fail the test.

The exact event-capture interface can differ with Selenium and browser versions. Keep collection separate from interpretation so you can replace the adapter without rewriting your test policy.

Runnable Python example using Chrome performance logs

Install Selenium in the Python environment used to run the test. Selenium Manager can manage a compatible Chrome driver in supported setups; if your environment manages browser and driver binaries separately, ensure they are compatible. This example uses Chrome and prints request lifecycle events for likely JavaScript and CSS assets.

import json
from urllib.parse import urlsplit

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

TARGET_URL = "https://example.com"

options = Options()
options.set_capability("goog:loggingPrefs", {"performance": "ALL"})
driver = webdriver.Chrome(options=options)

try:
    # Enable before navigation so initial document assets are observable.
    driver.execute_cdp_cmd("Network.enable", {})
    driver.get(TARGET_URL)

    relevant_methods = {
        "Network.requestWillBeSent",
        "Network.responseReceived",
        "Network.loadingFinished",
        "Network.loadingFailed",
        "Network.requestServedFromCache",
    }

    for entry in driver.get_log("performance"):
        message = json.loads(entry["message"])["message"]
        method = message.get("method")
        if method not in relevant_methods:
            continue

        params = message.get("params", {})
        response = params.get("response", {})
        request = params.get("request", {})
        url = response.get("url") or request.get("url")
        resource_type = params.get("type")

        # On responseReceived, params.type is typically Script or Stylesheet.
        # URL suffixes are only a fallback: query strings are excluded.
        path = urlsplit(url).path.lower() if url else ""
        looks_like_asset = (
            resource_type in {"Script", "Stylesheet"}
            or path.endswith(".js")
            or path.endswith(".css")
            or response.get("mimeType", "").lower() in {
                "text/javascript", "application/javascript", "text/css"
            }
        )
        if not looks_like_asset:
            continue

        print({
            "event": method,
            "request_id": params.get("requestId"),
            "resource_type": resource_type,
            "url": url,
            "status": response.get("status"),
            "mime_type": response.get("mimeType"),
            "error": params.get("errorText"),
            "canceled": params.get("canceled"),
            "blocked_reason": params.get("blockedReason"),
            "encoded_data_length": params.get("encodedDataLength"),
        })
finally:
    driver.quit()

This is a useful inspection baseline, not a complete request ledger: it prints event snapshots and does not combine them into one final row per request. The same URL can appear in multiple events. For reliable assertions or reporting, store a mutable record keyed by requestId, updating it as each event arrives.

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

Prefer protocol resource types to filename matching

Where available, CDP’s resource types Script and Stylesheet are a better classification than testing whether a URL ends in .js or .css. Assets may be served from extensionless routes, include query strings, or be generated dynamically. MIME type is also useful, particularly once a response arrives, but it is a response property and may not help identify a request that fails before receiving one.

The example uses urlsplit so query strings do not defeat a suffix fallback. Treat that fallback as a heuristic, not proof that the resource is a script or stylesheet.

Build a per-request record for assertions

For a test report, retain the request ID, URL, resource type, status, MIME type, cache flag, terminal event, failure text, and elapsed time. Create the record on requestWillBeSent, update it on responseReceived, and mark its result on loadingFinished or loadingFailed. Keep cache state separately when a cache event is observed. A request ID is the join key across lifecycle events; URL alone is unsafe because a page may request the same asset more than once.

To calculate elapsed time, retain event timestamps where available and subtract the request-start timestamp from the terminal event timestamp. Do not assume every lifecycle field is present in every event. A failed load may have no response status, and an event sequence can include cancellation or cache behavior that differs from a fresh transfer.

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

Make the failure policy match the test

Selenium does not provide a built-in rule that says every JavaScript or CSS request error should fail a test. Decide which resources are required for the behavior under test, then apply that policy to the collected records.

  • Fail on an HTTP error for a required first-party asset when the test depends on it.
  • Handle a browser-level failure separately from an HTTP status, because it may have no response code.
  • Keep an explicit allowlist for optional analytics, advertising, third-party widgets, and expected cancellations.
  • Do not discard cache information: a cached resource has different transfer context from a fresh network response.
  • Consider whether the assertion covers only initial navigation or also later interactions and route changes.

This separation prevents a test from becoming flaky because an unrelated optional service failed, while still catching failures in assets the tested page actually needs.

Choose an event-capture path and plan for change

The simplest approach above polls Chrome’s performance log after navigation. It is convenient for a bounded page-load check, but logs are an adapter that your code must parse. If you need events continuously during actions, route changes, or more controlled session handling, evaluate Selenium’s CDP session APIs and its WebDriver BiDi support.

Selenium’s documentation says its direct CDP methods “will eventually be removed when WebDriver BiDi implemented.” See Selenium’s CDP Network Features documentation and the Python CDP module reference. Keep the browser-event subscription or log parsing in a small adapter, with the record format and assertion policy independent of that adapter. That makes a later move to BiDi less invasive.

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

Cover requests beyond the initial page load

Enabling Network before the first navigation captures early page requests, but assets can also be requested after the page appears: for example, following a click, lazy loading, a client-side route change, or a user interaction. A check that reads logs once immediately after get() only evaluates the entries available at that point.

For interaction-driven checks, perform the action before collecting the next batch of events and ensure the page has had time to trigger the request. Use the application’s observable condition, such as a displayed element or route state, rather than an arbitrary sleep when possible. If you need to observe a long-running sequence, use an event subscription approach suitable for your Selenium/browser version instead of assuming a one-time log read is a live listener.

Troubleshoot missing or confusing results

No performance log is available

Confirm that the Chrome performance logging capability was set before the driver was created and that the session is using Chrome. Logging capabilities and supported behavior can vary by browser and Selenium version. If the logging adapter is unavailable in your environment, use a supported Selenium CDP or BiDi session path and keep the same event-recording policy.

Initial scripts or stylesheets are missing

Make sure Network.enable runs before driver.get(). Enabling Network after navigation cannot recover events that already occurred. Also check whether the code filters by extension only; an extensionless script URL can be omitted by that heuristic.

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

You see a URL but no status

A request-created event precedes its response, so it has no HTTP status yet. Match the later event by requestId. If the request fails before a response, inspect loadingFailed and its error and blocked-reason fields instead of expecting a status code.

A 404 appears as a response, not a failed load

That is expected: 404 is an HTTP response, so it is reported through response metadata. Your test should inspect the status code on responseReceived; do not rely only on loadingFailed to identify unsuccessful HTTP responses.

The same request appears several times

The output reports lifecycle events, not one line per resource. Combine events using requestId and update a single request record. Avoid using URL as the unique key because duplicate requests to the same URL can occur.

The browser reports cancellation or a blocked request

Check canceled, blockedReason, and errorText when present. A cancellation or blocked request may be expected in a test, such as when a page changes route or a policy blocks an optional resource. Decide whether it violates the test’s requirement rather than classifying every such event as an asset outage.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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 to obtain a page screenshot rather than assert on individual browser requests, ScreenshotNeo offers a one-call screenshot API. This is not a substitute for Selenium’s per-request status monitoring: it returns a screenshot or PDF rather than a request-event ledger. It can be useful when the deliverable is a clean visual capture.

Before capture, ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers say which page verdict and billing status applied. It also has an MCP server for AI agents, with take_screenshot, get_page_info, and capture_pdf tools.

Example using cURL (see the ScreenshotNeo documentation for API details):

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

The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. See ScreenshotNeo for the service and sign up free to get started.

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 Chrome DevTools to verify a failure manually

When a Selenium report identifies an unexpected asset, confirm it in Chrome DevTools before turning the observation into a permanent assertion. In DevTools, open the Network panel, reload the page, and inspect the resource’s Status, Type, Initiator, Size, and Time columns. Chrome documents these fields in its Network panel guide. Manual confirmation helps distinguish a genuinely required first-party asset from an optional dependency or an expected cancellation.

Frequently Asked Questions

Does a 404 trigger Network.loadingFailed?

Not necessarily. A 404 is an HTTP response; check the status in Network.responseReceived. Reserve loadingFailed for browser-level load failures.

Can Selenium monitor CSS and JavaScript on browsers other than Chrome with this code?

No. This example uses Chrome-specific CDP commands and performance logs. The event model is CDP; another browser requires an appropriate supported instrumentation interface.

Will this detect a JavaScript runtime exception?

No. Network events show request and response behavior, not whether downloaded JavaScript executed successfully or threw an exception.

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

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.