Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use one fresh BrowserContext for each independent test or user. A context is an isolated, incognito-like session inside a single browser process: its cookies, local storage and session storage are separate from every other context. Create the context, open one or more pages in it, perform the work, then close the context before closing the browser. For two users in one workflow, create two contexts in the same browser.

What a browser context isolates

A browser context is a session container, not another operating-system browser process. Several contexts can run concurrently inside one browser instance while keeping browser state separate. Playwright describes contexts as equivalent to incognito-like profiles and as fast, inexpensive units for test isolation.

  • Cookies: login cookies and other cookie data belong to the context that received them.
  • Web storage: local storage and session storage are not shared with another context.
  • Pages: a page is a tab-like document inside a context. Pages in the same context share that context’s state.
  • Permissions and routing: context-level grants and request routes apply to matching pages in that context.
  • Disk writes: a non-persistent context does not write browsing data to disk.

Starting every scenario with a new context prevents state leakage. Cleaning up a reused page or deleting a few cookies is less reliable: visited-link state and other browser data can be difficult to reset completely. A fresh context also makes a failure easier to reproduce because the starting conditions are known.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Playwright lifecycle: launch, isolate, use, close

The normal Playwright API flow is deliberately short: launch a browser, call browser.newContext(), create a page with context.newPage(), navigate and interact, then close the context and browser.

Minimal runnable example

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());

  await context.close();
  await browser.close();
})();

Install Playwright in the project that runs this script, and install the browser binaries required by your chosen Playwright version. Keep the context.close() call even when the script currently opens only one page. Closing a context explicitly lets Playwright flush artifacts such as videos and HAR files before the browser is closed.

Make cleanup exception-safe

In production and test runners, put cleanup in a finally block. This prevents a failed assertion, navigation timeout or thrown application error from leaving contexts open.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  let context;
  try {
    context = await browser.newContext();
    const page = await context.newPage();
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
    // Test or automation steps go here.
  } finally {
    if (context) await context.close();
    await browser.close();
  }
})();

Run two independent users in one browser

Create one context per identity. Each context can have multiple pages of its own, but the admin and user contexts do not share cookies or storage. This is the right shape for chat, approval, permission and other workflows in which two accounts must interact without accidentally becoming the same user.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const adminContext = await browser.newContext();
  const userContext = await browser.newContext();

  try {
    const adminPage = await adminContext.newPage();
    const userPage = await userContext.newPage();

    await adminPage.goto('https://app.example.test/admin');
    await userPage.goto('https://app.example.test/account');

    // Log in each page with its own credentials, then exercise the workflow.
  } finally {
    await adminContext.close();
    await userContext.close();
    await browser.close();
  }
})();

Do not create both pages from one context when you need two accounts; those pages intentionally share that context’s cookies and storage. Conversely, if one user needs several tabs, create several pages from the same context.

Configure state at the context boundary

Context creation is where you establish the conditions that should apply to every page in that session. The BrowserContext API provides methods for adding and clearing cookies, granting permissions, routing network requests, listing or creating pages, capturing storage state and closing the context. A route installed on a context therefore covers matching requests from all pages in it.

Preload or save authentication with storage state

storageState() can snapshot cookies, local storage, IndexedDB, origin private file-system data and, when the relevant option is enabled, virtual WebAuthn credentials. Save the state after a controlled login, then pass that state when creating a new context. You still get a new isolated context per test; only the selected starting state is reused.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();

  const signedIn = await browser.newContext();
  const loginPage = await signedIn.newPage();
  await loginPage.goto('https://app.example.test/login');
  // Fill the login form and wait for the authenticated landing page.
  await loginPage.getByLabel('Email').fill(process.env.TEST_EMAIL);
  await loginPage.getByLabel('Password').fill(process.env.TEST_PASSWORD);
  await loginPage.getByRole('button', { name: 'Sign in' }).click();
  await loginPage.waitForURL('**/dashboard');
  await signedIn.storageState({ path: 'state.json' });
  await signedIn.close();

  const testContext = await browser.newContext({ storageState: 'state.json' });
  const page = await testContext.newPage();
  await page.goto('https://app.example.test/dashboard');
  // This context starts signed in but remains isolated from every other one.

  await testContext.close();
  await browser.close();
})();

Treat the state file as a credential: keep it out of source control, protect it in CI, and regenerate it when the account, cookies or application session policy changes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Other useful context-level controls

  • Seed or remove cookies before opening a page.
  • Grant only the permissions a scenario requires.
  • Route, fulfill or block requests for deterministic tests and controlled network behavior.
  • Set viewport, user agent, timezone, locale and other context options once instead of repeating them per page.
  • Use context page-management methods when a workflow opens popups or several tabs.

Persistent versus non-persistent sessions

browser.newContext() creates a non-persistent context. It is the usual choice for tests and short-lived automation because it does not write browsing data to disk and disappears when closed. That gives each scenario a clean starting point.

Persistence is a different requirement from isolation. If you must retain a profile between runs, use the persistence mechanism documented by the framework version you have installed, with a distinct profile directory per independent identity. Never point two concurrent identities at the same profile directory. Option names and supported behavior can vary by browser engine and framework version, so verify them in that version’s API reference rather than assuming Chromium, Firefox and WebKit behave identically.

BrowserContext versus Page

Object What it represents State boundary Typical use
Browser One launched browser instance Contains multiple contexts Share process resources while running isolated sessions
BrowserContext One independent browser session Own cookies, local storage, session storage, permissions and context routes One test, tenant or user role
Page One tab-like document Shares its parent context’s state Navigate, locate elements and interact with a document

The practical rule is simple: choose a context when you need a new identity or clean state; choose a page when you need another tab for the same identity.

Playwright and Puppeteer: same idea, different APIs

Puppeteer also exposes BrowserContext. Its documentation describes isolated storage such as cookies and local storage, and states that in Chrome all non-default contexts are incognito. The concept maps closely to Playwright’s context, but the method names, browser-engine coverage, persistence behavior and cleanup details belong to the selected framework and version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Question Playwright Puppeteer
How do you obtain a context? browser.newContext() Use Puppeteer’s BrowserContext creation API for the installed version
What is isolated? Cookies, local storage, session storage and other context state Cookies, local storage and other context storage
How should you compare implementations? Check context creation, storage-state support, routing, permissions and close behavior Check the same axes against the Puppeteer version and browser engine you deploy

Do not copy a Playwright option name into Puppeteer (or vice versa) without checking that framework’s reference. The shared concept is isolation; the lifecycle and feature surface are not interchangeable.

Performance, reliability and cost choices

Keep one browser, create many contexts

Contexts are intended to be fast and inexpensive compared with launching a separate browser for every scenario. Reusing one browser process while creating a fresh context per test usually reduces startup overhead while preserving session isolation. The browser process is still a shared resource, so cap concurrency according to available CPU, memory and the workload’s page count.

Close in the right order

Close pages indirectly by closing their context, close every context explicitly, and close the browser last. This ordering is especially important when recording videos, HAR files or other artifacts that need flushing.

Make failures reproducible

  • Create a fresh context for each independent test rather than clearing a reused page.
  • Record which context represents each role in multi-user tests.
  • Use a saved storage state only when the test deliberately requires a signed-in starting point.
  • Wait for a meaningful application condition, such as a URL or selector, instead of relying only on arbitrary sleeps.
  • Dispose of contexts after both successful and failed scenarios.

Understand the cost model

Context creation itself is not a separate browser installation or operating-system process. Your practical costs come from the browser process, pages, network traffic, test duration and any external infrastructure or service you use. Measure concurrency and memory in the environment that will run the suite; documentation establishes isolation and lifecycle behavior, not a universal capacity number.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common problems and fixes

“The second user is still logged in as the first user”

Cause: both pages were created from the same context, or a shared storage-state file was supplied unintentionally. Fix: create a separate context for each identity and verify each login with an account-specific assertion.

“Cookies changed another test”

Cause: a context was reused across scenarios. Fix: create a new context per independent test and close the old one in teardown.

“The browser closes before my video or HAR is complete”

Cause: the browser was closed while contexts were still open. Fix: close each context first, then close the browser.

“A saved login no longer works”

Cause: the state file contains expired cookies, changed storage, or an account whose session was revoked. Fix: regenerate the state through the login flow, protect the file, and ensure the new context points to the intended path.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“A request route affects pages I did not intend to mock”

Cause: routing was installed on the context, so every matching page request was intercepted. Fix: install the route on the narrowest appropriate context, scope its URL pattern, and remove it when the scenario ends.

“The test passes locally but fails in CI”

Cause: different browser binaries, framework versions, timing, environment variables or persisted state. Fix: pin the framework and browser versions, start with a fresh context, make waits condition-based, and log the context role and target URL before each major action.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean image or PDF rather than interactive browser testing, ScreenshotNeo provides a single HTTP request. Its cleanup steps accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.

See the ScreenshotNeo API documentation for all options. The same endpoint supports PNG, JPEG, WebP and PDF output, and can also handle full-page captures with lazy images, CSS-selector element captures, dark mode, device presets, custom viewports, retina scale, PDF paper and page-range settings, custom CSS or JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL-based caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data and an OpenAPI specification. Parameter names used by other screenshot APIs are accepted to ease migration.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. Every feature is on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots, followed by $15 for 15,000, $39 for 60,000, $99 for 250,000 and $249 for 1,000,000. Yearly billing gives two months free. Create a free ScreenshotNeo account to begin.

FAQ

Can two contexts use the same logged-in account?

Yes. They remain technically isolated even if you deliberately seed both with the same credentials; isolation separates state, not account ownership.

Does closing a page destroy the context?

No. A context can contain multiple pages. Close the context when the entire session is finished.

Should I use a new context for every assertion?

No. Use one context for one coherent scenario or identity. Create a new one when the next scenario must not inherit state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can a context protect secrets from the browser process?

No. Contexts separate session data; they are not a security boundary against code or pages that already run inside the same browser process. Apply normal credential, network and test-environment controls.

Frequently Asked Questions

Can two contexts use the same logged-in account?

Yes. They remain technically isolated even if you deliberately seed both with the same credentials; isolation separates state, not account ownership.

Does closing a page destroy the context?

No. A context can contain multiple pages. Close the context when the entire session is finished.

Should I use a new context for every assertion?

No. Use one context for one coherent scenario or identity. Create a new one when the next scenario must not inherit state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can a context protect secrets from the browser process?

No. Contexts separate session data; they are not a security boundary against code or pages that already run inside the same browser process. Apply normal credential, network and test-environment controls.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.