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.

Browser automation stays reliable when every step uses the same deliberate session boundary. A session ties your client to a browser or driver; its cookies, storage, open pages and authentication state are what make a later command see the same application that an earlier command changed. Keep that state in the right Playwright BrowserContext, Selenium driver session or durable remote browser, set explicit timeouts, observe events, and clean up deterministically. Reconnect a live remote browser when preserving state and avoiding a cold start matters; relaunch when the browser is unhealthy or isolation is required.

What a browser session actually contains

In Selenium, creating a driver object creates a WebDriver session managed by the driver server. The session ends when you call quit(), which deletes it; close() only closes the current window and can leave the session alive. Selenium’s driver documentation describes this lifecycle at selenium.dev/documentation/webdriver/drivers/.

Playwright separates concerns into a browser process, one or more isolated BrowserContext objects, and pages (tabs) inside each context. Its agent CLI also gives commands a named session. A context is usually the useful state boundary: contexts have their own cookies, cache, local storage, IndexedDB, pages and navigation history. A new context does not share cookies or cache with another one, as documented at playwright.dev/docs/api/class-browser.

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.
Layer What it controls Use it for
Browser process Chromium, Firefox or WebKit process and its resources Sharing a process while keeping users isolated in separate contexts
Playwright BrowserContext Cookies, storage, pages, permissions and browser-level settings One user, tenant, role or test fixture
Selenium driver session Server-managed browser session addressed by a session ID Sequential WebDriver commands against one browser
Page or window A tab, URL and document Parallel tabs inside one authenticated context
Remote durable browser Provider-managed process that can survive client disconnects Long workflows, user handoffs and expensive cold starts

State scope determines whether a later step can see an earlier login, upload, navigation or consent decision. Do not assume that a new page, driver or context inherits state: choose the boundary explicitly.

How Playwright retains state between steps

One in-memory session

Commands sent to the same Playwright CLI session retain cookies and storage in memory. A persistent mode writes a browser profile to disk, allowing a later process to reopen that profile. This distinction is covered in the Playwright session documentation. In test code, keep the browser open, create one context for the workflow, and create pages within it:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com/login');
// ...login and subsequent steps use the same context...
await context.close();
await browser.close();

Close contexts before the browser. That gives Playwright time to flush traces, HAR files and videos before the underlying process disappears.

Save authentication with storageState

After a successful login, serialize the context’s reusable state and load it into a fresh context. The API-testing guide at playwright.dev/docs/api-testing and authentication guide at github.com/microsoft/playwright/blob/main/docs/src/auth.md document this pattern:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { chromium } from 'playwright';

const browser = await chromium.launch();
const loginContext = await browser.newContext();
const loginPage = await loginContext.newPage();
await loginPage.goto('https://app.example.com/login');
await loginPage.fill('#email', process.env.TEST_EMAIL);
await loginPage.fill('#password', process.env.TEST_PASSWORD);
await loginPage.click('button[type=submit]');
await loginPage.waitForURL('**/dashboard');
await loginContext.storageState({ path: 'playwright/.auth/user.json' });
await loginContext.close();

const authenticated = await browser.newContext({
  storageState: 'playwright/.auth/user.json'
});
const page = await authenticated.newPage();
await page.goto('https://app.example.com/dashboard');
await authenticated.close();
await browser.close();

State files can contain authentication cookies, headers, local storage, IndexedDB data or passkey-related credentials. Playwright warns that such files may enable impersonation; keep them outside source control, restrict file permissions and rotate them like credentials. Session storage is domain-specific and is not covered automatically by the same mechanism, so add your own save and restore code when the application depends on it.

Share API and browser cookies safely

An APIRequestContext associated with a BrowserContext shares that context’s cookies. Responses that set cookies update the context, so an API login can prepare a browser page (or a browser action can update subsequent API calls) without copying headers manually. Keep the request context tied to the intended user context; do not use one mutable context for unrelated accounts.

Resuming authenticated Selenium workflows

Selenium’s session ID and driver keep the browser state while the driver remains alive. A basic workflow sets timeouts, logs in once and performs later actions through the same driver:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=options)
driver.set_script_timeout(30)
driver.set_page_load_timeout(300)
driver.implicitly_wait(0)
try:
    driver.get("https://app.example.com/login")
    driver.find_element(By.ID, "email").send_keys("[email protected]")
    driver.find_element(By.ID, "password").send_keys("secret")
    driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
    WebDriverWait(driver, 20).until(
        EC.url_contains("/dashboard")
    )
    # Every following command addresses the same authenticated session.
    driver.get("https://app.example.com/reports")
finally:
    driver.quit()

Selenium documents defaults of 30,000 ms for script execution, 300,000 ms for page loads and 0 for implicit waiting in its driver options documentation. Set them explicitly rather than relying on a grid, language binding or browser-specific default. Prefer explicit waits for a known condition; mixing long implicit waits with explicit waits makes failure timing difficult to predict.

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

If a process dies, a new driver cannot magically recover the old server session unless your grid or provider exposes a supported attach mechanism. Persisting cookies and other application state can help, but it is not equivalent to preserving every tab, JavaScript object and in-memory page state.

Isolation: one context per identity

Use separate Playwright contexts (or separate Selenium sessions) for different users, tenants, permissions and test cases. Sharing a context creates hidden coupling: one test can change a cookie, local-storage token, selected organization or open tab that another test then observes. Context isolation also makes parallel execution safer. Reuse a context only when the workflow intentionally represents one continuous user.

  • Create the context with the minimum permissions and only the cookies or storage it needs.
  • Give each parallel worker its own state file or login fixture.
  • Close pages and contexts in a finally block so failures do not leak sessions.
  • Redact session IDs, cookies and authorization headers from logs.

Use WebDriver BiDi for event-driven recovery

Traditional WebDriver is mostly sequential request/response: send a command, wait, inspect the result. WebDriver BiDi adds a WebSocket channel to the W3C model. Selenium describes BiDi support at selenium.dev/documentation/webdriver/bidi/; scripts can subscribe to network requests, console messages, JavaScript exceptions and other browser events.

Events let a runner react to facts as they happen. For example, record a failed API response with its request ID, fail fast on an uncaught page exception, or wait for a specific network event rather than sleeping for an arbitrary number of seconds. Keep event handlers lightweight and correlate them with the test or workflow ID. BiDi improves observability and recovery logic; it does not remove the need for explicit waits or a correctly scoped session.

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

When to disconnect and reconnect a remote browser

Reconnect when the browser is healthy

Disconnecting the client while leaving a remote browser alive is useful when a request handler, worker or WebSocket connection must end but the user’s state should remain. Cloudflare’s Browser Run documentation shows browser.disconnect() followed by reconnecting for reusable sessions at developers.cloudflare.com/browser-run/features/reuse-sessions/. Reconnection can avoid a cold launch and preserve cookies, pages and navigation state.

  • Use a stable session identifier and authenticate every reconnect.
  • Apply an idle timeout and maximum lifetime so abandoned browsers are reclaimed.
  • Serialize competing commands; two workers writing the same page at once are not a reliable workflow.
  • Store only an opaque handle in a queue or database, never raw cookies or passwords.

Relaunch when the process is unhealthy

Relaunch after a browser crash, lost transport, corrupted profile, unrecoverable page, expired provider lease or a security-boundary change. A reconnect cannot repair a dead process or safely convert one user’s context into another’s. Cloudflare also documents Durable Objects for long-running browsers that must retain state or remain associated with a particular user or route; use that architecture when ownership and routing need to be durable rather than incidental.

Timeouts, cleanup and failure policy

A robust session has a written policy for each operation:

Operation Policy to define
Navigation Maximum page-load time and whether redirects or network-idle are required
Element action Explicit visibility, enabled-state and attachment conditions
Script execution Maximum runtime and cancellation behavior
Remote lease Idle timeout, absolute lifetime and reconnect window
Shutdown Close pages, then context, then browser; collect diagnostics before deletion

On timeout, capture the current URL, page screenshot, console errors, recent network events and a session correlation ID. Retry only idempotent operations, or make writes idempotent with an application key. Replaying a purchase, message or mutation after an uncertain timeout can duplicate the action.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common session failures and fixes

“Not authenticated” after a new context

Cause: contexts do not share cookies or cache. Fix: load a verified storageState, perform a controlled login in that context, or copy only the required cookie through the framework’s supported API. Check the cookie domain, path, secure flag and expiry.

State disappears after restarting the process

Cause: the profile was in memory. Fix: use Playwright persistent mode or save storageState; for Selenium, persist supported application cookies and relaunch with a clean, known profile. Do not treat a cookie export as a complete copy of sessionStorage or in-memory page state.

“Session ID is null” or disconnected driver

Cause: the driver was quit, the browser crashed, or a grid lease expired. Fix: stop issuing commands, collect logs if available, create a new driver and restore deliberately saved state. Do not call close() when you mean to end the whole Selenium session.

Steps hang or fail inconsistently

Cause: implicit waits, arbitrary sleeps, navigation races or an unobserved JavaScript error. Fix: set explicit timeouts, wait for a semantic condition, subscribe to BiDi or console events where available, and include the failing URL and selector in diagnostics.

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

Two jobs interfere with one browser

Cause: shared context or concurrent commands. Fix: allocate one context per identity and serialize commands within a context; use a queue or lock around reconnectable remote sessions.

Performance and cost decisions

Keeping a browser and context warm reduces launch overhead, but warm state increases memory use and the risk of stale pages or leaked credentials. A practical policy is to reuse a healthy session for a bounded workflow, periodically recycle it, and measure launch time, command latency, memory, timeout rate and reconnect success. In CI, isolation and reproducibility usually outweigh a small launch saving. In an interactive product, a durable remote browser may justify the operational complexity when users expect their tabs and login to remain live.

Or skip the browser setup

If your goal is a clean image or PDF of a page rather than an interactive workflow, ScreenshotNeo provides a single screenshot API and an MCP server for AI agents. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed as clean shots, and response headers identify the page verdict and billing result.

Use the same URL with any supported options; the API base is https://api.screenshotneo.com/v1/shot. Full parameter documentation is at screenshotneo.com/docs/.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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}`);

ScreenshotNeo also supports full-page lazy-image capture, CSS-selector element shots, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, clicks, selector or network-idle waits, ad and tracker blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, an OpenAPI specification and familiar parameter names for easier migration. Its MCP tools are take_screenshot, get_page_info and capture_pdf.

The Free plan includes 1,000 shots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Sign up for the free plan.

Frequently Asked Questions

Should I store a complete browser profile in source control?

No. Profiles and serialized state can contain credentials or impersonation-capable tokens. Store them in protected secret storage or generate them in a controlled setup step.

Can WebDriver BiDi replace Playwright or Selenium waits?

No. BiDi supplies event streams; you still need explicit conditions, timeouts and cleanup for commands that act on the page.

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.

Is reconnecting always cheaper than launching a browser?

No. Reconnection avoids a cold start only when the remote browser is healthy and the provider keeps it alive. Leases, idle limits, memory use and recovery complexity can make a fresh isolated session preferable.

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.