How ego-browser Handles CDP Session Management and Automatic Re-attachment After Session Loss

ego-browser maintains a resilient Chrome DevTools Protocol (CDP) layer by caching sessions for 2-second TTLs and automatically re-attaching to targets when sessions are lost using regex-based error detection and transparent retry logic.

The ego-browser package from the citrolabs/ego-lite repository provides a robust abstraction over Chrome's CDP that eliminates manual session handling. Unlike raw CDP clients that fail when tabs navigate or crash, ego-browser implements an intelligent recovery mechanism that transparently manages session lifecycles, allowing automation scripts to run without interruption.

Session Lifecycle and Caching Strategy

ego-browser optimizes CDP connectivity by maintaining a single session per active tab with a short-lived cache to prevent redundant attachment operations.

Session TTL Configuration

In package/ego-browser/src/browser-runtime.ts, the session freshness window is defined by the constant:

SESSION_TTL_MS = 2000  // Lines 5-6

This 2-second TTL ensures that cached sessions remain valid for rapid successive calls while expiring quickly enough to detect underlying target changes. When any CDP method is invoked, the system checks this timestamp; if expired, ensureSession() automatically refreshes the connection.

Active Tab Selection Logic

The ensureSession() function (lines 107-143) orchestrates session creation through a deterministic selection process:

  1. Enumerate targets via ego.listTabs()
  2. Select target using either a user-defined preferred target or the currently active tab
  3. Attach via Target.attachToTarget (using the raw CDP transport) to obtain a unique sessionId
  4. Initialize page-level events by calling Page.enable

This sequence ensures that every session is explicitly bound to a specific, verified target before any automation commands execute.

Automatic Re-attachment Mechanics

When underlying Chrome targets close, crash, or navigate, ego-browser detects the failure and recovers without throwing errors to the caller.

Detecting Session Loss

The system identifies broken sessions using a precise regex pattern defined at lines 9-10 in browser-runtime.ts:

SESSION_LOST = /Session (?:with given id )?not found|Target closed|No session/i

This pattern catches three distinct failure modes: explicit session ID errors, target closure notifications, and null session states.

The Recovery Pipeline

The browserCdp() function (lines 79-105) implements the core resilience logic:

  • Error interception: When a CDP request fails, the error message is tested against SESSION_LOST
  • Validation check: The system confirms the request was not an explicit browser-level call (which should not trigger re-attachment)
  • Session invalidation: Calls invalidateSession() (lines 46-54) to clear the cached sessionId and sessionAt timestamp
  • Transparent retry: Invokes ensureSession() to establish a fresh connection, then retries the original CDP method with the new session

This retry loop is completely transparent to user-level code; callers receive the successful response as if the session never failed.

Handling Target Detachment Events

The handleMessage() listener (lines 52-65) monitors browser-level events including Target.detachedFromTarget and Target.targetDestroyed. When these events reference the currently stored sessionTargetId, the function immediately invokes invalidateSession(), forcing the next CDP call to re-attach. This proactive invalidation prevents stale session usage before the TTL expires.

Key Source Files and Architecture

ego-browser's session management is distributed across three specialized modules:

File Role
package/ego-browser/src/browser-runtime.ts Contains browserCdp(), ensureSession(), invalidateSession(), and the SESSION_LOST detection regex. Implements the automatic recovery loop.
package/ego-browser/src/state.ts Holds mutable runtime state including sessionId, sessionAt, and sessionTargetId. Provides the low-level send wrapper used by the runtime.
package/ego-browser/src/cdp-eval.ts Exports the public cdp() helper that agents consume. This function forwards to browserCdp() and therefore inherits all automatic session management capabilities.

Practical Usage Examples

These patterns demonstrate how to leverage ego-browser's resilient CDP layer in automation scripts.

Basic CDP Calls With Automatic Recovery

The exported cdp() helper handles session validation and re-attachment automatically:

import { cdp } from "ego-browser";

// This call automatically ensures a valid session, re-attaches if the 
// target was lost, and retries the evaluation.
const result = await cdp("Runtime.evaluate", {
  expression: "document.title",
});
console.log("Page title:", result.result.value);

Manual Session Invalidation

For scenarios requiring explicit control (such as after programmatically reloading a tab), you can force a session refresh:

import { invalidateSession, ensureSession } from "ego-browser/src/browser-runtime.js";

// Clear the cached session to force re-attachment on next use
invalidateSession();

// Explicitly create a new session (optional - will happen automatically)
const freshSessionId = await ensureSession();

Subscribing to Browser Events

Monitor CDP events at the browser level while maintaining the auto-recovery benefits:

import { subscribeBrowserEvent } from "ego-browser/src/browser-runtime.js";

const unsub = subscribeBrowserEvent(
  "Target.detachedFromTarget",
  undefined, // No session filter - receive all detach events
  (event) => console.log("Target detached:", event.params?.targetId)
);

// Cleanup when done
unsub();

Summary

  • ego-browser caches CDP sessions for 2 seconds (SESSION_TTL_MS = 2000) to balance performance with freshness, as defined in browser-runtime.ts.
  • Session loss is detected via regex matching against /Session (?:with given id )?not found|Target closed|No session/i, covering navigation, crashes, and explicit closures.
  • Automatic recovery happens transparently in browserCdp(): invalidating the stale session, calling ensureSession() to re-attach, and retrying the original request without exposing errors to callers.
  • Proactive invalidation occurs when handleMessage() receives Target.detachedFromTarget or Target.targetDestroyed events for the current target.
  • Users control target selection via setPreferredTarget() and clearPreferredTarget(), influencing which tab receives the re-attached session.

Frequently Asked Questions

How long does ego-browser cache a CDP session before requiring re-attachment?

ego-browser considers a session valid for 2 seconds (2000ms), defined by the SESSION_TTL_MS constant in package/ego-browser/src/browser-runtime.ts. After this window expires, the next CDP call triggers ensureSession() to validate or refresh the connection.

What happens if the Chrome target crashes while ego-browser is executing a command?

The browserCdp() function catches the failure, matches the error against the SESSION_LOST regex, invalidates the cached session via invalidateSession(), and transparently retries the command after establishing a new session. This recovery occurs within the same async call, so the caller receives the successful result without handling the crash explicitly.

Can I force ego-browser to attach to a specific tab instead of the active one?

Yes. Use the setPreferredTarget() method before invoking CDP commands. When ensureSession() runs, it checks for a preferred target ID and attaches to that specific tab rather than querying for the currently active tab. Call clearPreferredTarget() to return to default behavior.

Where does ego-browser store the current session state?

Session state—including sessionId, sessionAt (timestamp), and sessionTargetId—is maintained in package/ego-browser/src/state.ts. This module also provides the low-level send wrapper that browser-runtime.ts uses to communicate with the Chrome DevTools Protocol.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →