How to Wait for Specific Page Conditions in ego-lite: Load States, URLs, and Element Visibility

Ego-lite provides Playwright-style wait helpers in driver/waits.ts that pause script execution until specific page conditions—such as load states, URL patterns, network activity, or element visibility—are met.

Ego-lite is a browser automation framework that abstracts Chrome DevTools Protocol (CDP) complexity into high-level synchronization primitives. Understanding how to wait for specific page conditions is essential for writing reliable automation scripts that avoid race conditions and ensure actions execute only when the page is actually ready.

Waiting for Page Load States

The waitForLoadState() function in package/ego-browser/src/driver/waits.ts serves as the primary entry point for page lifecycle synchronization. It supports three distinct load milestones:

  • loaddocument.readyState equals complete
  • domcontentloadeddocument.readyState is interactive or complete
  • networkidle – No network requests have been in-flight for a configurable idle period

The waitForLoadState Implementation

According to the source code, waitForLoadState() normalizes its arguments at lines 55-58, accepting either a string state name or an options object. The implementation bifurcates based on the requested state:

  • For "networkidle", it delegates to waitForNetworkIdle() (lines 62-64)
  • For "load" or "domcontentloaded", it invokes waitForDocumentLoad() (lines 66-68)

The waitForDocumentLoad() helper (located in driver/load.ts) polls document.readyState every few milliseconds (lines 25-27) until the required state appears or the global timeout expires.

Network Idle Detection

When requesting networkidle, ego-lite enables the Network CDP domain and monitors request activity. The system considers the page idle when no new network requests have started or remained in-flight for the specified duration, preventing premature interactions with pages that continue loading resources.

// Wait for the page to fully load and all network activity to cease
await waitForLoadState('networkidle', { timeout: 15000 });

// Wait only for DOM readiness before proceeding
await waitForLoadState('domcontentloaded');

Waiting for URL Navigation

The waitForURL() function (lines 84-118 in driver/waits.ts) repeatedly evaluates location.href via Runtime.evaluate and validates it against flexible matchers. It accepts strings, globs, regular expressions, or predicate functions through the urlMatches helper (lines 14-30).

If the caller specifies a waitUntil option, waitForURL() automatically chains into waitForLoadState() after the URL matches, ensuring the document reaches the desired ready state before returning control to the script.

// Wait for checkout URL pattern then ensure document is complete
await waitForURL('**/checkout', { waitUntil: 'load' });

// Wait with regex pattern and custom timeout
await waitForURL(/\/dashboard\/\d+/, { timeout: 10000 });

Waiting for Network Requests and Responses

For scenarios requiring synchronization with specific HTTP traffic, ego-lite exposes waitForRequest() and waitForResponse(). Both functions share the private waitForNetworkMatch() implementation (lines 50-77 in driver/waits.ts).

The workflow involves:

  1. Enabling network monitoring via acquireNetworkEvents() (lines 49-82), which activates the Network CDP domain only when needed
  2. Listening for CDP events through waitForBrowserEvent() until a request or response matches the supplied predicate (networkMatches, lines 22-38)
// Wait for a specific API request to initiate
await waitForRequest(url => url.includes('/api/cart'));

// Wait for the response to complete with specific status
const response = await waitForResponse(req => req.url.includes('/api/user'));

Waiting for Elements and Visibility

The waitForSelector() function (lines 85-112 in driver/waits.ts) provides robust element detection with optional visibility guarantees. It combines handle-based resolution with browser-side JavaScript evaluation.

The implementation follows this sequence:

  1. Resolve the selector using resolveHandle() (line 103), which maps CSS selectors, XPath expressions, or reference handles (@ref, loc=) to remote object handles
  2. Handle transient elements by retrying every 300ms (state.sleep(300)) if resolution fails
  3. Check visibility via Runtime.callFunctionOn executing the visibilityFn (line 99) if the state: 'visible' option is specified
  4. Cleanup by calling releaseHandle() (line 127) to prevent memory leaks in the CDP session
// Wait for element to exist in DOM
await waitForSelector('#submit-button');

// Wait for element to exist AND be visible
if (await waitForSelector('#confirm', { state: 'visible' })) {
  await click('#confirm');
}

// Wait with custom timeout and visibility requirement
await waitForSelector('.modal-content', { 
  state: 'visible', 
  timeout: 5000 
});

Summary

  • Load state synchronization uses waitForLoadState() in driver/waits.ts to monitor document.readyState or network idle conditions through driver/load.ts and network CDP domains.
  • URL-based waiting employs waitForURL() with flexible matchers and optional subsequent load state validation.
  • Network traffic waiting leverages waitForRequest() and waitForResponse() via the shared waitForNetworkMatch() helper that temporarily enables network event monitoring.
  • Element detection relies on waitForSelector() which uses handle resolution (resolveHandle/releaseHandle) from element-ops.ts and browser-side visibility checks to confirm elements are ready for interaction.
  • All wait operations respect the global timeout configuration from state.ts and use efficient polling intervals to balance responsiveness against CPU usage.

Frequently Asked Questions

What is the difference between "load" and "networkidle" in ego-lite?

The "load" state triggers when document.readyState becomes complete, indicating the HTML document and its immediate resources have finished parsing. The "networkidle" state requires that no network requests have been initiated or remained in-flight for a configurable idle period, ensuring that asynchronous scripts and dynamic content have finished loading.

How does ego-lite check element visibility during waits?

When waitForSelector() receives the state: 'visible' option, it executes a browser-side visibility function via Runtime.callFunctionOn (defined at line 99 in waits.ts). This function checks computed styles, bounding rectangles, and DOM properties to determine if the element is actually displayed to users before resolving the promise.

Can I wait for specific HTTP status codes or request methods?

Yes, the waitForRequest() and waitForResponse() functions accept predicate functions through the networkMatches helper (lines 22-38). You can inspect the request object for method, url, headers, or the response for status, providing fine-grained control over which network events unblock your automation script.

What happens if a wait operation times out?

All wait functions in driver/waits.ts reference the global state singleton from state.ts for default timeout values. When the timeout expires before the condition is met, the promise rejects with a timeout error, allowing your script to catch the exception and implement fallback logic or retries.

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 →