Manage Browser Contexts with Puppeteer
Learn how Puppeteer browser contexts isolate cookies and cache, how to create and manage pages in each session, and how to handle common context pitfalls.
A Puppeteer BrowserContext is a session boundary inside one browser instance. Create one with browser.createBrowserContext(), then create its pages with context.newPage(). Puppeteer documents that separate contexts do not share cookies or cache, so this is the standard pattern for keeping independent users or sessions apart. Puppeteer: createBrowserContext() and Puppeteer API reference.
1. Create an isolated browser context
Install Puppeteer in a Node.js project, then save and run this as an ES module:
npm install puppeteer
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.close();
}
createBrowserContext() returns a new context. Calling newPage() on that context places the page within it. Use this pair whenever the page should use a separate session’s cookies and cache.
2. Understand browser, context, and page scope
A browser instance has a default context, even if you never create another one. browser.newPage() creates a page in that default context. For an isolated session, explicitly create a context and call context.newPage().
| Operation | Scope | Use it for |
|---|---|---|
browser.newPage() |
The browser’s default context | A page in the default session |
context.newPage() |
The context on which it is called | A page in a particular session |
context.pages() |
One context | Managing pages for one session |
browser.pages() |
The whole browser | Coordinating pages across contexts |
browser.browserContexts() |
All contexts in the browser | Finding the default and created contexts |
browser.defaultBrowserContext() |
The default context | Working explicitly with the default session |
The default context cannot be closed. Puppeteer’s page-listing methods do not return non-visible pages such as background_page by default; consult the relevant target API when you need to handle those. See the official references for context.pages(), browser.pages(), browser.browserContexts(), and defaultBrowserContext().
3. Manage multiple independent sessions
This runnable example creates two contexts, visits a page in each, and lists pages per context and across the browser:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const contexts = [];
try {
for (const url of ['https://example.com', 'https://example.org']) {
const context = await browser.createBrowserContext();
contexts.push(context);
const page = await context.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
console.log(url, await page.title());
}
for (const [index, context] of contexts.entries()) {
console.log(`Context ${index + 1} pages:`, (await context.pages()).length);
}
console.log('Pages across browser:', (await browser.pages()).length);
} finally {
await browser.close();
}
The calls to context.pages() are session-scoped; browser.pages() sees pages throughout the browser. A page opened with window.open belongs to the same browser context as its opener, so treat it as part of that session. Puppeteer API reference.
4. Choose the right storage boundary
- Use the default context when a page can use the browser’s default session and you do not need to separate it from other pages there.
- Create one context per independent session when cookies and cache must not be shared across those sessions.
- Keep each session’s pages together by creating them through that session’s context and using
context.pages()for session-local management. - Use browser-wide enumeration when coordinating work across all contexts.
Puppeteer’s documentation describes isolated storage, including cookies and localStorage, for contexts and explicitly states that a newly created context does not share cookies or cache with other contexts. This describes storage behavior; do not treat the term “incognito” as a general security guarantee. Chrome’s non-default contexts are incognito according to the API reference, and the default context can also be incognito when Chrome is launched with --incognito. createBrowserContext() and API reference.
5. Browser and launch configuration
Context creation does not replace browser launch configuration. Launch Puppeteer as usual, then create contexts from the returned browser. Puppeteer guarantees operation with its bundled browser; using a custom executable path is at the caller’s risk. Keep the Puppeteer version and browser documentation you rely on aligned, since API documentation versions can change. Puppeteer LaunchOptions.
If you intentionally launch Chrome with --incognito, the default context behavior differs from the usual default-session setup. Check the launch options and the browser behavior you need before relying on that configuration.
6. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Pages unexpectedly share a session | A page was created with browser.newPage(), which uses the default context, or pages were created in the same context. |
Create a separate context for each independent session and use that context’s newPage(). |
A page is missing from context.pages() |
The page belongs to another context, or it is a non-visible page type omitted from the normal listing. | Check the owning context; use browser.pages() for visible pages browser-wide. For non-visible targets, consult Puppeteer’s target APIs. |
| Code attempts to close the default context | The default context is not closable. | Do not treat it like a created isolated context. Close the browser when the whole run should end. |
| Custom Chrome executable behaves differently or fails | Puppeteer only guarantees compatibility with its bundled browser. | Use the bundled browser or verify the custom executable and its compatibility yourself. |
| A popup appears in the wrong session | window.open popups belong to the opener’s context. |
Open the parent page in the intended context and account for its popup as a page in that same session. |
7. Performance, reliability, and cost
Contexts allow multiple sessions within a browser instance, but the cited Puppeteer documentation does not establish a performance advantage over using the default context. Choose based on the storage boundary and page-management scope you need. Keep the number of simultaneously open pages and contexts appropriate to your workload, and close the browser when the run is finished. Do not infer a memory or speed figure from context isolation alone.
For reliable automation, create pages through the intended context, enumerate at the matching scope, and use the browser version Puppeteer bundles unless you have validated a custom executable. Context isolation is useful for separating website storage; it is not a substitute for a broader security boundary.
8. Or skip the browser setup
If your task is to capture a URL as an image or PDF rather than manage an interactive Puppeteer session, ScreenshotNeo is a website screenshot API and MCP server for developers. The one-call GET API returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = await res.arrayBuffer();
- Cookie banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing; response headers identify the page verdict and billing status.
- An MCP server lets AI agents, including Claude and Cursor, take screenshots with its screenshot, page-info, and PDF tools.
- 1,000 screenshots per month are free with no card. Paid plans start at $5 for 3,000; every feature is on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
9. FAQ
Does each context get its own browser process?
The cited API describes contexts within one browser instance. It does not say that each context launches a separate process.
Will a popup inherit the opener’s context?
Yes. Puppeteer documents that a page opened with window.open belongs to the parent’s browser context.
Does context isolation guarantee a security boundary?
The documented behavior concerns isolated storage such as cookies and localStorage. It should not be interpreted as a general security guarantee.
Where can I verify the current API signatures?
Use the official Puppeteer API reference and the linked method pages, since documentation version labels can change.


