A high-level API to control headless Chrome and Firefox browsers over the DevTools Protocol and WebDriver BiDi
94
Request interception, response mocking, and comprehensive network monitoring for testing and debugging.
Represents an HTTP request that can be intercepted, modified, or monitored.
interface HTTPRequest {
/** Get request URL */
url(): string;
/** Get resource type */
resourceType(): ResourceType;
/** Get HTTP method */
method(): string;
/** Get request headers */
headers(): Record<string, string>;
/** Get POST data */
postData(): string | undefined;
/** Get POST data as buffer */
postDataBuffer(): Buffer | undefined;
/** Check if request is navigation request */
isNavigationRequest(): boolean;
/** Check if request is intercepted */
isInterceptResolutionHandled(): boolean;
/** Get response */
response(): HTTPResponse | null;
/** Get frame that initiated request */
frame(): Frame | null;
/** Get redirect chain */
redirectChain(): HTTPRequest[];
/** Get failure details if request failed */
failure(): { errorText: string } | null;
/** Abort request */
abort(errorCode?: ErrorCode): Promise<void>;
/** Continue request with optional overrides */
continue(overrides?: ContinueRequestOverrides): Promise<void>;
/** Respond to request with mock response */
respond(response: ResponseForRequest): Promise<void>;
/** Get request initiator */
initiator(): Initiator;
/** Check if request has POST data */
hasPostData(): boolean;
}
type ResourceType =
| "document"
| "stylesheet"
| "image"
| "media"
| "font"
| "script"
| "texttrack"
| "xhr"
| "fetch"
| "prefetch"
| "eventsource"
| "websocket"
| "manifest"
| "signedexchange"
| "ping"
| "cspviolationreport"
| "preflight"
| "other";
type ErrorCode =
| "aborted"
| "accessdenied"
| "addressunreachable"
| "blockedbyclient"
| "blockedbyresponse"
| "connectionaborted"
| "connectionclosed"
| "connectionfailed"
| "connectionrefused"
| "connectionreset"
| "internetdisconnected"
| "namenotresolved"
| "timedout"
| "failed";
interface ContinueRequestOverrides {
/** Override URL */
url?: string;
/** Override method */
method?: string;
/** Override POST data */
postData?: string;
/** Override headers */
headers?: Record<string, string>;
}
interface ResponseForRequest {
/** Response status code */
status?: number;
/** Response headers */
headers?: Record<string, string>;
/** Response body */
body?: string | Buffer;
/** Content type header */
contentType?: string;
}
interface Initiator {
/** Type of initiator */
type: "parser" | "script" | "preload" | "SignedExchange" | "preflight" | "other";
/** Stack trace if initiated by script */
stack?: CallFrame[];
/** URL if initiated by parser */
url?: string;
/** Line number */
lineNumber?: number;
/** Column number */
columnNumber?: number;
}
interface CallFrame {
functionName: string;
scriptId: string;
url: string;
lineNumber: number;
columnNumber: number;
}Usage Examples:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.launch({ executablePath: "/path/to/chrome" });
const page = await browser.newPage();
// Enable request interception
await page.setRequestInterception(true);
// Basic request monitoring
page.on("request", (request) => {
console.log("Request:", request.method(), request.url());
console.log("Resource type:", request.resourceType());
console.log("Headers:", request.headers());
// Continue all requests normally
request.continue();
});
// Block specific resource types
page.on("request", (request) => {
if (request.resourceType() === "image") {
request.abort("blockedbyclient");
} else {
request.continue();
}
});
// Modify requests
page.on("request", (request) => {
const overrides: ContinueRequestOverrides = {};
// Add custom header
overrides.headers = {
...request.headers(),
"X-Custom-Header": "custom-value"
};
// Modify user agent
if (request.headers()["user-agent"]) {
overrides.headers["user-agent"] = "Custom-User-Agent/1.0";
}
request.continue(overrides);
});
// Mock API responses
page.on("request", (request) => {
if (request.url().includes("/api/users")) {
request.respond({
status: 200,
contentType: "application/json",
body: JSON.stringify([
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Smith" }
])
});
} else {
request.continue();
}
});
await page.goto("https://example.com");
await browser.close();Represents an HTTP response received from the server.
interface HTTPResponse {
/** Get response URL */
url(): string;
/** Check if response is successful (200-299) */
ok(): boolean;
/** Get status code */
status(): number;
/** Get status text */
statusText(): string;
/** Get response headers */
headers(): Record<string, string>;
/** Get security details for HTTPS */
securityDetails(): SecurityDetails | null;
/** Get request that produced this response */
request(): HTTPRequest;
/** Check if response was served from cache */
fromCache(): boolean;
/** Check if response was served from service worker */
fromServiceWorker(): boolean;
/** Get frame that received this response */
frame(): Frame | null;
/** Get response body as text */
text(): Promise<string>;
/** Get response body as JSON */
json(): Promise<any>;
/** Get response body as buffer */
buffer(): Promise<Buffer>;
/** Get timing information */
timing(): ResponseTiming | null;
/** Get remote address */
remoteAddress(): RemoteAddress;
}
interface SecurityDetails {
/** Subject name */
subjectName(): string;
/** Issuer name */
issuer(): string;
/** Valid from timestamp */
validFrom(): number;
/** Valid to timestamp */
validTo(): number;
/** Protocol version */
protocol(): string;
/** Subject alternative names */
subjectAlternativeNames(): string[];
}
interface ResponseTiming {
/** Request start time */
requestTime: number;
/** Proxy start time */
proxyStart: number;
/** Proxy end time */
proxyEnd: number;
/** DNS start time */
dnsStart: number;
/** DNS end time */
dnsEnd: number;
/** Connect start time */
connectStart: number;
/** Connect end time */
connectEnd: number;
/** SSL start time */
sslStart: number;
/** SSL end time */
sslEnd: number;
/** Worker start time */
workerStart: number;
/** Worker ready time */
workerReady: number;
/** Send start time */
sendStart: number;
/** Send end time */
sendEnd: number;
/** Push start time */
pushStart: number;
/** Push end time */
pushEnd: number;
/** Receive headers end time */
receiveHeadersEnd: number;
}
interface RemoteAddress {
/** IP address */
ip: string;
/** Port number */
port: number;
}Usage Examples:
// Response monitoring
page.on("response", async (response) => {
console.log("Response:", response.status(), response.url());
console.log("Headers:", response.headers());
console.log("From cache:", response.fromCache());
console.log("From service worker:", response.fromServiceWorker());
if (!response.ok()) {
console.log("Failed response:", response.statusText());
}
// Get response body for specific URLs
if (response.url().includes("/api/")) {
const body = await response.text();
console.log("API Response body:", body);
}
});
// Security information for HTTPS
page.on("response", (response) => {
const security = response.securityDetails();
if (security) {
console.log("Certificate subject:", security.subjectName());
console.log("Certificate issuer:", security.issuer());
console.log("Protocol:", security.protocol());
}
});
// Performance monitoring
page.on("response", (response) => {
const timing = response.timing();
if (timing) {
const totalTime = timing.receiveHeadersEnd - timing.requestTime;
console.log(`Request to ${response.url()} took ${totalTime}ms`);
}
});Common patterns for request interception and modification:
interface RequestInterceptionPatterns {
/** Block resources by type or URL pattern */
blockResources(patterns: ResourceBlockPattern[]): void;
/** Mock API endpoints */
mockAPIs(mocks: APIMock[]): void;
/** Add authentication headers */
addAuth(token: string): void;
/** Modify user agent */
setUserAgent(userAgent: string): void;
/** Add CORS headers to responses */
enableCORS(): void;
/** Log all network activity */
logAllRequests(): void;
}
interface ResourceBlockPattern {
resourceType?: ResourceType;
urlPattern?: string | RegExp;
errorCode?: ErrorCode;
}
interface APIMock {
urlPattern: string | RegExp;
method?: string;
response: ResponseForRequest;
}Usage Examples:
// Block images and stylesheets for faster loading
await page.setRequestInterception(true);
page.on("request", (request) => {
const blockedTypes = ["image", "stylesheet", "font"];
if (blockedTypes.includes(request.resourceType())) {
request.abort("blockedbyclient");
} else {
request.continue();
}
});
// Mock multiple API endpoints
const apiMocks = [
{
url: "/api/users",
response: {
status: 200,
contentType: "application/json",
body: JSON.stringify([{ id: 1, name: "Test User" }])
}
},
{
url: "/api/config",
response: {
status: 200,
contentType: "application/json",
body: JSON.stringify({ theme: "dark", version: "1.0.0" })
}
}
];
page.on("request", (request) => {
const mock = apiMocks.find(m => request.url().includes(m.url));
if (mock) {
request.respond(mock.response);
} else {
request.continue();
}
});
// Add authentication to all API requests
page.on("request", (request) => {
if (request.url().includes("/api/")) {
const headers = {
...request.headers(),
"Authorization": "Bearer your-token-here"
};
request.continue({ headers });
} else {
request.continue();
}
});
// Comprehensive request logging
page.on("request", (request) => {
console.log(`→ ${request.method()} ${request.url()}`);
console.log(` Type: ${request.resourceType()}`);
console.log(` Headers:`, request.headers());
if (request.postData()) {
console.log(` POST data:`, request.postData());
}
request.continue();
});
page.on("response", async (response) => {
console.log(`← ${response.status()} ${response.url()}`);
console.log(` Headers:`, response.headers());
if (response.url().includes("/api/")) {
const body = await response.text();
console.log(` Body:`, body);
}
});
page.on("requestfailed", (request) => {
const failure = request.failure();
console.log(`✗ ${request.url()} failed: ${failure?.errorText}`);
});Page-level network events for monitoring and debugging:
interface NetworkEvents {
/** Emitted when request starts */
"request": (request: HTTPRequest) => void;
/** Emitted when response received */
"response": (response: HTTPResponse) => void;
/** Emitted when request completes successfully */
"requestfinished": (request: HTTPRequest) => void;
/** Emitted when request fails */
"requestfailed": (request: HTTPRequest) => void;
}Usage Examples:
// Network event monitoring
const networkEvents = [];
page.on("request", (request) => {
networkEvents.push({
type: "request",
url: request.url(),
method: request.method(),
timestamp: Date.now()
});
});
page.on("response", (response) => {
networkEvents.push({
type: "response",
url: response.url(),
status: response.status(),
timestamp: Date.now()
});
});
page.on("requestfailed", (request) => {
const failure = request.failure();
networkEvents.push({
type: "requestfailed",
url: request.url(),
error: failure?.errorText,
timestamp: Date.now()
});
});
// Analyze network activity after page load
await page.goto("https://example.com");
await page.waitForLoadState("networkidle");
console.log("Network activity summary:");
console.log(`Total requests: ${networkEvents.filter(e => e.type === "request").length}`);
console.log(`Successful responses: ${networkEvents.filter(e => e.type === "response").length}`);
console.log(`Failed requests: ${networkEvents.filter(e => e.type === "requestfailed").length}`);Advanced networking capabilities and utilities:
interface AdvancedNetworkFeatures {
/** Wait for specific request/response */
waitForRequest(urlOrPredicate: string | ((req: HTTPRequest) => boolean), options?: WaitForOptions): Promise<HTTPRequest>;
waitForResponse(urlOrPredicate: string | ((res: HTTPResponse) => boolean), options?: WaitForOptions): Promise<HTTPResponse>;
/** Capture network traffic */
captureNetworkTraffic(): NetworkCapture;
/** Simulate network conditions */
setNetworkConditions(conditions: NetworkConditions): Promise<void>;
/** Set offline mode */
setOfflineMode(enabled: boolean): Promise<void>;
/** Set user agent */
setUserAgent(userAgent: string, userAgentMetadata?: UserAgentMetadata): Promise<void>;
/** Set extra HTTP headers */
setExtraHTTPHeaders(headers: Record<string, string>): Promise<void>;
/** Authenticate with HTTP credentials */
authenticate(credentials: Credentials | null): Promise<void>;
}
interface NetworkCapture {
/** Start capturing */
start(): Promise<void>;
/** Stop capturing and return data */
stop(): Promise<NetworkTrafficEntry[]>;
}
interface NetworkTrafficEntry {
request: {
url: string;
method: string;
headers: Record<string, string>;
postData?: string;
timestamp: number;
};
response?: {
status: number;
headers: Record<string, string>;
body: string;
timestamp: number;
};
timing: ResponseTiming;
}
interface NetworkConditions {
/** Download speed in bytes/sec */
downloadThroughput: number;
/** Upload speed in bytes/sec */
uploadThroughput: number;
/** Latency in milliseconds */
latency: number;
/** Offline mode */
offline?: boolean;
}
interface WaitForOptions {
/** Maximum wait time */
timeout?: number;
/** Wait for navigation to complete */
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}Usage Examples:
// Wait for specific requests/responses
const apiRequest = page.waitForRequest(req =>
req.url().includes("/api/data") && req.method() === "POST"
);
const apiResponse = page.waitForResponse(res =>
res.url().includes("/api/data") && res.status() === 200
);
// Trigger the requests
await page.click("#load-data-button");
// Wait for completion
const [request, response] = await Promise.all([apiRequest, apiResponse]);
console.log("API call completed:", response.status());
// Simulate slow network
await page.emulateNetworkConditions({
downloadThroughput: 50 * 1024, // 50KB/s
uploadThroughput: 20 * 1024, // 20KB/s
latency: 200 // 200ms
});
// Test offline functionality
await page.setOfflineMode(true);
try {
await page.goto("https://example.com");
} catch (error) {
console.log("Page failed to load offline:", error.message);
}
await page.setOfflineMode(false);
// Set custom headers for all requests
await page.setExtraHTTPHeaders({
"X-API-Key": "your-api-key",
"X-Client-Version": "1.0.0"
});
// HTTP authentication
await page.authenticate({
username: "testuser",
password: "testpass"
});Network-related error handling and debugging:
class NetworkError extends Error {
constructor(message: string);
}
class RequestInterceptionError extends NetworkError {
constructor(message: string);
}
class ResponseError extends NetworkError {
constructor(message: string, response: HTTPResponse);
response: HTTPResponse;
}Usage Examples:
// Robust request interception with error handling
page.on("request", async (request) => {
try {
if (request.url().includes("/api/")) {
// Validate request before continuing
const headers = request.headers();
if (!headers["authorization"]) {
await request.respond({
status: 401,
body: JSON.stringify({ error: "Unauthorized" })
});
return;
}
}
await request.continue();
} catch (error) {
console.log("Request interception error:", error.message);
// Fallback: continue the request
try {
await request.continue();
} catch (fallbackError) {
console.log("Fallback failed:", fallbackError.message);
}
}
});
// Handle response errors gracefully
page.on("response", async (response) => {
if (!response.ok()) {
console.log(`HTTP ${response.status()} for ${response.url()}`);
try {
const body = await response.text();
console.log("Error response body:", body);
} catch (error) {
console.log("Could not read error response body:", error.message);
}
}
});
// Retry failed requests
async function waitForResponseWithRetry(
page: Page,
urlPattern: string,
maxRetries = 3
): Promise<HTTPResponse> {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await page.waitForResponse(
res => res.url().includes(urlPattern),
{ timeout: 10000 }
);
if (response.ok()) {
return response;
}
console.log(`Attempt ${i + 1}: Response ${response.status()}`);
} catch (error) {
console.log(`Attempt ${i + 1} failed:`, error.message);
}
if (i < maxRetries - 1) {
await page.waitForTimeout(1000 * (i + 1)); // Exponential backoff
}
}
throw new NetworkError(`Failed to get successful response after ${maxRetries} attempts`);
}Install with Tessl CLI
npx tessl i tessl/npm-puppeteer-coredocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10