How ego-lite Manages CDP Sessions and Automatic Re-attachment

ego-lite maintains a 2-second TTL-based CDP session that automatically re-attaches to the browser when connections are lost, using centralized state management and transparent retry logic.

The citrolabs/ego-lite browser automation framework communicates with Chromium through the Chrome DevTools Protocol (CDP) using a resilient session management architecture. This article examines how ego-lite handles CDP session lifecycle, implements automatic re-attachment, and maintains connection state to ensure uninterrupted browser automation.

Session TTL and Validation

ego-lite considers a CDP session valid for 2 seconds after creation, defined by the SESSION_TTL_MS = 2000 constant in src/browser-runtime.ts (line 5). After this period, the runtime treats the session as expired and requests a new one.

Every helper function that requires a page-level CDP call first invokes ensureSession() (lines 7-44). This function checks state.sessionId and validates whether the session has exceeded the TTL using the sessionAt timestamp. If the session is missing or stale, ensureSession() automatically creates a fresh session.

Session Creation and Target Attachment

When ensureSession() determines a new session is needed, it executes the following sequence (lines 16-36 in src/browser-runtime.ts):

  1. Lists all available tabs using browserEgo().listTabs()
  2. Selects the target tab based on priority: state.preferredTargetId if set, otherwise the active tab, or the last tab
  3. Calls Target.attachToTarget with flattened mode to obtain a new session ID
  4. Stores the session ID in state.sessionId and updates state.sessionAt with the current timestamp
  5. Invokes enablePageEvents(state.sessionId) to buffer page events like Page.loadEventFired

Developers can force attachment to a specific tab by setting state.preferredTargetId via the setPreferredTarget() function (lines 56-58).

Automatic Re-attachment Mechanism

Session loss is handled transparently through the browserCdp function's error handling logic (lines 95-103). When a CDP request fails with a "session not found" or "Target closed" error (matched against the SESSION_LOST regex), the runtime:

  1. Checks if the call was explicitly bound to a session
  2. If not bound, calls invalidateSession() (lines 46-54) to clear state.sessionId and associated caches (pageEnabledSessions, pendingDialogs)
  3. Retries the original request with a newly created session via ensureSession()

This automatic retry mechanism ensures that transient connection failures do not interrupt automation scripts.

Central State Management

All session-related state lives in the exported state object defined in src/state.ts (lines 24-38):

  • sessionId: Current CDP session identifier
  • sessionTargetId: The target (tab) to which the session is attached
  • sessionAt: Timestamp of last successful session acquisition (used for TTL validation)
  • sessionInflight: Promise tracking ongoing session creation to prevent duplicate work
  • preferredTargetId: Optional override specifying which tab to attach to
  • defaultTimeout: Default CDP request timeout (10 seconds)

Practical Implementation Examples

The following examples demonstrate how to interact with ego-lite's session management:

// Force the runtime to use a specific tab
import { browserCdp, setPreferredTarget } from "ego-browser";

setPreferredTarget("target-id-123");

// Page-level CDP commands automatically ensure a valid session
const result = await browserCdp("Page.navigate", { url: "https://example.com" });
console.log(result);
// Manual session invalidation for advanced error handling
import { browserCdp, invalidateSession } from "ego-browser";

try {
  await browserCdp("Runtime.evaluate", { expression: "document.title" });
} catch (err) {
  if (/Session.*not found/.test(err.message)) {
    invalidateSession(); // Force fresh attachment
    const title = await browserCdp("Runtime.evaluate", { expression: "document.title" });
    console.log("Recovered title:", title);
  } else {
    throw err;
  }
}

Summary

  • Session TTL: CDP sessions remain valid for 2 seconds (SESSION_TTL_MS = 2000) before requiring renewal
  • Automatic Creation: The ensureSession() function in src/browser-runtime.ts handles lazy session initialization and tab selection
  • Transparent Recovery: The browserCdp function automatically retries failed requests after calling invalidateSession() when session loss is detected
  • Centralized State: Session metadata is stored in the mutable state object from src/state.ts, including IDs, timestamps, and configuration
  • Tab Targeting: Use setPreferredTarget() to force attachment to specific tabs via state.preferredTargetId

Frequently Asked Questions

How long does ego-lite keep a CDP session active?

ego-lite maintains a CDP session for 2 seconds after creation. The SESSION_TTL_MS constant in src/browser-runtime.ts defines this duration, after which ensureSession() automatically creates a new session on the next page-level CDP call.

What happens when a CDP session is lost during execution?

When a request fails with a session error, browserCdp catches the exception using the SESSION_LOST regex, calls invalidateSession() to clear the cached ID, and transparently retries the request with a fresh session. This occurs in lines 95-103 of src/browser-runtime.ts.

Can I force ego-lite to use a specific browser tab?

Yes. Call setPreferredTarget(targetId) to set state.preferredTargetId. During the next session creation, ensureSession() will prioritize this target ID when calling Target.attachToTarget, ensuring attachment to your specified tab.

Where is session state stored in ego-lite?

Session state resides in the exported state object defined in src/state.ts (lines 24-38). This includes sessionId, sessionTargetId, sessionAt timestamps, and the sessionInflight promise used to prevent duplicate session creation requests.

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 →