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

# click_until_exhausted

Repeatedly click a button until no new content appears or max clicks reached.

This function is useful for "Load More" buttons or paginated content where you need to
keep clicking until all content is loaded. It provides several stopping conditions:

* Button becomes invisible/disabled
* Maximum number of clicks reached
* No change detected in container content (when container\_locator is provided)

```python theme={null}
async def click_until_exhausted(
    page: Page,
    button_locator: Locator,
    heartbeat: Callable[[], None],
    *,
    container_locator: Locator | None,
    max_clicks: int,
    click_delay: float,
    no_change_threshold: int,
)
```

## Examples

<CodeGroup>
  ```python Load All Items theme={null}
  from typing import TypedDict
  from playwright.async_api import Page
  from intuned_browser import click_until_exhausted
  class Params(TypedDict):
      pass
  async def automation(page: Page, params: Params, **_kwargs):
      await page.goto("https://sandbox.intuned.dev/load-more")
      load_more_button = page.locator("main main button")  # Select the main button in the main content area.
      # Click until button disappears or is disabled
      await click_until_exhausted(
          page=page,
          button_locator=load_more_button,
          max_clicks=20
      )
      # Will keep clicking the button until the button disappears or is disabled or the max_clicks is reached.
  ```

  ```python Track Container Changes theme={null}
  from typing import TypedDict
  from playwright.async_api import Page
  from intuned_browser import click_until_exhausted
  class Params(TypedDict):
      pass
  async def automation(page: Page, params: Params, **_kwargs):
      await page.goto("https://sandbox.intuned.dev/load-more")
      load_more_button = page.locator("aside button")  # Select the button in the sidebar.
      container = page.locator('xpath=//*[@id="root"]/div[1]/main/slot/div/aside/div/div/slot/slot')  # Watch the sidebar container to detect changes.
      # This will count the elements under the container given before each click and after, if the count is the same, the function will stop.
      click_count = 0
      def heartbeat_callback():
          nonlocal click_count
          click_count += 1
          print(f"Clicked {click_count} times")
      await click_until_exhausted(
          page=page,
          button_locator=load_more_button,
          container_locator=container,
          heartbeat=heartbeat_callback,
          max_clicks=30,
          click_delay=0.5,
          no_change_threshold=0
      )
      # Will keep clicking the button until the button disappears or is disabled or the max_clicks is reached or no more content is loaded.
  ```
</CodeGroup>

## Arguments

<ResponseField name="page" type="Page" required>
  Playwright Page object
</ResponseField>

<ResponseField name="button_locator" type="Locator" required>
  Locator for the button to click repeatedly
</ResponseField>

<ResponseField name="heartbeat" type="Callable[[], None]">
  Optional callback invoked after each click. Defaults to lambda: None.
</ResponseField>

<ResponseField name="container_locator" type="Locator">
  Optional content container to detect changes. Defaults to None.
</ResponseField>

<ResponseField name="max_clicks" type="int">
  Maximum number of times to click the button. Defaults to 50.
</ResponseField>

<ResponseField name="click_delay" type="float">
  Delay after each click (in seconds). Defaults to 0.5.
</ResponseField>

<ResponseField name="no_change_threshold" type="int">
  Minimum change in content size to continue clicking. Defaults to 0.
</ResponseField>

## Returns: `None`

Function completes when clicking is exhausted
