Register a route handler: await page.route('**/api/**', async route => { ... }) before triggering the network request
Inside the handler, fetch the original response via route.fetch() (which uses Playwright's internal request context) to preserve the real response body and status
Call route.fulfill({ response: originalResponse, headers: { ...originalResponse.headers(), 'x-custom-header': 'value' } }) to forward the response with modified headers
To remove a header, pass it with an empty string value; to add one, include it in the headers map alongside the originals
Unregister the route after the test if registering at the context level to avoid leaking the handler into subsequent tests
Known gotchas
route.fetch() reuses Playwright's own networking, not the browser's — cookies attached to the browser session are not automatically forwarded unless you pass the request's headers explicitly
Header values are always coerced to strings; passing null or undefined for a header key throws rather than removing it — use an empty string to suppress a header
Using route.continue() with the headers option modifies request headers (outbound), not response headers — use route.fulfill() for modifying responses
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