Implementation:Microsoft Playwright Page Route
| Knowledge Sources | |
|---|---|
| Domains | Network_Testing, Mocking, Request_Interception |
| Last Updated | 2026-02-11 00:00 GMT |
Overview
Concrete tool for intercepting network requests and providing custom fulfillment, modification, or abortion provided by the Playwright library.
Description
The page.route() method registers a route handler that intercepts network requests matching a URL pattern. The handler receives a Route object and a Request object, and must call one of three terminal methods: route.fulfill(), route.continue(), or route.abort(). Additionally, route.fallback() passes control to the next matching handler, and route.fetch() makes the actual server request and returns the response for inspection or modification.
The route is registered at packages/playwright-core/src/client/page.ts:L506-509. The handler is wrapped in a RouteHandler object (packages/playwright-core/src/client/network.ts:L811-905) that manages URL matching via urlMatches() at L844 and handler invocation at L848. Route handlers are stored in an internal _routes array with newest handlers at the front (unshift), ensuring last-registered-first-checked ordering.
The Route class (packages/playwright-core/src/client/network.ts:L299-454) provides the core interception API:
route.fulfill()at L352-356 constructs and returns a synthetic response.route.continue()at L426-431 forwards the request with optional modifications.route.abort()at L334-338 cancels the request with an error code.route.fallback()at L328-332 passes to the next handler without consuming the route.route.fetch()at L346-350 performs the actual network request and returns anAPIResponse.
Usage
Use page.route() when:
- You need to mock API responses to return predictable data in tests.
- You want to test how the UI handles specific HTTP status codes (404, 500, etc.).
- You need to modify request headers before they are sent to the server.
- You want to block specific resources to speed up page loading in tests.
- You need to simulate slow responses or network errors.
- You want to modify response bodies while still hitting the real server.
Code Reference
Source Location
- Repository: playwright
- page.route():
packages/playwright-core/src/client/page.ts:L506-509 - Route class:
packages/playwright-core/src/client/network.ts:L299-454 - RouteHandler class:
packages/playwright-core/src/client/network.ts:L811-905
Signature
// Register a route handler
page.route(
url: string | RegExp | ((url: URL) => boolean),
handler: (route: Route, request: Request) => Promise<void> | void,
options?: { times?: number }
): Promise<void>;
// Route class methods
class Route {
request(): Request;
fulfill(options?: {
response?: APIResponse;
status?: number;
headers?: Record<string, string>;
contentType?: string;
body?: string | Buffer;
json?: any;
path?: string;
}): Promise<void>;
continue(options?: {
url?: string;
method?: string;
headers?: Record<string, string>;
postData?: string | Buffer | object;
}): Promise<void>;
abort(errorCode?: string): Promise<void>;
fallback(options?: {
url?: string;
method?: string;
headers?: Record<string, string>;
postData?: string | Buffer | object;
}): Promise<void>;
fetch(options?: {
url?: string;
method?: string;
headers?: Record<string, string>;
postData?: string | Buffer | object;
maxRedirects?: number;
maxRetries?: number;
timeout?: number;
}): Promise<APIResponse>;
}
Import
// Playwright Test (recommended)
import { test, expect } from '@playwright/test';
// Library mode
import { chromium } from 'playwright';
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| url | RegExp | ((url: URL) => boolean) | Yes | URL pattern to match. Strings support glob syntax (**/api/*). RegExp provides full regex matching. Functions receive the URL object for custom logic.
|
| handler | (route: Route, request: Request) => void |
Yes | Callback function invoked for each matching request. Must call fulfill(), continue(), abort(), or fallback().
|
| options.times | number |
No | Maximum number of times the handler will be invoked. After this count, the route is automatically removed. |
| route.fulfill options.status | number |
No | HTTP status code (default: 200). |
| route.fulfill options.headers | Record<string, string> |
No | Response headers. |
| route.fulfill options.contentType | string |
No | Shortcut for setting the content-type header.
|
| route.fulfill options.body | Buffer | No | Response body as string or buffer. |
| route.fulfill options.json | any |
No | Response body as JSON (auto-sets content-type to application/json). Mutually exclusive with body.
|
| route.fulfill options.path | string |
No | Path to a file to serve as the response body. |
| route.fulfill options.response | APIResponse |
No | An APIResponse from route.fetch() to use as the base for the response.
|
| route.continue options.url | string |
No | Override the request URL. |
| route.continue options.method | string |
No | Override the HTTP method. |
| route.continue options.headers | Record<string, string> |
No | Override the request headers. |
| route.continue options.postData | Buffer | object | No | Override the request body. |
| route.abort errorCode | string |
No | Error code: 'aborted', 'accessdenied', 'addressunreachable', 'blockedbyclient', 'blockedbyresponse', 'connectionaborted', 'connectionclosed', 'connectionfailed', 'connectionrefused', 'connectionreset', 'internetdisconnected', 'namenotresolved', 'timedout', 'failed'.
|
Outputs
| Name | Type | Description |
|---|---|---|
| page.route return | Promise<void> |
Resolves when the route handler is registered. |
| route.fulfill return | Promise<void> |
Resolves when the synthetic response has been delivered to the browser. |
| route.continue return | Promise<void> |
Resolves when the (possibly modified) request has been sent to the network. |
| route.abort return | Promise<void> |
Resolves when the request has been aborted. |
| route.fetch return | Promise<APIResponse> |
Resolves with the actual server response, which can be inspected or passed to route.fulfill().
|
Usage Examples
Basic Example: Mock an API Response
import { test, expect } from '@playwright/test';
test('mock API response', async ({ page }) => {
// Intercept API calls and return mock data
await page.route('**/api/users', route => {
route.fulfill({
status: 200,
json: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
],
});
});
await page.goto('https://example.com/users');
await expect(page.locator('.user')).toHaveCount(2);
});
Modify Request Headers
import { test, expect } from '@playwright/test';
test('inject auth header', async ({ page }) => {
await page.route('**/api/**', route => {
const headers = route.request().headers();
headers['authorization'] = 'Bearer test-token-123';
route.continue({ headers });
});
await page.goto('https://example.com/dashboard');
});
Modify Response Body
import { test, expect } from '@playwright/test';
test('modify server response', async ({ page }) => {
await page.route('**/api/config', async route => {
// Fetch real response from server
const response = await route.fetch();
const json = await response.json();
// Modify the response
json.featureFlags.newDashboard = true;
// Fulfill with modified data
await route.fulfill({ response, json });
});
await page.goto('https://example.com');
});
Abort Requests to Block Resources
import { test, expect } from '@playwright/test';
test('block images for faster tests', async ({ page }) => {
await page.route('**/*.{png,jpg,jpeg,gif,svg}', route => {
route.abort();
});
await page.goto('https://example.com');
});
Use times Option for One-Shot Mock
import { test, expect } from '@playwright/test';
test('mock first request only', async ({ page }) => {
// Only mock the first call; subsequent calls go to the real server
await page.route('**/api/data', route => {
route.fulfill({ json: { value: 'mocked' } });
}, { times: 1 });
await page.goto('https://example.com');
});