Puppeteer BrowserContext API: Isolated Browser Sessions
Create isolated Puppeteer sessions with BrowserContext, understand what state is shared, and clean up pages reliably.
To create an isolated browser session in Puppeteer, call browser.createBrowserContext(), then create pages for that session with context.newPage(). Cookies and local storage are not shared between contexts; closing a context closes its pages. Use a separate context for each task or user session that needs separate browser storage and independent cleanup.
1. Create and close an isolated context
Install Puppeteer if it is not already in your project:
npm install puppeteer
Save this as isolated-session.mjs and run it with node isolated-session.mjs:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const context = await browser.createBrowserContext();
try {
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log('Page title:', await page.title());
} finally {
// Closes pages belonging to this context.
await context.close();
// Closes the browser process and any remaining contexts.
await browser.close();
}
The browser management guide documents the create-context, create-page, and close flow. See the Puppeteer browser management guide and the createBrowserContext API reference.
2. What BrowserContext isolates
A BrowserContext groups pages under a browser-level user context. Contexts keep browser storage such as cookies and local storage separate. The API reference also says cookies and cache are not shared between contexts. In Chrome, non-default contexts are incognito contexts.
| Behavior | What to expect |
|---|---|
| Separate contexts | Cookies and local storage are not shared; the API reference also specifies separate cache. |
| Pages in one context | They belong to the same session context, so do not use separate pages in one context when you need separate session state. |
| Popup opened by a page | The popup belongs to the same context as its opener. |
| Context close | Closing a created context closes its associated pages. |
| Default context | The browser has a default context, and it cannot be closed. |
Context isolation is storage separation within a Browser. It does not mean Puppeteer starts a separate browser process for each context, and the documentation does not promise anonymity, fingerprinting resistance, or a complete security boundary.
3. Keep sessions separate in a multi-session script
Create one context per independent session. Create all pages for that session from its context, and close the context when the session is finished:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const sessions = [];
try {
for (const url of ['https://example.com', 'https://example.org']) {
const context = await browser.createBrowserContext();
sessions.push(context);
const page = await context.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
console.log(url, await page.title());
}
} finally {
// Close each independent session, including its pages.
await Promise.all(sessions.map((context) => context.close()));
await browser.close();
}
Keep a reference to every context you create so cleanup is explicit. browser.browserContexts() can list open contexts, but retaining the context reference makes it straightforward to close the session that owns the work.
4. Choose the right page creation method
browser.newPage() creates a page in the browser’s default context. To use an isolated context, call context.newPage() on that context. This distinction is easy to miss: creating a context and then calling browser.newPage() does not put the new page into the context you just created.
- Use the default context when the page should use the browser’s default session.
- Use a new context when cookies, local storage, cache, or teardown should be separated from other work.
- Use multiple pages in one context when they should belong to the same session.
- Use separate contexts when each page or task needs its own session state.
5. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| A page still sees another page’s session state | The pages were created in the same context, or a page was created with browser.newPage() and landed in the default context. |
Create a separate context for each isolated session and use that context’s newPage(). |
| Closing the default context fails | The default browser context cannot be closed. | Close the pages individually, or run work in a separately created context and close that context. |
| Pages remain open after a task | The context was not closed, or cleanup did not run after an error. | Put context cleanup in a finally block. Closing a created context closes its associated pages. |
| A popup appears to share the opener’s session | Popups belong to the context of the page that opened them. | For a separate session, start the work from a page in a separate context. |
| Code assumes incognito means anonymous | Incognito describes Chrome’s non-default context behavior; it is not a documented anonymity or fingerprinting guarantee. | Treat it as browser storage separation and assess other privacy or security requirements separately. |
6. Reliability, performance, and cost
Always close contexts after their work completes. A context is a useful unit of cleanup because it closes its pages together; closing the browser in a top-level finally block also handles failures that leave work unfinished. Reuse a context only when pages should share its session state.
Each context is an additional session within the browser instance, not a separate browser process. The cited Puppeteer documentation does not provide a universal performance or memory cost per context, so measure concurrency and resource use for your own pages and workload. Avoid creating contexts without tracking their lifecycle.
7. Or skip the browser setup
If the task is to capture a website screenshot rather than automate a browser session, ScreenshotNeo provides a screenshot API and MCP server. A single GET request returns an image or PDF; its options include custom headers and cookies when a capture needs session-related request data. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
- Cookie and consent banners are accepted before capture, and 60+ known consent platforms, newsletter popups, and chat widgets are removed; each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses identify the page verdict and billing status in headers.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is on every plan.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
8. FAQ
Does each Puppeteer BrowserContext have its own browser process?
No. A context is a session within a browser instance; Puppeteer’s cited API does not describe it as a separate browser process.
Can I close the default browser context?
No. The default context cannot be closed. Close its pages or use and close a separately created context.
Does incognito guarantee anonymity?
No such guarantee appears in the cited Puppeteer documentation. The documented point is context storage separation and Chrome’s incognito terminology for non-default contexts.


