Puppeteer BrowserContext: Isolated Browser Sessions Explained
Learn what Puppeteer BrowserContext isolates, how to create and close contexts, and how pages, popups, cookies, and the default context behave.
BrowserContext is Puppeteer’s unit for separating browser storage between automation tasks. Create one with browser.createBrowserContext(), open pages with context.newPage(), and close the context when the task is finished. Puppeteer documents context isolation for cookies, localStorage, and cache. A context is a storage boundary within a browser instance; the documentation does not describe it as a separate browser process or a complete security boundary.
This guide uses the current Puppeteer API. In Puppeteer 22, createIncognitoBrowserContext() was renamed to createBrowserContext(). See the Puppeteer changelog for the version history.
1. Create an isolated context
Install Puppeteer in a Node.js project, then launch a browser, create a context, and make a page in it:
npm install puppeteer
// save as context-example.js
const puppeteer = require('puppeteer');
async function main() {
const browser = await puppeteer.launch({ headless: true });
let context;
try {
context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log('Page title:', await page.title());
console.log('Context pages:', context.pages().length);
} finally {
// Closing this context closes its pages. Close the browser as well
// to release the browser process started by this script.
if (context) await context.close();
await browser.close();
}
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
Run it with node context-example.js. The example closes the context even if navigation or inspection fails. Closing the browser also closes its contexts, but closing each task context explicitly makes its lifecycle clear and supports reuse of a browser for multiple tasks.
Read the current createBrowserContext API and browser management guide for the full API details.
2. What a BrowserContext isolates
A context represents an individual user context. Puppeteer documents separate cookies and cache between contexts, and the BrowserContext class reference also identifies localStorage as isolated storage. This is useful when tests need different login state or browser data without sharing those values through one context.
- Cookies: cookies set in one context are not shared with another.
- localStorage: context storage is isolated, so values written by one context are not the other context’s localStorage state.
- Cache: contexts do not share cache according to the context creation API.
“Isolated session” is a useful shorthand for this storage separation. It does not mean each context is a separate operating-system process, nor should it be treated as a complete security boundary for hostile tenants. The cited API documentation establishes context storage and lifecycle behavior, not process-level isolation.
3. Default context versus a new context
A launched browser has at least one context: its default context. browser.newPage() creates a page in that default context. browser.createBrowserContext() creates an additional context, and context.newPage() creates a page in that selected context.
| Approach | Page creation | Storage separation | Cleanup |
|---|---|---|---|
| Default context | await browser.newPage() |
Pages share the default context’s browser storage. | The default context cannot be closed. Close individual pages or close the browser. |
| Explicit context | const context = await browser.createBrowserContext(); await context.newPage() |
Storage is separated from other contexts. | await context.close() closes all pages in that context. |
Use the default context when a task does not need its state separated from other work in the browser. Use an explicit context when each task needs separate cookies or cache, or when all of a task’s pages should be closed together. Puppeteer’s browser management guide documents both page-creation patterns.
In Chrome, non-default contexts are incognito. The default context can also be incognito if Chrome was launched with --incognito, so “default” and “non-incognito” are not always equivalent.
4. Pages, popups, and context membership
A context can have multiple pages. A popup opened by window.open belongs to the context of the page that opened it; it does not automatically get a new context. Closing the owning non-default context closes its associated pages.
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://example.com');
// A page opened by window.open remains in this page's context.
const popupPromise = new Promise(resolve => page.once('popup', resolve));
await page.evaluate(() => window.open('https://example.org', '_blank'));
const popup = await popupPromise;
console.log('Parent context pages:', context.pages().length);
console.log('Popup uses same context:', popup.browserContext() === context);
await context.close(); // closes both page and popup
For applications that open popups as part of login, payment, or OAuth flows, keep the context open until the popup work is complete. The Page.browserContext API exposes the context associated with a page.
5. Manage cookies in the task context
Use the context’s cookie methods when the task operates in a non-default context. Puppeteer documents context-level methods for reading, setting, and deleting cookies. The cookie guide also explains the corresponding browser-level methods, which operate on the default context.
const context = await browser.createBrowserContext();
try {
const page = await context.newPage();
await context.setCookie({
name: 'session_hint',
value: 'example',
domain: 'example.com',
path: '/',
secure: true,
httpOnly: true,
sameSite: 'Lax',
});
await page.goto('https://example.com');
const cookies = await context.cookies();
console.log(cookies.map(cookie => cookie.name));
await context.deleteCookie({
name: 'session_hint',
domain: 'example.com',
path: '/',
});
} finally {
await context.close();
}
Cookie requirements vary by target site and browser behavior. Set a domain and path appropriate to the target, and use secure cookie attributes when required. For current method signatures and cookie behavior, consult Puppeteer’s cookie guide and BrowserContext reference. Page-level cookie methods are deprecated in favor of Browser or BrowserContext APIs in the current Page reference.
6. Inspect and clean up contexts safely
browser.browserContexts() returns the currently open contexts. A newly created browser has one default context in this list. Do not assume every listed context can be closed: Puppeteer does not allow closing the default context.
const contexts = browser.browserContexts();
console.log('Open contexts:', contexts.length);
const taskContext = await browser.createBrowserContext();
try {
const page = await taskContext.newPage();
await page.goto('https://example.com');
} finally {
await taskContext.close();
}
Keep a reference to contexts your code creates. This makes ownership explicit and avoids trying to close the default context during generic cleanup. The browserContexts API and BrowserContext.close API describe inspection and closure behavior.
7. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
browser.createIncognitoBrowserContext is not a function |
The code uses the old method name, removed in Puppeteer 22. | Use browser.createBrowserContext(). Check the changelog when maintaining examples across versions. |
| Cookies appear missing in a page | The cookie was set in another context, or its domain/path does not match the site. | Set and read cookies on the same context used for the page, and verify the cookie’s domain, path, and attributes. |
| Closing a context closes more pages than expected | Those pages belong to the context being closed; context closure closes associated pages. | Create a separate context for work that needs an independent lifecycle, or keep the shared context open until all its pages are done. |
| Attempt to close a context fails | The context is the browser’s default context, which cannot be closed. | Close pages individually or close the browser. Close only additional contexts your code created. |
| A popup shares state with its opener | Popups opened with window.open belong to the parent page’s context. |
That behavior is expected. If the workflow needs separate storage, create a separate context and open a page there instead of using a popup. |
| Two tasks see the same authenticated state | Both pages were created in the same context, often through browser.newPage(). |
Create one explicit context per independently stateful task and use context.newPage(). |
8. Performance, reliability, and cost considerations
The cited Puppeteer documentation defines storage and lifecycle behavior but does not provide benchmark data for contexts. Avoid assuming a numeric speed or memory cost from the API contract. In practice, each context can contain multiple pages, and closing a task context also closes its pages; choose context boundaries around independent state and cleanup needs.
- Reliability: use
try/finallyso task contexts close after navigation errors, assertion failures, or timeouts. - Browser reuse: multiple task contexts can be created within a browser instance. Ensure each task closes the context it owns.
- State correctness: create separate contexts for tests that must not inherit another task’s cookies or cache.
- Cost: Puppeteer is browser automation software; the cited sources do not specify a per-context charge. Infrastructure cost depends on where and how you run the browser, which these sources do not quantify.
9. Or skip the browser setup
If the task is simply to capture a page as an image or PDF, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It does not expose Puppeteer BrowserContext; it provides a managed screenshot request when you do not need to operate a browser session yourself.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
Python:
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)
Node.js:
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 import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
See the ScreenshotNeo API documentation for request options. Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and response headers report the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.
10. FAQ
Does each BrowserContext launch a separate browser?
No. A BrowserContext is a context inside the browser instance. Puppeteer’s cited documentation describes storage separation, not a separate process for each context.
Can a BrowserContext contain more than one page?
Yes. Create additional pages with context.newPage(); popups opened by a page belong to that page’s context.
Can I close the default context?
No. Close pages individually or close the browser. Close non-default contexts that your automation created.
Which method should new code use?
Use browser.createBrowserContext(). The former createIncognitoBrowserContext() name was changed in Puppeteer 22.0.0.


