How to Use Ego-Browser Wait Helpers: Mastering waitForSelector and waitForURL
Ego-browser wait helpers provide auto-polling mechanisms that repeatedly check for DOM elements or URL patterns until conditions are met, eliminating manual while loops with consistent timeout and error handling.
The citrolabs/ego-lite repository exposes a Playwright-compatible API through a page facade that simplifies browser automation for agents. These wait helpers abstract away complex polling logic, offering precise control over element visibility, navigation timing, and network activity.
Architecture of the Wait Helper System
The Page Facade Pattern
In src/helpers.ts, the createPageFacade() function assembles the page object that exposes wait methods to agent scripts. Lines 91-98 export these helpers, making them available as page.waitForSelector(), page.waitForURL(), and related methods. This facade pattern ensures agents interact with a consistent, auto-waiting interface regardless of underlying implementation details.
Core Implementation in waits.ts
The actual logic resides in src/driver/waits.ts. When an agent invokes await page.waitForSelector(), control jumps to the implementation at lines 91-132, which repeatedly calls resolveHandle from src/element-resolver.ts until the element exists or the timeout expires. Similarly, waitForURL at lines 84-118 evaluates location.href via Runtime.evaluate until the URL matches the provided pattern.
Using waitForSelector Effectively
The waitForSelector method polls CSS selectors, @ref attributes, loc= prefixes, or XPath expressions until an element exists. Located at src/driver/waits.ts:91-132, it accepts a selector string and an options object containing:
state: Either'visible'(default) or'attached'timeout: Milliseconds to wait (defaults to runtime'sstate.defaultTimeout)
When state: 'visible' is requested, the helper runs a visibility function inside the page context to ensure the element is actually displayed, not merely present in the DOM.
// Wait for button to be visible (default behavior)
await page.waitForSelector('button.submit', { state: 'visible' });
// Wait for element to exist without visibility requirement
await page.waitForSelector('#progress-bar', {
state: 'attached',
timeout: 15000
});
Navigating with waitForURL
The waitForURL helper repeatedly reads location.href until it matches the provided pattern. It supports string matching, glob patterns, RegExp, or custom predicate functions, then optionally waits for a specific load state.
Parameters include:
urlMatcher: String, glob,RegExp, or function receiving the URL objectwaitUntil: Optional load state ('load','domcontentloaded','networkidle', or'commit')timeout: Maximum milliseconds to poll
// Glob pattern with full page load
await page.waitForURL('**/checkout*', {
waitUntil: 'load',
timeout: 20000
});
// Predicate function with network idle
await page.waitForURL(url => url.pathname === '/dashboard', {
waitUntil: 'networkidle'
});
Internally, after URL matching succeeds, the helper optionally calls waitForLoadState to ensure the document has reached the specified readiness state.
Advanced Wait Helpers
waitForLoadState
Located at src/driver/waits.ts:150-169, this helper waits for document lifecycle events. It delegates to waitForDocumentLoad from src/driver/load.ts for standard events or activates a network-idle monitor when requesting 'networkidle'.
waitForFunction
At lines 48-82 of src/driver/waits.ts, this helper re-evaluates a JavaScript expression or function until it returns a truthy value. This is essential for SPAs that expose ready flags.
await page.waitForFunction(() => window.appReady === true, {
polling: 250,
timeout: 120000
});
Network Activity Waits
waitForRequest and waitForResponse (lines 120-144) listen for network activity matching string, RegExp, or predicate patterns.
// Capture request before it completes
const req = await page.waitForRequest('/api/orders', { timeout: 5000 });
console.log('Payload:', await req.postData());
// Wait for response and parse JSON
const res = await page.waitForResponse(/\/api\/profile/);
const profile = await res.json();
Error Handling and Timeout Behavior
All helpers default to the runtime's state.defaultTimeout but accept explicit timeout options. The system distinguishes between transient failures (retrying) and permanent errors:
ElementResolutionError: Thrown for temporary selector resolution failures during polling- Standard
Error: Thrown for permanent issues like invalid selectors or expired timeouts
Wrap waits in try/catch blocks to implement fallback logic or capture diagnostic screenshots.
Summary
- Page Facade: Access all wait helpers through
page.waitFor...methods exported fromsrc/helpers.ts - Auto-Polling:
waitForSelectorandwaitForURLautomatically retry usingresolveHandleandRuntime.evaluateuntil conditions are met - Flexible Matchers: URL waiting supports strings, globs,
RegExp, and predicate functions via theurlMatchesutility - Load State Integration: Combine URL waits with
'networkidle'or'load'to ensure complete page readiness before proceeding - Error Differentiation: Handle
ElementResolutionErrorfor transient DOM issues and standard errors for configuration problems
Frequently Asked Questions
What is the default timeout for ego-browser wait helpers?
All wait helpers default to the runtime's state.defaultTimeout (typically 30 seconds), but you can override this via the timeout option specified in milliseconds. If the timeout is exceeded, the promise rejects with an error indicating which condition failed to resolve.
How does waitForSelector handle element visibility?
When state: 'visible' is specified (the default), the helper first resolves the element handle using resolveHandle from src/element-resolver.ts, then executes a visibility function inside the browser context. This checks CSS properties and DOM geometry to ensure the element is actually displayed to users, not merely attached to the document.
Can I use regular expressions with waitForURL?
Yes. The waitForURL helper at src/driver/waits.ts:84-118 accepts RegExp objects, glob strings, literal URL fragments, or synchronous predicate functions receiving the URL object. This flexibility allows matching dynamic routes containing IDs, query parameters, or hash fragments without exact string matching.
What is the difference between waitForRequest and waitForResponse?
waitForRequest resolves when a request is initiated matching your pattern, giving you access to headers and POST data before the server responds. waitForResponse resolves when the corresponding HTTP response completes, allowing you to access the status code, headers, and response body via methods like .json() or .text().
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 →