How ego-lite Manages CDP Sessions with a 2-Second TTL

Ego-lite caches Chrome DevTools Protocol sessions for exactly 2 seconds using a TTL-based expiration mechanism defined in browser-runtime.ts, automatically refreshing stale connections via the ensureSession() helper before executing page-level CDP commands.

Ego-lite provides lightweight browser automation by communicating directly with the Chrome DevTools Protocol (CDP). To minimize connection overhead while preventing stale WebSocket attachments, the framework implements a strict ego-lite CDP session management strategy that caches session identifiers for precisely two seconds before requiring refresh.

The 2-Second TTL Constant

The session lifetime threshold is hardcoded as a constant in the browser runtime module. In package/ego-browser/src/browser-runtime.ts at line 5, the codebase defines:

// package/ego-browser/src/browser-runtime.ts
export const SESSION_TTL_MS = 2000; // 2 seconds

This value represents the maximum age in milliseconds that a cached CDP session remains valid. Once the elapsed time since the last successful attachment exceeds this threshold, the runtime treats the session as expired.

Session State Architecture

Session metadata persists in a global state object defined in package/ego-browser/src/state.ts. Lines 32-35 declare three critical properties that track the active CDP connection:

// package/ego-browser/src/state.ts
export const state = {
  // ... other state properties
  sessionId: null as string | null,        // Active CDP session identifier
  sessionAt: 0 as number,                  // Timestamp of last attach (epoch ms)
  sessionTargetId: null as string | null,  // Target tab or page ID
};

These fields enable synchronous validation of session freshness before issuing asynchronous CDP commands.

The ensureSession() Validation Lifecycle

Every helper function that requires a page-level CDP call invokes await ensureSession(). This function implements the TTL logic by comparing the current timestamp against state.sessionAt:

// Conceptual implementation based on browser-runtime.ts patterns
async function ensureSession() {
  const now = Date.now();
  const sessionAge = now - state.sessionAt;
  
  // Check if existing session is still within 2-second TTL
  if (state.sessionId && sessionAge < SESSION_TTL_MS) {
    return state.sessionId; // Reuse valid cached session
  }
  
  // TTL expired or no session exists - refresh required
  return await refreshSession();
}

When the session age exceeds 2000ms, the function triggers refreshSession(), which detaches from the stale target, establishes a new CDP session via Target.attachToTarget, and updates state.sessionId, state.sessionTargetId, and state.sessionAt with current values.

Automatic Refresh Behavior

The 2-second window creates an aggressive eviction policy that serves two purposes:

  • Prevents stale connections: WebSocket links to browser targets can crash or timeout; the short TTL ensures ego-lite never attempts to reuse a dead session for more than 2 seconds.
  • Reduces session churn: Rapid-fire operations completing within 2 seconds reuse the same sessionId, avoiding the overhead of repeated Target.attachToTarget calls.

When refreshing, the runtime updates all three state properties atomically to maintain consistency across concurrent operations.

Summary

  • TTL Definition: SESSION_TTL_MS = 2000 in package/ego-browser/src/browser-runtime.ts enforces a strict 2-second session lifetime.
  • State Tracking: The global state object maintains sessionId, sessionAt, and sessionTargetId in package/ego-browser/src/state.ts.
  • Validation: ensureSession() checks Date.now() - state.sessionAt against the TTL before every CDP operation.
  • Auto-Refresh: Expired sessions trigger automatic re-attachment to the Chrome DevTools Protocol target without manual intervention.

Frequently Asked Questions

What triggers a CDP session refresh in ego-lite?

A refresh occurs when ensureSession() detects that the elapsed time since state.sessionAt exceeds SESSION_TTL_MS (2000ms). This function runs before every page-level CDP command, automatically detaching from stale targets and creating new sessions when the 2-second TTL expires.

Why does ego-lite limit CDP sessions to 2 seconds?

The 2-second TTL prevents memory leaks and WebSocket timeouts in long-running automation scripts while allowing batch operations to reuse connections. According to the citrolabs/ego-lite source code, this aggressive expiration ensures that crashed or frozen browser targets do not leave zombie sessions in the cache.

Where is the active CDP session ID stored in ego-lite?

The active session identifier resides in state.sessionId, defined in package/ego-browser/src/state.ts at line 32. This property updates whenever ensureSession() establishes a new connection, alongside state.sessionAt (timestamp) and state.sessionTargetId (browser tab reference).

How can I force a new CDP session before the TTL expires?

While the framework handles this automatically, you can manually invalidate the cache by setting state.sessionAt = 0 or state.sessionId = null. The next call to ensureSession() will detect the invalid state and trigger a fresh Target.attachToTarget request regardless of the 2-second window.

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 →