Run isolated parallel sessions in Puppeteer with BrowserContext instead of multiple browsers
Launch one Chromium instance and create a BrowserContext per session to isolate cookies, storage and permissions for parallel scraping or testing without paying launch overhead per user.
15 Jun 2026, 19:01 UTC

Problem: one browser launch per session kills throughput
Launching a full Chromium process for every logical user or test case adds seconds of startup and a lot of memory. BrowserContext gives you a separate cookie jar, storage and permissions inside one browser instance. The useful takeaway is to launch once, create a context per session, and close contexts when done.
Desired outcome
Multiple independent browsing sessions share a single browser process. Each session has its own cookies, localStorage, sessionStorage, IndexedDB and permissions. Closing one context does not affect others, and memory stays bounded when contexts are closed.
Prerequisites
A Node.js runtime and Puppeteer installed in the project. A launched Browser instance via browserType.launch. The target site must be reachable and any authentication credentials prepared outside code.
Pin Puppeteer in package.json. BrowserContext API is stable in modern Puppeteer but parameter names and defaults can shift between major versions. Verify the options you use against the version you pin.
Setup and creation
Run from a project directory with network access and write permission for node_modules.
// launch once
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({ headless: true });Create a context with the profile attributes you need for that session. Viewport, userAgent and locale are common isolation knobs.
const contextA = await browser.newContext({
viewport: { width: 1280, height: 800 },
userAgent: 'PLACEHOLDER_USER_AGENT',
locale: 'en-US'
});
const pageA = await contextA.newPage();Repeat newContext for each logical user or test case. Do not reuse a page across contexts.
const contextB = await browser.newContext({
viewport: { width: 1280, height: 800 },
userAgent: 'PLACEHOLDER_USER_AGENT_2',
locale: 'en-GB'
});
const pageB = await contextB.newPage();Perform navigation and actions inside the page belonging to that context.
await pageA.goto('https://example.com/login', { waitUntil: 'domcontentloaded' });Expected checks
Confirm isolation by inspecting context state, not by visual inspection.
- Log context identifiers to confirm pages belong to different contexts. Use context._contextId and page.target()._targetId for correlation.
- Set a cookie in one context and verify it is absent in another via context.cookies().
- Write to localStorage in pageA and read in pageB. The values should be independent.
- Close a context with context.close() and verify its pages are disposed while other contexts remain usable.
Memory usage stays bounded when contexts are closed. Contexts share the same browser process and GPU resources; too many concurrent contexts can exhaust memory or file descriptors.
Recovery options
Context operations can fail under load or when a target is closed.
- Catch TargetCloseError and recreate the context and page for that session.
- Retry navigation with exponential backoff on network failures before marking the session failed.
- If context creation fails due to resource limits, fall back to browser.newPage() for a single shared session as a degraded path.
Headless mode may be detectable by sites. Isolation does not bypass bot detection or site policies.
Limitations
Contexts share the browser process, so a crash in the browser affects all contexts. Isolation is logical, not process-level. Parameter names and defaults can change across major Puppeteer releases, so keep the version pinned and re-verify options after upgrades.
Practical verification: run two contexts in parallel to the same URL, set distinct cookies in each, and assert independent cookie lists and no cross-contamination of session storage.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.