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.hrefviaRuntime.evaluate - Applies
urlMatchesagainst string, glob (*), RegExp, or predicate function - Optional
waitUntilparameter 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.requestWillBeSentevents - 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
waitForRequestarchitecture - Listens for
Network.responseReceivedplus 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
waitForBrowserEventto listen forTaskSpaceChangedevents - 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 at2147483647 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) andsrc/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →