Register a route handler before navigation: `await page.route('**/api/users', route => route.fulfill({ status: 200, body: JSON.stringify([{ id: 1, name: 'Alice' }]) }))` — the glob pattern matches the URL and `fulfill` returns the mock response.
To modify a real response rather than replace it, use `route.fetch()` to make the actual request, mutate the response body, and call `route.fulfill({ response, body: modifiedBody })`.
Abort specific requests (e.g., analytics) with `route.abort()` to speed up tests and remove noise.
Inspect outgoing requests without blocking them using `page.on('request', req => console.log(req.url()))` and `page.on('response', res => ...)` event listeners.
Remove a route when no longer needed with `page.unroute('**/api/users')` to avoid interfering with subsequent navigation in the same context.
Known gotchas
Route handlers are matched in the order they are registered; the first matching handler wins. If you register a catch-all route early, it may intercept requests you intended to pass through — register specific routes before broad ones.
`page.route` intercepts requests made by the page, but not requests from service workers or shared workers running in the same context unless you also use `browserContext.route`.
When using `route.fetch()` to proxy through to the real server, the request inherits the original headers. If the test environment cannot reach the real server (e.g., in offline CI), the fetch will fail — stub the response entirely in that case instead of using the proxy pattern.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp