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.
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.
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
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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
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.
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().
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.
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.
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.