# How to Use Ego-Browser Wait Helpers: Mastering waitForSelector and waitForURL

> Master ego-browser wait helpers like waitForSelector and waitForURL. Eliminate manual loops with auto-polling for DOM elements and URL patterns, ensuring consistent timeouts and error handling.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-07-30

---

**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`](https://github.com/citrolabs/ego-lite/blob/main/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`](https://github.com/citrolabs/ego-lite/blob/main/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`](https://github.com/citrolabs/ego-lite/blob/main/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's `state.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.

```javascript
// 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 object
- **`waitUntil`**: Optional load state (`'load'`, `'domcontentloaded'`, `'networkidle'`, or `'commit'`)
- **`timeout`**: Maximum milliseconds to poll

```javascript
// 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`](https://github.com/citrolabs/ego-lite/blob/main/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`](https://github.com/citrolabs/ego-lite/blob/main/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.

```javascript
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.

```javascript
// 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 from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)
- **Auto-Polling**: `waitForSelector` and `waitForURL` automatically retry using `resolveHandle` and `Runtime.evaluate` until conditions are met
- **Flexible Matchers**: URL waiting supports strings, globs, `RegExp`, and predicate functions via the `urlMatches` utility
- **Load State Integration**: Combine URL waits with `'networkidle'` or `'load'` to ensure complete page readiness before proceeding
- **Error Differentiation**: Handle `ElementResolutionError` for 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`](https://github.com/citrolabs/ego-lite/blob/main/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()`.