Ego-Browser Wait Functions: Complete Guide to Handling Different Waiting Conditions

Ego‑browser provides eight distinct wait helpers in src/driver/waits.ts and src/helpers.ts that handle timeouts, DOM elements, page functions, URLs, network requests/responses, load states, and agent task‑space ownership.

All wait functions are exposed through the helpers object, making them directly callable from agent scripts. This article examines each wait function's implementation, parameters, and use cases based on the citrolabs/ego-lite source code.

waitForTimeout: Fixed Duration Pauses

The simplest wait function pauses execution for a specified duration.

// src/driver/waits.ts#L44
await waitForTimeout(2000);  // 2 second pause

Implementation details:

  • Calls state.sleep(ms) internally
  • Defaults to 1000 ms when no argument provided
  • No polling overhead—pure sleep-based delay

Use sparingly; prefer explicit condition waits over arbitrary timeouts.

waitForFunction: Custom JavaScript Expressions

Polls until an arbitrary JavaScript expression returns a truthy value.

// Poll a custom page function with 250ms intervals
const title = await waitForFunction(
  () => document.title === 'Dashboard',
  { timeout: 5000, polling: 250 }
);

How it works:

  • Converts the function to a string via buildWaitForFunctionExpression
  • Repeatedly evaluates via Chrome DevTools Protocol's Runtime.evaluate
  • Loop continues until truthy return or timeout expires

waitForSelector: DOM Element Presence and Visibility

The most common element wait, supporting complex locator syntax beyond CSS selectors.

// Wait for element to exist in DOM
await waitForSelector('#login');

// Wait for visible, interactive element
await waitForSelector('#submit', { state: 'visible' });

Condition evaluation:

  • Repeatedly calls resolveHandle(selector) to locate the element
  • On successful resolution, optionally runs a visibility check via Runtime.callFunctionOn
  • Transient resolution errors trigger retry with short sleep
  • Permanent errors abort immediately

Available states: 'attached' (default), 'visible', 'hidden'.

waitForURL: Navigation Completion

Waits for the page URL to match a pattern, with optional load state verification.

// Glob pattern matching with network idle confirmation
await waitForURL('**/dashboard/**', { waitUntil: 'networkidle' });

// RegExp matcher
await waitForURL(/\/user\/\d+\/profile/, { timeout: 10000 });

Matching logic:

  • Polls location.href via Runtime.evaluate
  • Applies urlMatches against string, glob (*), RegExp, or predicate function
  • Optional waitUntil parameter accepts: 'load', 'domcontentloaded', 'networkidle', 'commit'

Network Observation Waits

These functions automatically enable the CDP Network domain during operation and clean up afterward.

waitForRequest

Captures outgoing network requests matching criteria.

// String matcher
await waitForRequest('**/api/users', { timeout: 10000 });

// Predicate function for complex matching
await waitForRequest(req => req.method === 'POST' && req.url.includes('/submit'));

Implementation: (src/driver/waits.ts#L26)

  • Uses internal waitForNetworkMatch("request", …)
  • Listens for Network.requestWillBeSent events
  • Builds request façade with URL, method, headers, postData accessors

waitForResponse

Captures incoming network responses with full body access.

// RegExp matcher with JSON extraction
const resp = await waitForResponse(/\.json$/, { timeout: 8000 });
const data = await resp.json();
console.log(resp.status());  // 200

Response façade methods: status(), text(), json(), headers(), url()

Implementation: (src/driver/waits.ts#L34)

  • Mirrors waitForRequest architecture
  • Listens for Network.responseReceived plus redirect chains
  • Provides lazy body retrieval methods

waitForLoadState: Page Lifecycle Milestones

Waits for specific document or network idle conditions.

// Standard load states
await waitForLoadState('domcontentloaded');
await waitForLoadState('load');

// Network idle with custom idle duration
await waitForLoadState('networkidle', { idleMs: 500, timeout: 15000 });

Two implementation paths:

Target Internal function Mechanism
networkidle waitForNetworkIdle (private) Polls drainEvents from src/driver/observe.ts until no network activity for idleMs
load / domcontentloaded waitForDocumentLoad from src/driver/load.ts Polls document.readyState until target state reached

waitForAgentControl: Task-Space Ownership

A specialized helper defined in src/helpers.ts for multi-agent coordination scenarios.

// Ensure exclusive access to a task space
await waitForAgentControl('my-task-space');

Implementation: (src/helpers.ts#L384)

  • Captures initial snapshot via ego.snapshot
  • Polls snapshot until task‑space ownership transfers to calling agent
  • Uses waitForBrowserEvent to listen for TaskSpaceChanged events
  • Prevents race conditions when human users and agents share browser instances

Shared Timeout Behavior

All wait functions honor consistent timeout semantics:

  • Omitted timeout: Uses state.defaultTimeout
  • timeout: 0: Infinite wait (internally capped at 2147483647 ms / ~24.8 days)
  • Network waits: Automatic CDP Network domain lifecycle management

Complete Usage Examples

import { helpers } from 'ego-browser';

// Sequential wait chain for complex login flow
async function performSecureLogin() {
  await helpers.waitForSelector('#username', { state: 'visible' });
  await helpers.waitForTimeout(500); // anti-automation debounce
  
  // Submit and wait for navigation + network quiet
  await helpers.waitForURL('**/dashboard', { 
    waitUntil: 'networkidle',
    timeout: 15000 
  });
  
  // Verify API initialization
  const initResponse = await helpers.waitForResponse('**/api/session/init');
  const session = await initResponse.json();
  
  // Confirm page-specific condition
  await helpers.waitForFunction(
    () => window.app?.initialized === true,
    { polling: 100, timeout: 5000 }
  );
}

Key Source Files

File Purpose
src/driver/waits.ts Core wait API implementations (waitForTimeout, waitForFunction, waitForURL, waitForRequest, waitForResponse, waitForLoadState, waitForSelector)
src/helpers.ts Re-exports waits and defines waitForAgentControl
src/driver/load.ts Document load state polling (waitForDocumentLoad)
src/driver/observe.ts Event draining for network idle detection
src/browser-runtime.ts Low-level waitForBrowserEvent infrastructure

Summary

  • Eight wait functions cover timeouts, DOM elements, JavaScript predicates, URLs, network requests/responses, load states, and agent control
  • Automatic CDP domain management ensures network waits work reliably across bridge configurations
  • Consistent timeout API with global default, explicit override, and infinite wait support
  • Locator flexibility extends beyond CSS selectors to include @refs and custom predicates
  • Source files in src/driver/waits.ts (core waits) and src/helpers.ts (agent control)

Frequently Asked Questions

What is the default timeout for wait functions in ego-browser?

When timeout is omitted, all wait functions fall back to state.defaultTimeout. The repository does not hard-code a single value—this is configurable at the browser context level. Explicit timeout: 0 creates an effectively infinite wait.

How does waitForSelector handle elements that appear then disappear?

waitForSelector resolves on first successful match according to the state option. For dynamic elements, combine with waitForFunction to verify stable presence, or chain multiple waits to observe state transitions.

Can waitForRequest and waitForResponse match request bodies?

The request façade includes postData() for body access, but matching predicates execute against the façade object before body retrieval. For body-based matching, use waitForResponse and inspect the response in subsequent code rather than in the matcher itself.

What happens if networkidle is requested but the page has persistent polling?

waitForLoadState('networkidle') waits until no network requests occur for idleMs milliseconds (default 500). Persistent polling will prevent networkidle unless the polling interval exceeds the idle threshold. Consider using domcontentloaded or explicit waitForFunction checks for such pages.

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 →