VLearnVibium

How to Monitor Network Requests with Vibium

Monitor network requests with Vibium in Python — log every request and response with onRequest and onResponse, then wait for a specific API call with waitForResponse.

By Pramod Dutta··4 min read·Verified with Vibium 26.2
▶ Animated overview · made with Remotion

To monitor network requests with Vibium, register page.onRequest() and page.onResponse() callbacks before you navigate, then read each request's url() and method() and each response's status(). Vibium captures live traffic over WebDriver BiDi, so you see every API call, asset, and XHR the page fires as it loads. To wait for one specific call to finish — say an XHR that runs after a button click — use page.waitForResponse(pattern), which blocks until a matching response arrives and hands it back so you can read its status(), headers(), and json(). This replaces brittle fixed sleeps with a precise, event-driven wait. It is the same observability you get from a browser's network tab, exposed as a clean Python API you can script and assert against.

What is the network-logging script?

from vibium import browser_sync as browser
 
vibe = browser.launch()
 
vibe.on_request(lambda req: print("->", req.method(), req.url()))
vibe.on_response(lambda res: print("<-", res.status(), res.url()))
 
vibe.go("https://example.com")
 
vibe.quit()

This registers a request and a response listener, then navigates. As the page loads, every outgoing request prints with its method and URL, and every response prints with its HTTP status. Registering the callbacks before go() matters — listeners only capture traffic that happens after they are attached.

How does each step work?

  1. vibe.on_request(fn) — runs your callback for each outgoing request. The request object exposes url(), method(), and headers().
  2. vibe.on_response(fn) — runs your callback for each completed response, exposing status(), headers(), body(), and json().
  3. vibe.go(url) — triggers the page load, which fires the requests your listeners capture.
  4. vibe.quit() — shuts the browser and tears down the listeners.

Because callbacks are event-driven, you see traffic in real time as the page runs, not as a batch dump after the fact.

How do I wait for a specific API call?

Fixed sleeps are fragile — too short and you read stale data, too long and your script crawls. waitForResponse() blocks only until the matching call lands:

from vibium import browser_sync as browser
 
vibe = browser.launch()
vibe.go("https://example.com/dashboard")
 
# Trigger an action that fires an XHR, then wait for that exact response
vibe.find("#load-more").click()
res = vibe.wait_for_response("**/api/items*")
 
print("status:", res.status())
print("payload:", res.json())
 
vibe.quit()

wait_for_response() takes a URL pattern, waits until a response whose URL matches arrives, and returns the response object. From there res.json() parses the body so you can assert on the actual data the API returned.

How do I filter to just the API calls I care about?

Page loads fire dozens of requests for images, fonts, and scripts. Filter inside your callback so the log stays signal, not noise:

def log_api(res):
    url = res.url()
    if "/api/" in url:
        print(res.status(), res.method() if hasattr(res, "method") else "", url)
 
vibe.on_response(log_api)
vibe.go("https://example.com/app")

Filtering on a path fragment like /api/ keeps your output focused on the XHR and fetch calls that matter, while ignoring static assets.

How do I assert on response status and data?

Network monitoring shines in tests: confirm an endpoint returned 200 and the expected payload. Collect responses into a list, then check them after the action completes:

calls = []
vibe.on_response(lambda res: calls.append((res.url(), res.status())))
 
vibe.go("https://example.com/checkout")
vibe.find("#pay").click()
 
# Confirm no request failed
failed = [c for c in calls if c[1] >= 400]
assert not failed, f"Failed requests: {failed}"

This catches silent failures — a 500 from a background API that the UI swallows but that still breaks the experience.

Notes on request bodies

Reading a request's url(), method(), and headers() works out of the box. Reading a request body (postData()) may require a data collector, because WebDriver BiDi does not always capture request payloads by default. If you need POST bodies, check the official docs at vibium.com for the data-collector setup rather than assuming the body is present.

Tips for reliable network monitoring

  • Attach listeners before go() — callbacks only capture traffic that occurs after they are registered.
  • Prefer waitForResponse() over sleeps — it waits exactly as long as the call takes and no longer.
  • Filter early — match on a path fragment inside the callback to keep logs readable on busy pages.

Next steps

Frequently asked questions

How do I monitor network requests with Vibium?

Register a callback with page.onRequest() and page.onResponse() before navigating, then read each request's url() and method() and each response's status(). Vibium captures live traffic over WebDriver BiDi, so you see every API call, asset, and XHR the page makes as it loads.

How do I wait for a specific API call in Vibium?

Use page.waitForResponse(pattern) to block until a matching response arrives, then read its status() and json(). This is ideal for waiting on an XHR or fetch to finish after a click, instead of guessing with a fixed sleep that may be too short or too long.

Can Vibium read the body of a network response?

Yes. A response object exposes status(), headers(), body(), and json() so you can assert on returned data. Reading a request body may require a data collector because request payloads are not always captured by default in WebDriver BiDi.

Vibium is created by Jason Huggins. This is an independent tutorial — see the official Vibium site and GitHub repo for canonical docs.

Related guides