# How the 2-Second Session TTL and Auto-Reattachment Work in ego-browser

> Understand the 2-second session TTL and auto-reattachment in ego-browser. Learn how it minimizes overhead, invalidates stale sessions, and re-attaches to targets for efficient operation.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: internals
- Published: 2026-07-27

---

**The ego-browser runtime maintains a 2-second TTL on Chrome DevTools Protocol sessions to minimize overhead, automatically invalidating stale sessions and re-attaching to targets when errors indicate session loss.**

The `citrolabs/ego-lite` repository implements a lightweight browser automation layer that communicates with Chrome via the DevTools Protocol. To balance performance against reliability, the runtime employs a **2-second session TTL and auto-reattachment** strategy that aggressively caches sessions while transparently recovering from target detachment. This design ensures rapid DOM interactions without the fragility of long-lived connections.

## The 2-Second Session TTL Mechanism

The session cache duration is defined by the `SESSION_TTL_MS` constant in [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts).

```typescript
// package/ego-browser/src/browser-runtime.ts
const SESSION_TTL_MS = 2000;  // 2-second window

```

The `ensureSession()` function enforces this TTL by comparing the current timestamp against `state.sessionAt`, which records when the session was last attached. If the cached session is younger than 2 seconds, it is reused; otherwise, a fresh attachment is created.

```typescript
export async function ensureSession() {
  // Re-use cached session only if within TTL
  if (state.sessionId && Date.now() - state.sessionAt < SESSION_TTL_MS) {
    return state.sessionId;
  }
  // ... attach to target and update state.sessionId / state.sessionAt
}

```

This short-lived caching avoids the latency of repeated `Target.attachToTarget` calls during rapid-fire operations while preventing stale session accumulation. The mutable state (`sessionId`, `sessionAt`) is maintained in [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts).

## Automatic Re-attachment on Session Loss

When a CDP request fails due to a disappeared session—such as when a tab closes or Chrome resets the target—the `browserCdp()` function intercepts the error and initiates recovery.

The runtime uses a `SESSION_LOST` regex to detect failure messages like *"Session not found"* or *"Target closed"*. Upon detection, it invalidates the stale cache and retries the original request with a fresh session.

```typescript
// package/ego-browser/src/browser-runtime.ts
export async function browserCdp(method, params = {}, sessionId, timeoutMs) {
  // ...
  try {
    return await rawCdp(method, params, effective, timeoutMs);
  } catch (error) {
    const lost = SESSION_LOST.test(error?.message || "");
    // Auto-retry only for implicit sessions (no explicit sessionId provided)
    if (lost && !explicit && !BROWSER_LEVEL(method)) {
      invalidateSession();                    // clear state.sessionId
      const fresh = await ensureSession();    // attach new target
      return rawCdp(method, params, fresh, timeoutMs); // retry
    }
    throw error;
  }
}

```

The `invalidateSession()` helper clears `state.sessionId` and `state.sessionAt`, forcing `ensureSession()` to create a new attachment on the next invocation. This makes transient session failures invisible to calling code.

## Practical Usage Examples

### Example 1: Normal Helper Usage (Auto-Reuse)

High-level helper methods automatically benefit from the TTL without manual session handling.

```javascript
// Both calls share the same session if within 2 seconds
await ego.browser.click('@12');
await ego.browser.evaluate(() => document.title);

```

### Example 2: TTL Expiry Triggers Fresh Attachment

Simulating a delay longer than the TTL forces a new attachment on the next operation.

```javascript
// Wait beyond the 2-second window
await new Promise(r => setTimeout(r, 2500));

// ensureSession() detects expiry and re-attaches
await ego.browser.evaluate(() => document.body.innerHTML);

```

### Example 3: Transparent Recovery from Session Loss

If Chrome terminates the session externally, the runtime retries automatically.

```javascript
// If the target closes during this call, the runtime catches the error,
// invalidates the stale session, attaches to the new target, and retries.
// The caller never sees the failure.
await ego.browser.evaluate(() => document.title);

```

## Summary

- **2-second TTL**: Sessions are reused only within a 2000ms window defined by `SESSION_TTL_MS` in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), minimizing attachment overhead.
- **State tracking**: `state.sessionAt` and `state.sessionId` in [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts) track session freshness.
- **Automatic recovery**: The `browserCdp()` function catches session-loss errors via regex matching, calls `invalidateSession()`, and retries with a fresh attachment.
- **Transparency**: Recovery only occurs for implicit sessions (when the caller does not provide an explicit `sessionId`), ensuring predictable behavior for manual session management.

## Frequently Asked Questions

### What triggers the 2-second session TTL reset?

The TTL resets whenever `ensureSession()` creates a new attachment, updating `state.sessionAt` to the current timestamp. This occurs when the previous session expires after 2000ms or when `invalidateSession()` clears the cache due to a detected session loss.

### How does ego-browser detect a lost session?

The runtime tests error messages against the `SESSION_LOST` regex in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), which matches patterns like *"Session not found"* or *"Target closed"*. When `browserCdp()` catches such an error, it triggers the invalidation and re-attachment flow.

### Can I disable automatic re-attachment for specific calls?

Yes. The auto-retry logic only executes when the `sessionId` parameter is omitted (implicit session). If you explicitly pass a `sessionId` to `browserCdp()`, the runtime treats the call as browser-level or manually managed and propagates session errors without retrying.

### Where is the session state stored?

Mutable session state—including `sessionId`, `sessionAt`, and attachment metadata—is stored in [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts). The [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) module imports this state to implement the TTL checks in `ensureSession()` and the cleanup logic in `invalidateSession()`.