> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uplink.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Waiting

> Methods for waiting for elements, conditions, and network requests

Wait for elements, JavaScript conditions, and network requests before proceeding with automation.

## Methods

### `page.waitForSelector()`

Waits for an element matching the selector to appear in the DOM.

```typescript theme={null}
page.waitForSelector(selector: string, options?: WaitForOptions): Promise<void>
```

**Parameters:**

* `selector`: CSS selector for the element to wait for
* `options` (optional): Wait options

**Options:**

```typescript theme={null}
interface WaitForOptions {
  timeout?: number    // Timeout in milliseconds (default: 60000)
  times?: number      // Number of retry attempts (default: 600)
  interval?: number   // Interval between attempts in ms (default: 100)
}
```

**Returns:** `Promise<void>`

**Examples:**

```typescript theme={null}
// Wait for element (default 60s timeout)
await page.waitForSelector('.loaded-content')

// Custom timeout (5 seconds)
await page.waitForSelector('#modal', { timeout: 5000 })

// Custom retry behavior
await page.waitForSelector('.dynamic-element', {
  timeout: 30000,
  times: 300,
  interval: 100
})
```

### `page.waitForFunction()`

Waits until a function returns a truthy value.

```typescript theme={null}
page.waitForFunction(
  fn: Function,
  options?: WaitForOptions,
  ...args: unknown[]
): Promise<void>
```

**Parameters:**

* `fn`: Function to evaluate repeatedly until it returns truthy
* `options` (optional): Wait options
* `args` (optional): Arguments to pass to the function

**Returns:** `Promise<void>`

**Examples:**

```typescript theme={null}
// Wait for page ready state
await page.waitForFunction(() => document.readyState === 'complete')

// Wait for custom condition
await page.waitForFunction(() => {
  return document.querySelectorAll('.product').length > 0
})

// With parameters
await page.waitForFunction(
  (minCount) => document.querySelectorAll('.item').length >= minCount,
  {},
  10
)

// With timeout
await page.waitForFunction(
  () => window.dataLoaded === true,
  { timeout: 10000 }
)
```

### `page.waitForRequest()`

Waits for a matching HTTP request to occur.

```typescript theme={null}
page.waitForRequest(
  matcher: string | RequestMatchFunction,
  options?: WaitForOptions
): Promise<Request>
```

**Parameters:**

* `matcher`: URL string or predicate function to match requests
* `options` (optional): Wait options

**RequestMatchFunction:**

```typescript theme={null}
type RequestMatchFunction = (request: Request) => boolean

interface Request {
  url: string
  method: string
  headers: Record<string, string>
}
```

**Returns:** `Promise<Request>` - The matched request

**Examples:**

```typescript theme={null}
// Wait for specific URL
const request = await page.waitForRequest('https://api.example.com/data')
console.log('API request detected:', request.url)

// Wait with predicate function
const apiRequest = await page.waitForRequest((req) => {
  return req.url.includes('/api/') && req.method === 'POST'
})
console.log('POST request to API:', apiRequest.url)

// With timeout
const request = await page.waitForRequest(
  'https://slow-api.example.com/data',
  { timeout: 120000 }  // 2 minutes
)
```

## Complete examples

### Wait for page load

```typescript theme={null}
await page.goto('https://example.com')

// Wait for multiple indicators
await Promise.all([
  page.waitForSelector('#main-content'),
  page.waitForFunction(() => document.readyState === 'complete'),
  page.waitForFunction(() => {
    return document.querySelectorAll('.item').length > 0
  })
])

console.log('Page fully loaded and ready')
```

### Wait for dynamic content

```typescript theme={null}
await page.goto('https://example.com/products')

// Wait for loading spinner to disappear
await page.waitForFunction(() => {
  const spinner = document.querySelector('.loading-spinner')
  return spinner === null || spinner.style.display === 'none'
})

// Wait for products to load
await page.waitForSelector('.product-grid')
await page.waitForFunction(() => {
  return document.querySelectorAll('.product').length >= 10
})

console.log('Products loaded')
```

### Wait for API response

```typescript theme={null}
await page.goto('https://example.com/app')

// Click button that triggers API call
await page.click('#load-data-button')

// Wait for specific API request
const request = await page.waitForRequest((req) => {
  return req.url.includes('/api/users') && req.method === 'GET'
})

console.log('API request made:', request.url)

// Wait for data to appear
await page.waitForSelector('.user-list')
```

### Sequential waits

```typescript theme={null}
// Step 1: Navigate to login
await page.goto('https://example.com/login')

// Step 2: User logs in on their device
await page.waitForAuthentication(
  async (page) => {
    return window.location.pathname === '/dashboard'
  },
  { timeout: 120000 }
)

// Step 3: Wait for dashboard content to load
await page.waitForSelector('.dashboard-widget')

console.log('User authenticated, dashboard loaded')
```

### Timeout handling

```typescript theme={null}
async function waitForElementSafely(selector, timeout = 10000) {
  try {
    await page.waitForSelector(selector, { timeout })
    return true
  } catch (error) {
    console.error(`Element ${selector} not found within ${timeout}ms`)
    return false
  }
}

const modalAppeared = await waitForElementSafely('#modal', 5000)

if (modalAppeared) {
  await page.click('#modal .close-button')
} else {
  console.log('No modal to close')
}
```

### Wait for multiple conditions

```typescript theme={null}
await page.goto('https://example.com/interactive')

// Wait for all conditions to be true
await Promise.all([
  // Element present
  page.waitForSelector('#app-container'),

  // JavaScript loaded
  page.waitForFunction(() => typeof window.app !== 'undefined'),

  // Data fetched
  page.waitForFunction(() => window.app?.dataReady === true),

  // No loading indicators
  page.waitForFunction(() => {
    return document.querySelectorAll('.loading').length === 0
  })
])

console.log('App fully initialized and ready')
```

### Wait for text content

```typescript theme={null}
// Wait for specific text to appear
await page.waitForFunction((searchText) => {
  return document.body.innerText.includes(searchText)
}, {}, ['Success'])

console.log('Success message appeared')

// Wait for element with specific text
await page.waitForFunction(() => {
  const el = document.querySelector('.status')
  return el && el.textContent.trim() === 'Complete'
})
```

### Poll for changes

```typescript theme={null}
await page.goto('https://example.com/live-data')

// Wait for count to reach threshold
await page.waitForFunction(() => {
  const countEl = document.querySelector('.count')
  if (!countEl) return false

  const count = parseInt(countEl.textContent, 10)
  return count >= 100
}, { timeout: 60000 })

console.log('Count reached 100')
```

### Wait for network idle

```typescript theme={null}
await page.goto('https://example.com/app')

// Wait for no API calls for 2 seconds
let lastRequestTime = Date.now()

await page.on('xhr', () => {
  lastRequestTime = Date.now()
})

await page.waitForFunction(() => {
  return Date.now() - lastRequestTime > 2000
}, { timeout: 30000 })

console.log('Network idle for 2 seconds')
```

## Best practices

<AccordionGroup>
  <Accordion title="Always wait before interacting" icon="hourglass">
    Wait for elements before clicking or typing:

    ```typescript theme={null}
    await page.waitForSelector('#button')
    await page.click('#button')
    ```
  </Accordion>

  <Accordion title="Use appropriate timeouts" icon="clock">
    Set timeouts based on expected load times:

    ```typescript theme={null}
    // Fast operation
    await page.waitForSelector('.quick', { timeout: 5000 })

    // Slow API
    await page.waitForRequest('/slow-api', { timeout: 120000 })
    ```
  </Accordion>

  <Accordion title="Handle timeout errors" icon="triangle-exclamation">
    Always catch timeout errors gracefully:

    ```typescript theme={null}
    try {
      await page.waitForSelector('.optional-element', { timeout: 5000 })
    } catch (error) {
      console.log('Optional element not found, continuing...')
    }
    ```
  </Accordion>

  <Accordion title="Wait for multiple indicators" icon="list-check">
    Wait for several conditions to ensure page is ready:

    ```typescript theme={null}
    await Promise.all([
      page.waitForSelector('.content'),
      page.waitForFunction(() => document.readyState === 'complete')
    ])
    ```
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Navigation" icon="compass" href="/api-reference/page/navigation">
    Navigate and track page loads
  </Card>

  <Card title="Events" icon="bell" href="/api-reference/page/events">
    Monitor page events
  </Card>

  <Card title="Interaction" icon="hand-pointer" href="/api-reference/page/interaction">
    Interact after waiting
  </Card>

  <Card title="Page overview" icon="window-maximize" href="/api-reference/page/overview">
    Back to Page API overview
  </Card>
</CardGroup>
