A high-level API to control headless Chrome and Firefox browsers over the DevTools Protocol and WebDriver BiDi
94
Isolated browser contexts for managing sessions, cookies, permissions, and parallel test execution.
Provides isolated browser sessions with independent cookies, storage, and permissions.
interface BrowserContext extends EventEmitter {
/** Create new page in this context */
newPage(): Promise<Page>;
/** Get all pages in this context */
pages(): Page[];
/** Get browser instance */
browser(): Browser;
/** Close context and all pages */
close(): Promise<void>;
/** Check if context is closed */
isIncognito(): boolean;
/** Get/set cookies */
cookies(...urls: string[]): Promise<Cookie[]>;
setCookie(...cookies: CookieParam[]): Promise<void>;
addCookies(cookies: CookieParam[]): Promise<void>;
clearCookies(): Promise<void>;
/** Permissions management */
grantPermissions(permissions: Permission[], options?: { origin?: string }): Promise<void>;
clearPermissionOverrides(): Promise<void>;
overridePermissions(origin: string, permissions: Permission[]): Promise<void>;
/** Geolocation */
setGeolocation(geolocation: GeolocationOptions): Promise<void>;
/** HTTP credentials */
setHTTPCredentials(httpCredentials: HTTPCredentials | null): Promise<void>;
/** User agent */
setUserAgent(userAgent: string): Promise<void>;
/** Viewport */
setViewportSize(viewportSize: ViewportSize): Promise<void>;
/** Offline mode */
setOffline(offline: boolean): Promise<void>;
/** Extra HTTP headers */
setExtraHTTPHeaders(headers: Record<string, string>): Promise<void>;
/** Request interception */
setRequestInterception(value: boolean): Promise<void>;
/** Default timeout */
setDefaultTimeout(timeout: number): void;
setDefaultNavigationTimeout(timeout: number): void;
/** Wait for events */
waitForEvent(event: string, optionsOrPredicate?: Function | { timeout?: number; predicate?: Function }): Promise<any>;
/** Tracing */
tracing(): Tracing;
/** Route handling */
route(url: string | RegExp | ((url: URL) => boolean), handler: RouteHandler): Promise<void>;
unroute(url: string | RegExp | ((url: URL) => boolean), handler?: RouteHandler): Promise<void>;
/** Storage state */
storageState(options?: { path?: string }): Promise<StorageState>;
addInitScript(script: Function | string | { path?: string; content?: string }): Promise<void>;
/** Expose function to all pages */
exposeFunction(name: string, callback: Function): Promise<void>;
exposeBinding(name: string, callback: Function, options?: { handle?: boolean }): Promise<void>;
/** Service workers */
serviceWorkers(): Worker[];
/** Background pages */
backgroundPages(): Page[];
/** CDPSession */
newCDPSession(page: Page): Promise<CDPSession>;
}
interface Cookie {
name: string;
value: string;
domain?: string;
path?: string;
expires?: number;
httpOnly?: boolean;
secure?: boolean;
sameSite?: "Strict" | "Lax" | "None";
priority?: "Low" | "Medium" | "High";
sameParty?: boolean;
sourceScheme?: "Unset" | "NonSecure" | "Secure";
partitionKey?: string;
}
interface CookieParam {
name: string;
value: string;
url?: string;
domain?: string;
path?: string;
secure?: boolean;
httpOnly?: boolean;
sameSite?: "Strict" | "Lax" | "None";
expires?: number;
priority?: "Low" | "Medium" | "High";
sameParty?: boolean;
sourceScheme?: "Unset" | "NonSecure" | "Secure";
partitionKey?: string;
}
type Permission =
| "geolocation"
| "midi"
| "notifications"
| "camera"
| "microphone"
| "background-sync"
| "ambient-light-sensor"
| "accelerometer"
| "gyroscope"
| "magnetometer"
| "accessibility-events"
| "clipboard-read"
| "clipboard-write"
| "payment-handler"
| "persistent-storage"
| "idle-detection"
| "midi-sysex";
interface GeolocationOptions {
latitude: number;
longitude: number;
accuracy?: number;
}
interface HTTPCredentials {
username: string;
password: string;
origin?: string;
}
interface ViewportSize {
width: number;
height: number;
}
interface RouteHandler {
(route: Route, request: Request): Promise<void> | void;
}
interface StorageState {
cookies: Cookie[];
origins: OriginState[];
}
interface OriginState {
origin: string;
localStorage: NameValuePair[];
sessionStorage: NameValuePair[];
}
interface NameValuePair {
name: string;
value: string;
}Usage Examples:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.launch({ executablePath: "/path/to/chrome" });
// Create isolated contexts
const context1 = await browser.createBrowserContext();
const context2 = await browser.createBrowserContext();
// Each context has its own session
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// Set different cookies for each context
await context1.setCookie({
name: "user",
value: "alice",
domain: "example.com"
});
await context2.setCookie({
name: "user",
value: "bob",
domain: "example.com"
});
// Navigate to same site - each will have different cookies
await page1.goto("https://example.com");
await page2.goto("https://example.com");
// Set different permissions
await context1.grantPermissions(["geolocation"], { origin: "https://example.com" });
await context2.overridePermissions("https://example.com", []); // No permissions
// Close contexts
await context1.close();
await context2.close();
await browser.close();Create browser contexts with specific configurations:
interface BrowserContextOptions {
/** Accept downloads */
acceptDownloads?: boolean;
/** Bypass CSP */
bypassCSP?: boolean;
/** Color scheme */
colorScheme?: "light" | "dark" | "no-preference";
/** Device scale factor */
deviceScaleFactor?: number;
/** Extra HTTP headers */
extraHTTPHeaders?: Record<string, string>;
/** Geolocation */
geolocation?: GeolocationOptions;
/** Has touch */
hasTouch?: boolean;
/** HTTP credentials */
httpCredentials?: HTTPCredentials;
/** Ignore HTTPS errors */
ignoreHTTPSErrors?: boolean;
/** Is mobile */
isMobile?: boolean;
/** Java Script enabled */
javaScriptEnabled?: boolean;
/** Locale */
locale?: string;
/** Offline */
offline?: boolean;
/** Permissions */
permissions?: Permission[];
/** Proxy */
proxy?: ProxySettings;
/** Record HAR */
recordHar?: HarOptions;
/** Record video */
recordVideo?: VideoOptions;
/** Reduced motion */
reducedMotion?: "reduce" | "no-preference";
/** Screen */
screen?: ScreenSize;
/** Service workers */
serviceWorkers?: "allow" | "block";
/** Storage state */
storageState?: string | StorageState;
/** Timezone */
timezoneId?: string;
/** User agent */
userAgent?: string;
/** Viewport */
viewport?: ViewportSize | null;
}
interface ProxySettings {
server: string;
bypass?: string;
username?: string;
password?: string;
}
interface HarOptions {
omitContent?: boolean;
path?: string;
}
interface VideoOptions {
dir: string;
size?: ViewportSize;
}
interface ScreenSize {
width: number;
height: number;
}Usage Examples:
// Create context with mobile emulation
const mobileContext = await browser.createBrowserContext({
viewport: { width: 375, height: 667 },
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15",
isMobile: true,
hasTouch: true,
deviceScaleFactor: 2
});
// Create context with specific locale and timezone
const localizedContext = await browser.createBrowserContext({
locale: "de-DE",
timezoneId: "Europe/Berlin",
colorScheme: "dark"
});
// Create context with geolocation and permissions
const locationContext = await browser.createBrowserContext({
geolocation: { latitude: 37.7749, longitude: -122.4194 },
permissions: ["geolocation", "notifications"]
});
// Create context with proxy
const proxyContext = await browser.createBrowserContext({
proxy: {
server: "http://proxy.example.com:8080",
username: "proxyuser",
password: "proxypass"
}
});
// Create context with custom storage state
const contextWithStorage = await browser.createBrowserContext({
storageState: {
cookies: [
{
name: "session_id",
value: "abc123",
domain: "example.com",
path: "/",
secure: true,
httpOnly: true
}
],
origins: [
{
origin: "https://example.com",
localStorage: [
{ name: "theme", value: "dark" },
{ name: "language", value: "en" }
],
sessionStorage: []
}
]
}
});Comprehensive cookie management within contexts:
interface CookieManagement {
/** Add single cookie */
addCookie(cookie: CookieParam): Promise<void>;
/** Add multiple cookies */
addCookies(cookies: CookieParam[]): Promise<void>;
/** Get cookies for URLs */
getCookies(urls?: string[]): Promise<Cookie[]>;
/** Set cookies (replaces existing) */
setCookies(cookies: CookieParam[]): Promise<void>;
/** Delete specific cookies */
deleteCookies(cookies: DeleteCookieParam[]): Promise<void>;
/** Clear all cookies */
clearAllCookies(): Promise<void>;
/** Get cookie by name */
getCookie(name: string, url?: string): Promise<Cookie | null>;
}
interface DeleteCookieParam {
name: string;
url?: string;
domain?: string;
path?: string;
}Usage Examples:
const context = await browser.createBrowserContext();
// Add authentication cookies
await context.addCookies([
{
name: "auth_token",
value: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
domain: "api.example.com",
path: "/",
secure: true,
httpOnly: true,
sameSite: "Strict"
},
{
name: "session_id",
value: "sess_abc123",
domain: "example.com",
path: "/",
expires: Date.now() + 86400000 // 24 hours
}
]);
// Get cookies for specific domains
const allCookies = await context.cookies();
const exampleCookies = await context.cookies("https://example.com");
const apiCookies = await context.cookies("https://api.example.com");
// Update cookie value
await context.setCookie({
name: "theme",
value: "dark",
domain: "example.com"
});
// Delete specific cookies
await context.clearCookies();
// Cookie-based session management
class SessionManager {
constructor(private context: BrowserContext) {}
async login(username: string, password: string) {
const page = await this.context.newPage();
await page.goto("https://example.com/login");
await page.type("#username", username);
await page.type("#password", password);
await page.click("#login-button");
// Wait for redirect and session cookie
await page.waitForNavigation();
await page.close();
}
async isLoggedIn(): Promise<boolean> {
const cookies = await this.context.cookies("https://example.com");
return cookies.some(cookie => cookie.name === "session_id");
}
async logout() {
await this.context.clearCookies();
}
}
const sessionManager = new SessionManager(context);
await sessionManager.login("user@example.com", "password123");Control browser permissions within contexts:
interface PermissionManagement {
/** Grant permissions for origin */
grantPermissions(permissions: Permission[], origin?: string): Promise<void>;
/** Override permissions for origin */
overridePermissions(origin: string, permissions: Permission[]): Promise<void>;
/** Clear permission overrides */
clearPermissionOverrides(): Promise<void>;
/** Check permission state */
getPermissionState(permission: Permission, origin?: string): Promise<PermissionState>;
}
type PermissionState = "granted" | "denied" | "prompt";Usage Examples:
const context = await browser.createBrowserContext();
// Grant geolocation permission
await context.grantPermissions(["geolocation"], {
origin: "https://maps.example.com"
});
// Block notifications globally
await context.overridePermissions("https://example.com", []);
// Grant multiple permissions
await context.grantPermissions([
"camera",
"microphone",
"notifications"
], { origin: "https://video-chat.example.com" });
// Permission-based testing
async function testLocationFeature(context: BrowserContext) {
// Test with permission granted
await context.grantPermissions(["geolocation"]);
const page = await context.newPage();
await page.goto("https://example.com/location");
const locationButton = await page.$("#get-location");
await locationButton.click();
// Verify location was obtained
const locationText = await page.$("#current-location").textContent();
console.log("Location with permission:", locationText);
await page.close();
// Test with permission denied
await context.overridePermissions("https://example.com", []);
const page2 = await context.newPage();
await page2.goto("https://example.com/location");
await page2.click("#get-location");
// Verify error message
const errorText = await page2.$("#location-error").textContent();
console.log("Location without permission:", errorText);
await page2.close();
}
await testLocationFeature(context);Browser context events for monitoring and automation:
interface BrowserContextEvents {
/** Emitted when page is created */
"page": (page: Page) => void;
/** Emitted when page is closed */
"close": () => void;
/** Emitted when background page is created */
"backgroundpage": (page: Page) => void;
/** Emitted when service worker is created */
"serviceworker": (worker: Worker) => void;
/** Emitted when request starts */
"request": (request: HTTPRequest) => void;
/** Emitted when response is received */
"response": (response: HTTPResponse) => void;
/** Emitted when request fails */
"requestfailed": (request: HTTPRequest) => void;
/** Emitted when request finishes */
"requestfinished": (request: HTTPRequest) => void;
}Usage Examples:
const context = await browser.createBrowserContext();
// Monitor page creation
context.on("page", (page) => {
console.log("New page created:", page.url());
// Set up page-level monitoring
page.on("console", (msg) => {
console.log(`Page console: ${msg.text()}`);
});
page.on("pageerror", (error) => {
console.error("Page error:", error.message);
});
});
// Monitor network activity across all pages
context.on("request", (request) => {
console.log(`Request: ${request.method()} ${request.url()}`);
});
context.on("response", (response) => {
if (!response.ok()) {
console.log(`Failed response: ${response.status()} ${response.url()}`);
}
});
// Handle context closure
context.on("close", () => {
console.log("Browser context closed");
});
// Create pages and trigger events
const page1 = await context.newPage();
const page2 = await context.newPage();
await page1.goto("https://example.com");
await page2.goto("https://another-example.com");
await context.close();Save and restore browser state across sessions:
interface StorageStateManagement {
/** Get current storage state */
getStorageState(): Promise<StorageState>;
/** Save storage state to file */
saveStorageState(path: string): Promise<void>;
/** Load storage state from file */
loadStorageState(path: string): Promise<StorageState>;
/** Create context with saved state */
createContextWithState(statePath: string): Promise<BrowserContext>;
}Usage Examples:
// Save authenticated session
const context = await browser.createBrowserContext();
const page = await context.newPage();
// Perform login
await page.goto("https://example.com/login");
await page.type("#username", "user@example.com");
await page.type("#password", "password123");
await page.click("#login-button");
await page.waitForNavigation();
// Save storage state
const storageState = await context.storageState();
await context.storageState({ path: "auth-state.json" });
await context.close();
// Restore session later
const restoredContext = await browser.createBrowserContext({
storageState: "auth-state.json"
});
const restoredPage = await restoredContext.newPage();
await restoredPage.goto("https://example.com/dashboard");
// User should already be logged in
const welcomeText = await restoredPage.$("#welcome-message").textContent();
console.log(welcomeText); // Should show logged-in state
// Session state management utility
class SessionStateManager {
private stateFile: string;
constructor(stateFile: string) {
this.stateFile = stateFile;
}
async createAuthenticatedContext(browser: Browser): Promise<BrowserContext> {
try {
return await browser.createBrowserContext({
storageState: this.stateFile
});
} catch (error) {
console.log("No saved state found, creating fresh context");
return await browser.createBrowserContext();
}
}
async saveState(context: BrowserContext): Promise<void> {
await context.storageState({ path: this.stateFile });
}
async clearState(): Promise<void> {
try {
await import("fs").then(fs => fs.unlinkSync(this.stateFile));
} catch (error) {
// File doesn't exist, nothing to do
}
}
}
const stateManager = new SessionStateManager("user-session.json");
const authContext = await stateManager.createAuthenticatedContext(browser);
// Use context...
await stateManager.saveState(authContext);Use contexts for parallel test execution and isolation:
interface ParallelExecution {
/** Run tests in parallel contexts */
runParallel<T>(tests: (() => Promise<T>)[], maxConcurrency?: number): Promise<T[]>;
/** Create context pool */
createContextPool(browser: Browser, poolSize: number): ContextPool;
/** Execute with context isolation */
withIsolatedContext<T>(browser: Browser, operation: (context: BrowserContext) => Promise<T>): Promise<T>;
}
interface ContextPool {
acquire(): Promise<BrowserContext>;
release(context: BrowserContext): void;
close(): Promise<void>;
}Usage Examples:
// Parallel test execution
async function runParallelTests(browser: Browser) {
const tests = [
async () => {
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto("https://example.com/test1");
const result = await page.$("#result").textContent();
await context.close();
return { test: "test1", result };
},
async () => {
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto("https://example.com/test2");
const result = await page.$("#result").textContent();
await context.close();
return { test: "test2", result };
},
async () => {
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto("https://example.com/test3");
const result = await page.$("#result").textContent();
await context.close();
return { test: "test3", result };
}
];
const results = await Promise.all(tests.map(test => test()));
return results;
}
const testResults = await runParallelTests(browser);
console.log("Test results:", testResults);
// Context pool for resource management
class BrowserContextPool {
private contexts: BrowserContext[] = [];
private inUse: Set<BrowserContext> = new Set();
constructor(private browser: Browser, private maxSize: number) {}
async acquire(): Promise<BrowserContext> {
// Try to find available context
const available = this.contexts.find(ctx => !this.inUse.has(ctx));
if (available) {
this.inUse.add(available);
return available;
}
// Create new context if under limit
if (this.contexts.length < this.maxSize) {
const context = await this.browser.createBrowserContext();
this.contexts.push(context);
this.inUse.add(context);
return context;
}
// Wait for context to become available
return new Promise((resolve) => {
const checkAvailable = () => {
const available = this.contexts.find(ctx => !this.inUse.has(ctx));
if (available) {
this.inUse.add(available);
resolve(available);
} else {
setTimeout(checkAvailable, 100);
}
};
checkAvailable();
});
}
release(context: BrowserContext): void {
this.inUse.delete(context);
}
async close(): Promise<void> {
await Promise.all(this.contexts.map(ctx => ctx.close()));
this.contexts = [];
this.inUse.clear();
}
}
// Usage
const contextPool = new BrowserContextPool(browser, 5);
async function runWithPool(operation: (page: Page) => Promise<any>) {
const context = await contextPool.acquire();
try {
const page = await context.newPage();
const result = await operation(page);
await page.close();
return result;
} finally {
contextPool.release(context);
}
}
// Run multiple operations
const operations = Array(10).fill(0).map((_, i) =>
runWithPool(async (page) => {
await page.goto(`https://example.com/item/${i}`);
return await page.$("#title").textContent();
})
);
const results = await Promise.all(operations);
await contextPool.close();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