Chat with us, powered by LiveChat
← Return to MyDisct Solver

BrowserAPI Wait Methods

The BrowserAPI class provides four wait methods through the session.browser interface that let you pause execution, synchronize with dynamic page content, and wait for specific elements or text to appear within an adaptive mode BBRE session. The wait(seconds) method introduces a fixed delay, pausing execution for a specified number of seconds before continuing to the next action. The waitForElement(options) method is the core polling-based wait that repeatedly checks the page for an element matching a CSS selector or containing specific text, with configurable timeout, poll interval, visibility requirements, and error handling behavior. The waitForText(text, timeout) method is a convenience wrapper around waitForElement() that waits for an element containing the specified text to appear on the page. The waitForSelector(selector, timeout) method is another convenience wrapper that waits for an element matching a CSS selector to appear. Together, these four methods form the synchronization layer of the BrowserAPI, enabling you to build reliable automation workflows that adapt to varying page load times, asynchronous content rendering, AJAX responses, and dynamic UI updates. Without proper wait strategies, automation scripts frequently fail because they attempt to interact with elements that have not yet appeared on the page. This page provides complete documentation for every wait method, including method signatures, parameter tables, return types, detailed explanations of the polling mechanism, practical code examples covering post-navigation waits, form submission verification, dynamic content loading, AJAX response handling, and conditional element detection, along with best practices, common issues, and links to related documentation.

Adaptive Mode Required

All BrowserAPI wait methods require an active session running in adaptive mode. Adaptive mode sessions launch a real browser instance managed by the BBRE engine, which is necessary for polling the live DOM, detecting element visibility, and monitoring text content changes on the page. If you attempt to call wait methods on a passive mode session, the operation will fail with a BROWSER_ACTION_FAILED error. Create your session with mode: "adaptive" to use these methods. For simple HTTP requests where you only need the raw response without browser rendering, consider using passive mode with session.request() instead, which is faster and consumes fewer credits.

Understanding the Polling Mechanism

The waitForElement() method and its convenience wrappers (waitForText() and waitForSelector()) use a polling-based approach to detect elements on the page. Instead of blocking until an event fires, the method repeatedly queries the DOM at a configurable interval (pollInterval, default 0.3 seconds) until the target element is found or the timeout expires. This polling approach works reliably across all types of dynamic content loading, including server-side rendering delays, client-side JavaScript execution, AJAX responses, WebSocket updates, and CSS transitions that reveal hidden elements. The default timeout of 30 seconds and poll interval of 0.3 seconds provide a good balance between responsiveness and resource efficiency for most use cases.

session.browser.wait(seconds)

The wait() method introduces a fixed delay, pausing execution for the specified number of seconds before the next action runs. It sends a wait action to the BBRE engine, which holds the browser idle for the given duration. The method accepts either a plain number representing seconds or an object with a seconds property. If no value is provided or the value is not a valid number, the method defaults to a 1-second delay. Fixed waits are useful when you need a brief pause between rapid interactions to let animations complete, when you want to simulate human-like browsing behavior with natural delays between actions, or when you need to give a page time to settle after a complex state change that does not produce a reliable DOM indicator. However, fixed waits should be used sparingly because they always consume the full duration regardless of whether the page is ready sooner. Prefer waitForElement(), waitForText(), or waitForSelector() when you can identify a specific element or text that signals readiness, as these methods return as soon as the condition is met rather than waiting the full duration.

Method Signature

JavaScript
await session.browser.wait(seconds);

await session.browser.wait({ seconds: 2 });

Parameters

The wait() method accepts a single parameter that specifies the delay duration. You can pass either a number directly or an object with a seconds property. If the parameter is omitted or invalid, the method defaults to a 1-second delay.

Parameter Type Required Description
seconds number | object Optional The number of seconds to wait. Pass a number directly (e.g., 2) or an object with a seconds property (e.g., { seconds: 2 }). Defaults to 1 second if omitted or if the value is not a valid number.

Return Type

The method returns a Promise that resolves to the action result object from the BBRE engine after the specified delay has elapsed. The return value itself is rarely used directly; the primary purpose of calling wait() is the side effect of pausing execution.

Return Type Description
Promise<object> The raw action result from the BBRE engine. The return value is typically not used; the method is called for its delay side effect.

Basic Fixed Delay

The simplest usage of wait() pauses execution for a specified number of seconds. This is useful when you need a brief pause between actions to let the page settle or to simulate natural browsing behavior.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function basicWaitExample() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://example.com");

    await session.browser.wait(2);

    const title = await session.browser.getTitle();
    console.log("Page title after 2 second wait:", title);
  } finally {
    await session.close();
  }
}

basicWaitExample();

Wait with Object Parameter

You can also pass an object with a seconds property instead of a plain number. This format is useful when constructing wait parameters dynamically or when you want the code to be more self-documenting about what the numeric value represents.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitWithObjectParam() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://example.com/dashboard");

    await session.browser.wait({ seconds: 3 });

    const url = await session.browser.getUrl();
    console.log("Current URL after wait:", url);
  } finally {
    await session.close();
  }
}

waitWithObjectParam();

Simulate Human Browsing Delays

When automating interactions on websites that monitor user behavior patterns, adding natural delays between actions helps your session appear more like a real human user. Combine wait() with varying delay durations between navigation, clicks, and form fills to create a realistic browsing rhythm.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function humanLikeBrowsing() {
  const session = await client.createSession({
    mode: "adaptive",
    sensibility: "high"
  });

  try {
    await session.start();

    await session.browser.navigate("https://shop.example.com");
    await session.browser.wait(2);

    await session.browser.click(".category-electronics");
    await session.browser.wait(1.5);

    await session.browser.click(".product-card:first-child a");
    await session.browser.wait(3);

    const productName = await session.browser.getText("h1.product-title");
    const price = await session.browser.getText(".product-price");
    console.log("Viewed product:", productName, "Price:", price);

    await session.browser.wait(1);
    await session.browser.click("#add-to-cart");
    await session.browser.wait(2);

    console.log("Product added to cart with human-like delays");
  } finally {
    await session.close();
  }
}

humanLikeBrowsing();

session.browser.waitForElement(options)

The waitForElement() method is the core wait method in the BrowserAPI. It polls the page at regular intervals, checking for an element that matches the specified criteria until the element is found or the timeout expires. You can search for elements by text content, by CSS selector, or by both. The method accepts either a plain string (which is treated as a text search) or an options object with full control over the search criteria, timing, visibility requirements, and error handling behavior. When the element is found within the timeout period, the method resolves with the action result. When the timeout expires without finding the element, the behavior depends on the throwOnTimeout option: if set to true, the method throws an error; if set to false (the default), it resolves silently, allowing your code to continue and handle the missing element through conditional logic. The polling mechanism checks the page every pollInterval seconds (default 0.3), which means the method can detect elements that appear asynchronously due to AJAX responses, JavaScript rendering, CSS transitions, or server-sent events. This method is the foundation that waitForText() and waitForSelector() are built upon, and understanding its full parameter set gives you maximum flexibility for handling complex wait scenarios.

Method Signature

JavaScript
const result = await session.browser.waitForElement("Loading complete");

const result = await session.browser.waitForElement({
  text: "Loading complete",
  selector: ".status-message",
  timeout: 15,
  pollInterval: 0.5,
  visible: true,
  throwOnTimeout: false
});

Parameters

The waitForElement() method accepts either a string or an options object. When you pass a string, it is treated as the text parameter with all other options set to their defaults. When you pass an object, you can configure every aspect of the wait behavior.

String Parameter (Shorthand)

When a string is passed, the method searches for an element containing that text with a 30-second timeout, 0.3-second poll interval, visibility required, and no error thrown on timeout.

Parameter Type Required Description
options string Required The text content to search for on the page. Equivalent to passing { text: options, timeout: 30, pollInterval: 0.3, visible: true, throwOnTimeout: false }.

Object Parameter (Full Options)

Parameter Type Required Description
text string Optional The text content to search for on the page. The method looks for any element whose visible text contains this string. Either text or selector (or both) should be provided.
selector string Optional A CSS selector to match against elements on the page. The method looks for any element matching this selector. Either text or selector (or both) should be provided.
timeout number Optional Maximum number of seconds to wait before giving up. The method polls the page repeatedly until this duration expires. Default: 30 seconds.
pollInterval number Optional The interval in seconds between each poll attempt. Lower values detect elements faster but generate more requests to the BBRE engine. Default: 0.3 seconds.
visible boolean Optional When true, the method only matches elements that are visible on the page (not hidden by CSS display: none, visibility: hidden, or zero dimensions). When false, hidden elements also match. Default: true.
throwOnTimeout boolean Optional When true, the method throws an error if the element is not found within the timeout period. When false, the method resolves silently on timeout, allowing your code to handle the missing element through conditional logic. Default: false.

Return Type

The method returns a Promise that resolves to the action result object from the BBRE engine. When the element is found, the result contains information about the matched element. When the timeout expires and throwOnTimeout is false, the result may indicate that no element was found. When throwOnTimeout is true and the timeout expires, the Promise is rejected with an error.

Return Type Description
Promise<object> The action result from the BBRE engine. Contains information about the matched element when found, or a timeout indication when the element was not found within the specified duration.

Wait for Element by Text

The simplest usage of waitForElement() passes a string to wait for an element containing specific text. This is ideal for waiting for success messages, status updates, or any text that appears dynamically after an action.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForSuccessMessage() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/settings");

    await session.browser.fill("#display-name", "Alice Developer");
    await session.browser.click("#save-settings");

    await session.browser.waitForElement("Settings saved successfully");

    console.log("Settings were saved successfully");
  } finally {
    await session.close();
  }
}

waitForSuccessMessage();

Wait for Element by CSS Selector

Pass an options object with a selector property to wait for an element matching a CSS selector. This is useful when you know the element's class name or ID but not its text content, such as waiting for a loading spinner to disappear or a data table to render.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForDataTable() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://dashboard.example.com/reports");

    await session.browser.waitForElement({
      selector: ".report-table tbody tr",
      timeout: 20
    });

    const firstRowText = await session.browser.getText(".report-table tbody tr:first-child");
    console.log("First report row:", firstRowText);
  } finally {
    await session.close();
  }
}

waitForDataTable();

Custom Timeout and Poll Interval

For pages that take longer to load or for time-sensitive operations, customize the timeout and pollInterval values. A shorter poll interval detects elements faster but generates more polling requests. A longer timeout accommodates slow-loading pages but delays failure detection.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitWithCustomTiming() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://analytics.example.com/generate-report");

    await session.browser.click("#generate-report-btn");

    await session.browser.waitForElement({
      selector: ".report-ready-indicator",
      timeout: 60,
      pollInterval: 1
    });

    console.log("Report generation completed");

    const downloadLink = await session.browser.getText(".report-download-link");
    console.log("Download link:", downloadLink);
  } finally {
    await session.close();
  }
}

waitWithCustomTiming();

Using throwOnTimeout for Strict Waits

Set throwOnTimeout: true when the element is absolutely required for your workflow to continue. This causes the method to throw an error if the element is not found within the timeout, which you can catch in a try-catch block to handle the failure explicitly. This is preferable to silent timeouts when a missing element indicates a critical failure such as a page not loading, a server error, or an authentication redirect.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function strictWaitExample() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/login");

    await session.browser.fill("#email", "[email protected]");
    await session.browser.fill("#password", "securepassword");
    await session.browser.click("#login-button");

    try {
      await session.browser.waitForElement({
        selector: ".dashboard-container",
        timeout: 15,
        throwOnTimeout: true
      });
      console.log("Login successful, dashboard loaded");
    } catch (error) {
      console.log("Login failed or dashboard did not load:", error.message);

      const currentUrl = await session.browser.getUrl();
      console.log("Current URL:", currentUrl);

      const errorText = await session.browser.getText(".error-message");
      if (errorText) {
        console.log("Error message on page:", errorText);
      }
    }
  } finally {
    await session.close();
  }
}

strictWaitExample();

Wait for Hidden Elements with visible: false

By default, waitForElement() only matches visible elements. Set visible: false to also match elements that exist in the DOM but are hidden by CSS. This is useful when you need to detect that an element has been added to the DOM even if it is not yet visible, such as a modal that is rendered but not yet displayed, or a hidden input field that gets populated by JavaScript.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForHiddenElement() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/checkout");

    await session.browser.waitForElement({
      selector: "#payment-token",
      visible: false,
      timeout: 20
    });

    console.log("Payment token element has been injected into the DOM");

    const html = await session.browser.getHtml();
    console.log("Page is ready for payment processing");
  } finally {
    await session.close();
  }
}

waitForHiddenElement();

Combine Text and Selector for Precise Matching

When you need to wait for a specific element that contains specific text, provide both text and selector in the options object. The method will only match elements that satisfy both criteria, which is useful when the same text appears in multiple places on the page but you only care about a specific container.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForSpecificElement() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/orders");

    await session.browser.waitForElement({
      text: "Order Confirmed",
      selector: ".order-status-badge",
      timeout: 30
    });

    console.log("Order confirmation badge appeared");

    const orderNumber = await session.browser.getText(".order-number");
    console.log("Order number:", orderNumber);
  } finally {
    await session.close();
  }
}

waitForSpecificElement();

session.browser.waitForText(text, timeout)

The waitForText() method is a convenience wrapper around waitForElement() that waits for an element containing the specified text to appear on the page. Internally, it calls waitForElement({ text, timeout }) with all other options set to their defaults (pollInterval: 0.3, visible: true, throwOnTimeout: false). This method provides a clean, readable syntax for the most common wait scenario: waiting for a specific piece of text to appear after an action such as a form submission, page navigation, or AJAX request. The text parameter is matched against the visible text content of elements on the page, so the method will find the text regardless of which HTML element contains it. Use waitForText() when you know what text will appear but do not know or care about the specific CSS selector of the element that will contain it. For more control over the wait behavior, use waitForElement() directly with the full options object.

Method Signature

JavaScript
const result = await session.browser.waitForText(text, timeout);

Parameters

Parameter Type Required Description
text string Required The text content to wait for on the page. The method polls the page until an element containing this text is found or the timeout expires.
timeout number Optional Maximum number of seconds to wait before giving up. Default: 30 seconds.

Return Type

Return Type Description
Promise<object> The action result from the BBRE engine, delegated from waitForElement(). Contains information about the matched element when found.

Wait for Success Message After Form Submission

After submitting a form, use waitForText() to wait for the confirmation message to appear before proceeding. This ensures that the server has processed the submission and the page has updated with the result.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function submitFormAndWaitForConfirmation() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/contact");

    await session.browser.fill("#name", "Alice Developer");
    await session.browser.fill("#email", "[email protected]");
    await session.browser.fill("#message", "I have a question about your API pricing.");
    await session.browser.click("#submit-contact-form");

    await session.browser.waitForText("Thank you for your message");

    console.log("Contact form submitted successfully");
  } finally {
    await session.close();
  }
}

submitFormAndWaitForConfirmation();

Wait for Error Message with Custom Timeout

When testing error scenarios or validating form input, use waitForText() with a shorter timeout to quickly detect error messages without waiting the full default 30 seconds.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function detectValidationError() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/register");

    await session.browser.fill("#email", "invalid-email-format");
    await session.browser.click("#register-button");

    await session.browser.waitForText("Please enter a valid email address", 10);

    console.log("Validation error detected as expected");

    const errorText = await session.browser.getText(".form-error");
    console.log("Full error message:", errorText);
  } finally {
    await session.close();
  }
}

detectValidationError();

Wait for Dynamic Content After AJAX Request

Many modern web applications load content asynchronously via AJAX requests triggered by user interactions. Use waitForText() to wait for the AJAX response content to appear on the page before extracting data.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForSearchResults() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://search.example.com");

    await session.browser.fill("#search-input", "web automation tools");
    await session.browser.click("#search-button");

    await session.browser.waitForText("results found", 20);

    const resultCount = await session.browser.getText(".result-count");
    console.log("Search results:", resultCount);

    const firstResult = await session.browser.getText(".search-result:first-child .title");
    console.log("First result:", firstResult);
  } finally {
    await session.close();
  }
}

waitForSearchResults();

session.browser.waitForSelector(selector, timeout)

The waitForSelector() method is a convenience wrapper around waitForElement() that waits for an element matching a CSS selector to appear on the page. Internally, it calls waitForElement({ selector, timeout }) with all other options set to their defaults (pollInterval: 0.3, visible: true, throwOnTimeout: false). This method provides a clean, readable syntax for the common scenario of waiting for a specific element to appear in the DOM after a page load, navigation, or dynamic content update. The selector parameter supports all standard CSS selector syntax including class selectors, ID selectors, attribute selectors, pseudo-selectors, and compound selectors. Use waitForSelector() when you know the CSS selector of the element you are waiting for but do not need to match against text content. For text-based matching, use waitForText() instead. For full control over all wait parameters, use waitForElement() directly.

Method Signature

JavaScript
const result = await session.browser.waitForSelector(selector, timeout);

Parameters

Parameter Type Required Description
selector string Required A CSS selector string that identifies the element to wait for. Supports class selectors (.product-list), ID selectors (#main-content), attribute selectors ([data-loaded="true"]), and compound selectors (.container .item:first-child).
timeout number Optional Maximum number of seconds to wait before giving up. Default: 30 seconds.

Return Type

Return Type Description
Promise<object> The action result from the BBRE engine, delegated from waitForElement(). Contains information about the matched element when found.

Wait for Page Content After Navigation

After navigating to a new page, use waitForSelector() to wait for the main content area to render before interacting with the page. This is the most reliable way to ensure the page has fully loaded, especially for single-page applications that render content asynchronously.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForPageContent() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://shop.example.com/products");

    await session.browser.waitForSelector(".product-grid");

    const title = await session.browser.getTitle();
    console.log("Page loaded:", title);

    const firstProduct = await session.browser.getText(".product-card:first-child .product-name");
    console.log("First product:", firstProduct);
  } finally {
    await session.close();
  }
}

waitForPageContent();

Wait for Modal or Popup to Appear

When clicking a button triggers a modal dialog or popup, use waitForSelector() to wait for the modal container to appear before interacting with its contents. Modals are often rendered with a short animation delay, so waiting for the selector ensures the modal is fully visible.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function interactWithModal() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/dashboard");

    await session.browser.click("#create-project-btn");

    await session.browser.waitForSelector(".modal-dialog.show", 10);

    await session.browser.fill(".modal-dialog #project-name", "My New Project");
    await session.browser.select(".modal-dialog #project-type", "web-application");
    await session.browser.click(".modal-dialog #confirm-create");

    await session.browser.waitForText("Project created successfully");
    console.log("Project created via modal dialog");
  } finally {
    await session.close();
  }
}

interactWithModal();

Wait for Table Data to Load

Data tables on dashboards and admin panels often load their rows asynchronously via API calls. Use waitForSelector() to wait for the table body to contain at least one row before extracting data.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function extractTableData() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://admin.example.com/users");

    await session.browser.waitForSelector("table.user-table tbody tr", 15);

    const totalUsers = await session.browser.getText(".total-count");
    console.log("Total users:", totalUsers);

    const firstUserName = await session.browser.getText("table.user-table tbody tr:first-child td:nth-child(1)");
    const firstUserEmail = await session.browser.getText("table.user-table tbody tr:first-child td:nth-child(2)");
    console.log("First user:", firstUserName, firstUserEmail);
  } finally {
    await session.close();
  }
}

extractTableData();

Wait Patterns for Common Scenarios

Choosing the right wait strategy is one of the most important decisions in browser automation. The wrong approach leads to flaky scripts that fail intermittently due to timing issues, while the right approach produces reliable workflows that adapt to varying network conditions and server response times. This section covers the most common scenarios where wait methods are needed and the recommended patterns for each.

Pattern 1: Wait After Navigation

After calling navigate(), the browser starts loading the new page, but the DOM may not be fully rendered when the navigate call returns. Always follow a navigation with a wait for a key element that indicates the page content is ready. Choose an element that appears only after the main content has loaded, such as the primary content container, a data table, or a specific heading.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function navigateAndWait() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();

    await session.browser.navigate("https://shop.example.com/products");
    await session.browser.waitForSelector(".product-grid");

    await session.browser.click(".product-card:first-child a");
    await session.browser.waitForSelector(".product-detail-container");

    const productName = await session.browser.getText("h1.product-title");
    const productPrice = await session.browser.getText(".product-price");
    console.log("Product:", productName, "Price:", productPrice);
  } finally {
    await session.close();
  }
}

navigateAndWait();

Pattern 2: Wait After Form Submission

Form submissions typically trigger a server round-trip that results in either a success message, an error message, or a redirect to a new page. Use waitForText() to wait for the expected response message, or use waitForSelector() to wait for a new page element that appears after the redirect.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function submitFormAndVerify() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/signup");
    await session.browser.waitForSelector("#signup-form");

    await session.browser.fill("#username", "newuser2024");
    await session.browser.fill("#email", "[email protected]");
    await session.browser.fill("#password", "SecurePass123");
    await session.browser.fill("#confirm-password", "SecurePass123");
    await session.browser.checkbox("#terms-agreement", true);
    await session.browser.click("#create-account-btn");

    await session.browser.waitForText("Welcome to your new account", 20);

    const welcomeMessage = await session.browser.getText(".welcome-banner h2");
    console.log("Registration successful:", welcomeMessage);
  } finally {
    await session.close();
  }
}

submitFormAndVerify();

Pattern 3: Wait for Dynamic Content Loading

Single-page applications and JavaScript-heavy websites often load content dynamically after the initial page render. This includes product listings loaded via API calls, comments sections that render asynchronously, and dashboard widgets that fetch data independently. Use waitForSelector() to wait for the container element that holds the dynamic content.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForDynamicContent() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://dashboard.example.com");

    await session.browser.waitForSelector(".revenue-chart canvas", 15);
    console.log("Revenue chart loaded");

    await session.browser.waitForSelector(".recent-orders-table tbody tr", 15);
    console.log("Recent orders table loaded");

    await session.browser.waitForSelector(".notification-badge", 10);
    console.log("Notification badge loaded");

    const revenue = await session.browser.getText(".revenue-total");
    const orderCount = await session.browser.getText(".order-count");
    console.log("Revenue:", revenue, "Orders:", orderCount);
  } finally {
    await session.close();
  }
}

waitForDynamicContent();

Pattern 4: Wait for AJAX Response Indicators

When a user action triggers an AJAX request (such as clicking a filter, sorting a table, or loading more items), the page typically shows a loading indicator and then replaces it with the response content. Wait for the response content to appear rather than waiting for the loading indicator to disappear, as this is more reliable and directly confirms that the data has arrived.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForAjaxResponse() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://shop.example.com/products");
    await session.browser.waitForSelector(".product-grid");

    await session.browser.click(".filter-category[data-category='electronics']");

    await session.browser.waitForSelector(".product-grid[data-filtered='true']", 15);

    const resultCount = await session.browser.getText(".filter-result-count");
    console.log("Filtered results:", resultCount);
  } finally {
    await session.close();
  }
}

waitForAjaxResponse();

Pattern 5: Conditional Wait with Fallback

Sometimes you need to wait for one of several possible outcomes. For example, after submitting a login form, the page might show a success redirect or an error message. Use waitForElement() with a short timeout and throwOnTimeout: false to check for each possible outcome sequentially, or use the default silent timeout behavior to implement conditional logic.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function loginWithConditionalWait() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/login");

    await session.browser.fill("#email", "[email protected]");
    await session.browser.fill("#password", "mypassword");
    await session.browser.click("#login-button");

    await session.browser.waitForElement({
      selector: ".dashboard-container, .login-error",
      timeout: 15
    });

    const currentUrl = await session.browser.getUrl();

    if (currentUrl.includes("/dashboard")) {
      console.log("Login successful, redirected to dashboard");
      const userName = await session.browser.getText(".user-display-name");
      console.log("Logged in as:", userName);
    } else {
      const errorMessage = await session.browser.getText(".login-error");
      console.log("Login failed:", errorMessage);
    }
  } finally {
    await session.close();
  }
}

loginWithConditionalWait();

Pattern 6: Sequential Waits in Multi-Step Workflows

Complex automation workflows involve multiple steps where each step depends on the previous one completing successfully. Chain wait calls between each step to ensure that the page is in the expected state before proceeding. This pattern is essential for checkout flows, multi-page forms, and wizard-style interfaces.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function multiStepCheckout() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();

    await session.browser.navigate("https://shop.example.com/cart");
    await session.browser.waitForSelector(".cart-items");
    console.log("Step 1: Cart loaded");

    await session.browser.click("#proceed-to-checkout");
    await session.browser.waitForSelector("#shipping-form");
    console.log("Step 2: Shipping form loaded");

    await session.browser.fill("#address", "123 Main Street");
    await session.browser.fill("#city", "San Francisco");
    await session.browser.fill("#zip", "94102");
    await session.browser.click("#continue-to-payment");
    await session.browser.waitForSelector("#payment-form");
    console.log("Step 3: Payment form loaded");

    await session.browser.fill("#card-number", "4111111111111111");
    await session.browser.fill("#expiry", "12/25");
    await session.browser.fill("#cvv", "123");
    await session.browser.click("#place-order");
    await session.browser.waitForText("Order Confirmed", 30);
    console.log("Step 4: Order confirmed");

    const orderNumber = await session.browser.getText(".order-number");
    console.log("Order number:", orderNumber);
  } finally {
    await session.close();
  }
}

multiStepCheckout();

Choosing Between wait() and waitForElement()

One of the most common mistakes in browser automation is overusing fixed delays with wait() instead of using condition-based waits with waitForElement(), waitForText(), or waitForSelector(). Understanding when to use each approach is critical for building reliable and efficient automation scripts.

When to Use wait()

Fixed delays with wait() are appropriate in a limited set of scenarios where there is no reliable DOM indicator to wait for. These include: waiting for CSS animations or transitions to complete before taking a screenshot, adding human-like delays between rapid interactions on websites that detect automated behavior, giving a page time to settle after a complex state change that does not produce a detectable DOM change, and rate-limiting your interactions to avoid overwhelming a target server.

JavaScript
await session.browser.click("#expand-details");
await session.browser.wait(0.5);
await session.browser.screenshot({ path: "expanded-details.png" });

When to Use waitForElement() / waitForText() / waitForSelector()

Condition-based waits should be your default choice for almost every wait scenario. They return as soon as the condition is met, making your scripts both faster and more reliable. Use them after navigation to wait for page content, after form submissions to wait for confirmation messages, after clicking buttons that trigger AJAX requests, and before extracting data from dynamically loaded content.

JavaScript
await session.browser.click("#load-more-products");
await session.browser.waitForSelector(".product-card:nth-child(21)");
const newProducts = await session.browser.getText(".product-count");
console.log("Products loaded:", newProducts);

Comparison Table

Aspect wait() waitForElement() / waitForText() / waitForSelector()
Behavior Always waits the full specified duration Returns immediately when the condition is met
Speed Slower (always consumes full delay) Faster (returns as soon as element appears)
Reliability May be too short or too long depending on conditions Adapts to actual page load time automatically
Use Case Animations, human-like delays, rate limiting Page loads, AJAX responses, dynamic content, form results
Failure Mode No failure detection (always succeeds) Detects when element does not appear (timeout)

Advanced Wait Techniques

Beyond the basic wait patterns, there are several advanced techniques that help you handle complex scenarios such as waiting for content to disappear, implementing retry logic with waits, and building reusable wait utilities for your automation projects.

Wait for Loading Indicator to Disappear

Many websites show a loading spinner or skeleton screen while content is being fetched. Instead of waiting for the spinner to disappear (which requires polling for absence), wait for the actual content to appear. This is more reliable because it directly confirms that the data has loaded rather than inferring it from the absence of a loading indicator.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForContentNotSpinner() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://dashboard.example.com/analytics");

    await session.browser.waitForSelector(".analytics-data-loaded", 30);

    const totalVisitors = await session.browser.getText(".visitor-count");
    const bounceRate = await session.browser.getText(".bounce-rate");
    console.log("Visitors:", totalVisitors, "Bounce rate:", bounceRate);
  } finally {
    await session.close();
  }
}

waitForContentNotSpinner();

Retry Pattern with Wait

For operations that may fail intermittently due to network issues or server load, combine wait methods with a retry loop. Each retry attempt navigates to the page, waits for the expected content, and either succeeds or catches the timeout and retries.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function retryWithWait(session, url, selector, maxRetries) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    console.log("Attempt", attempt, "of", maxRetries);

    await session.browser.navigate(url);

    try {
      await session.browser.waitForElement({
        selector: selector,
        timeout: 10,
        throwOnTimeout: true
      });
      console.log("Element found on attempt", attempt);
      return true;
    } catch (error) {
      console.log("Attempt", attempt, "timed out");
      if (attempt < maxRetries) {
        await session.browser.wait(2);
      }
    }
  }

  console.log("All", maxRetries, "attempts failed");
  return false;
}

async function runWithRetry() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    const success = await retryWithWait(
      session,
      "https://api.example.com/status",
      ".status-healthy",
      3
    );

    if (success) {
      const statusText = await session.browser.getText(".status-message");
      console.log("Service status:", statusText);
    }
  } finally {
    await session.close();
  }
}

runWithRetry();

Wait for Multiple Elements Sequentially

When a page loads multiple independent sections asynchronously, wait for each section individually to ensure all required data is available before extraction. This is common on dashboard pages where different widgets fetch data from different API endpoints.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function waitForAllDashboardWidgets() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://dashboard.example.com");

    const widgets = [
      { selector: ".sales-widget .data-loaded", name: "Sales" },
      { selector: ".traffic-widget .data-loaded", name: "Traffic" },
      { selector: ".orders-widget .data-loaded", name: "Orders" },
      { selector: ".inventory-widget .data-loaded", name: "Inventory" }
    ];

    for (const widget of widgets) {
      await session.browser.waitForSelector(widget.selector, 15);
      console.log(widget.name, "widget loaded");
    }

    console.log("All dashboard widgets loaded successfully");

    const salesTotal = await session.browser.getText(".sales-widget .total");
    const trafficCount = await session.browser.getText(".traffic-widget .count");
    console.log("Sales:", salesTotal, "Traffic:", trafficCount);
  } finally {
    await session.close();
  }
}

waitForAllDashboardWidgets();

Error Handling with Wait Methods

Proper error handling around wait methods is essential for building robust automation scripts. The default behavior of waitForElement() (and its wrappers) is to resolve silently on timeout, which means your code continues executing even when the expected element was not found. This section covers strategies for handling both silent timeouts and thrown errors effectively.

Handling Silent Timeouts

When throwOnTimeout is false (the default), the method resolves without throwing an error even if the element was not found. To detect this case, check the page state after the wait by verifying the URL, checking for the expected element with find(), or reading text content.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function handleSilentTimeout() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/slow-page");

    await session.browser.waitForSelector(".main-content", 10);

    const pageTitle = await session.browser.getTitle();
    const currentUrl = await session.browser.getUrl();

    if (currentUrl.includes("/slow-page") && pageTitle.includes("Content")) {
      console.log("Page loaded successfully");
      const data = await session.browser.getText(".main-content");
      console.log("Content:", data);
    } else {
      console.log("Page may not have loaded correctly");
      console.log("Current URL:", currentUrl);
      console.log("Page title:", pageTitle);
    }
  } finally {
    await session.close();
  }
}

handleSilentTimeout();

Handling Thrown Timeout Errors

When throwOnTimeout is true, wrap the wait call in a try-catch block to handle the timeout error gracefully. The error message will indicate that the wait timed out, and you can use this information to log the failure, take a screenshot for debugging, or attempt an alternative action.

JavaScript
const BBREClient = require("mydisctsolver-bbre");

const client = new BBREClient({ apiKey: "YOUR_API_KEY" });

async function handleThrownTimeout() {
  const session = await client.createSession({ mode: "adaptive" });

  try {
    await session.start();
    await session.browser.navigate("https://app.example.com/data-export");

    await session.browser.click("#start-export");

    try {
      await session.browser.waitForElement({
        text: "Export Complete",
        timeout: 45,
        throwOnTimeout: true
      });
      console.log("Export completed successfully");
    } catch (error) {
      console.log("Export did not complete within 45 seconds");
      console.log("Error:", error.message);

      await session.browser.screenshot({ path: "export-timeout-debug.png" });

      const statusText = await session.browser.getText(".export-status");
      console.log("Current export status:", statusText);
    }
  } finally {
    await session.close();
  }
}

handleThrownTimeout();

Best Practices

Prefer Condition-Based Waits Over Fixed Delays

Always use waitForSelector(), waitForText(), or waitForElement() instead of wait() whenever possible. Condition-based waits return as soon as the element appears, making your scripts both faster and more reliable. A fixed wait(3) always takes 3 seconds even if the element appears in 0.5 seconds, and it provides no guarantee that the element will be present after the delay. Reserve wait() for situations where there is genuinely no DOM indicator to wait for, such as CSS animations, human-like browsing simulation, or rate limiting between rapid interactions.

Choose Meaningful Wait Targets

When selecting what to wait for after a navigation or action, choose an element that directly indicates the content you need is ready. For example, after navigating to a product page, wait for the product price element rather than the page header, because the price is loaded dynamically while the header may appear immediately from the static HTML. Waiting for the right element prevents premature data extraction that returns empty or stale values. The ideal wait target is the last element to load in the section you plan to interact with.

Set Appropriate Timeout Values for Each Scenario

The default 30-second timeout works well for most page loads, but you should adjust it based on the expected response time of each operation. Use shorter timeouts (5 to 10 seconds) for fast operations like form validation messages and modal dialogs. Use the default 30 seconds for standard page navigations and AJAX content loading. Use longer timeouts (45 to 60 seconds) for operations that involve server-side processing such as report generation, file exports, or payment processing. Setting appropriate timeouts improves failure detection speed for fast operations and prevents premature timeouts for slow operations.

Use throwOnTimeout for Critical Wait Points

For wait points where the element is absolutely required for the workflow to continue, set throwOnTimeout: true and wrap the call in a try-catch block. This makes failures explicit and prevents your script from silently continuing with stale or missing data. Critical wait points include: waiting for the login success indicator, waiting for the checkout confirmation page, and waiting for data that will be used in subsequent calculations. For non-critical waits such as optional UI elements or supplementary data, the default silent timeout behavior is appropriate.

Keep pollInterval at the Default Unless You Have a Specific Reason

The default poll interval of 0.3 seconds provides a good balance between responsiveness and efficiency for most scenarios. Lowering it below 0.2 seconds generates excessive polling requests without meaningful improvement in detection speed. Raising it above 1 second introduces noticeable delays between the element appearing and the method returning. Only adjust the poll interval when you have a specific reason: use a longer interval (1 to 2 seconds) for long-running operations like report generation where checking every 0.3 seconds is wasteful, and use a shorter interval (0.1 to 0.2 seconds) for time-critical operations where every fraction of a second matters.

Always Wait Before Extracting Data from Dynamic Pages

Before calling getText(), getHtml(), or find() on a page that loads content dynamically, always insert a wait for the specific element you plan to extract data from. This is the single most effective way to prevent empty or incomplete data extraction. The pattern is simple: navigate, wait for the target element, then extract. Skipping the wait step is the most common cause of intermittent failures in browser automation scripts.

Common Issues

waitForSelector() Times Out Even Though the Element Exists

Symptom: You call waitForSelector() with a selector that you can see in the browser DevTools, but the method times out without finding the element.
Cause: The element exists in the DOM but is hidden by CSS (display: none, visibility: hidden, or zero dimensions). By default, waitForElement() only matches visible elements because the visible option defaults to true. Another common cause is that the selector contains a typo or uses a class name that has changed since you last inspected the page.
Solution: If the element is intentionally hidden, use waitForElement({ selector: ".my-element", visible: false }) to match hidden elements. If the element should be visible, verify the selector by inspecting the live page and checking for dynamically generated class names. Try a simpler selector first (such as a tag name or ID) to confirm that the element is detectable, then refine the selector.

waitForText() Does Not Find Text That Is Visible on the Page

Symptom: You call waitForText() with text that you can clearly see on the page, but the method times out.
Cause: The visible text may differ from what you expect due to extra whitespace, line breaks, non-breaking spaces, or Unicode characters that look identical but have different character codes. Some websites also render text using CSS pseudo-elements (::before, ::after) or background images that display text visually but are not part of the DOM text content.
Solution: Try using a shorter, more distinctive substring of the text. For example, instead of waiting for "Your order has been placed successfully!", try waiting for "order has been placed". If the text is rendered via CSS or images, use waitForSelector() with the element's CSS selector instead of waitForText().

Wait Methods Fail with BROWSER_ACTION_FAILED on Passive Mode Sessions

Symptom: Calling any wait method throws an error with the code BROWSER_ACTION_FAILED.
Cause: The session was created in passive mode, which does not launch a browser instance. All BrowserAPI methods, including wait methods, require an adaptive mode session with an active browser. Passive mode sessions can only use session.request() for HTTP requests.
Solution: Create the session with mode: "adaptive": const session = await client.createSession({ mode: "adaptive" });. If you do not need browser automation and only need HTTP responses, use passive mode with session.request() instead, which is faster and consumes fewer credits.

Script Continues After waitForElement() Without Finding the Element

Symptom: Your script calls waitForElement() or waitForSelector(), and the subsequent code executes even though the element was never found, leading to empty data extraction or failed interactions.
Cause: The default value of throwOnTimeout is false, which means the method resolves silently when the timeout expires without finding the element. Your code continues executing as if the element was found.
Solution: For critical wait points where the element must be present, set throwOnTimeout: true and wrap the call in a try-catch block. Alternatively, after the wait call, verify the page state by checking the URL with getUrl() or attempting to read the element with getText() before proceeding.

wait() Does Not Accept Decimal Values Correctly

Symptom: You pass a decimal value like wait(0.5) but the actual delay seems different from what you expected.
Cause: The wait() method passes the seconds value to the BBRE engine, which handles the actual timing. The precision of the delay depends on the engine's internal timer resolution and network latency between the SDK and the engine. Very small values (below 0.1 seconds) may not produce accurate delays due to these factors.
Solution: Use values of 0.5 seconds or higher for reliable delays. For sub-second precision, the actual delay will be approximate. If you need precise timing control, use waitForElement() with a specific condition instead of relying on fixed delays.