Skip to content

Sessions and lifecycle

Every browser-touching tool accepts an optional session argument (default "default"). Each session id is a fully isolated browser context: its own cookie jar and storage, its own ref registry, its own console and network buffers. That isolation is the whole concurrency model.

  • Many agents, one server. Give each agent its own session id and they cannot stomp each other. There is no server-global “active session”.
  • One agent, many sessions. Drive several windows or flows in parallel by id.
  • Multi-user. Two sessions logged in as different users of the same app do not bleed, because they are different browser contexts with different cookie jars.

Omitting session resolves to a lazily created "default" session, so simple single-session callers need to know none of this.

  • open_session({ session, mode?, profile?, device?, viewport?, har?, hars? }) eagerly creates an id. Re-opening a live id is an error.
  • close_session({ session }) tears one down.
  • close_sessions({ prefix?, all?, idleMs? }) is the bulk reap primitive for multi-agent cleanup. Selectors AND together, and at least one is required so you cannot accidentally close nothing or everything.
  • list_sessions() returns [{ id, mode, url, pages, openedAt }].
ModeIsolationPersistenceUse it for
persistentown profile dir under the workspacecookies and storage survive across runslogged-in flows you want to resume
incognitoown ephemeral context and browsernothing persisted, all state discarded on closeone-off driving with no profile trace
attachedthe externally launched Chrome (not owned)the user’s real profileBYOB, attach to a Chrome you already control

Different ids are always isolated contexts regardless of mode. With persistent, the profile argument lets two ids share a profile dir or pin a stable name.

In persistent and incognito modes, browxai spawns Chromium as a child process of the MCP server. When the MCP client restarts the server, for a config edit, a code reload, or any other reason, that Chrome child dies with it and any live page state is gone. A stored ref that pointed at a now-dead page resolves to about:blank or a fresh document.

If you need page state to survive server restarts, run Chrome yourself and attach to it:

Terminal window
google-chrome \
--remote-debugging-port=9222 \
--user-data-dir="$BROWX_WORKSPACE/byob-profile"
Terminal window
BROWX_ATTACH_CDP=http://127.0.0.1:9222

An attached Chrome is not owned by browxai: it is never closed on shutdown and it survives browxai restarts cleanly.

  • open_session({ device }) takes any Playwright device-preset name (for example "iPhone 14", "Pixel 7", "Desktop Chrome") and applies its viewport, scale factor, touch, and user agent.
  • open_session({ viewport: { width, height } }) overrides a preset’s size while keeping its mobile, touch, and UA traits.
  • set_viewport({ session, width, height }) resizes mid-session for responsive testing and returns an ActionResult, since a re-layout often triggers responsive re-render or lazy loading. Only the size changes live; full device traits are fixed at session creation.

Beyond isolation, each session carries policies for browser events that would otherwise deadlock a headless context or silently change app state: dialogs (alert / confirm / prompt), permissions (camera, geolocation, and more), the Notification constructor, and File System Access pickers. Each defaults to a raise posture, meaning the event is handled so the page does not hang, but the next result reports it rather than letting it pass silently. The tool reference documents every policy mode.

Made by Kalebtec · GitHub · MIT licensed