BrowserAPI Navigation Methods
The BrowserAPI class exposes five navigation methods through the
session.browser interface that give you full control over page navigation
within an adaptive mode BBRE session. The navigate(url, options) method
loads a new URL in the browser with configurable wait conditions and timeout values,
making it the primary way to move between pages. The goto(url, options)
method is a convenience alias for navigate() that provides identical
functionality with a shorter name for developers who prefer that syntax. The
reload(options) method refreshes the current page with the same wait
condition and timeout options available in navigate(), which is useful
for retrying failed page loads or refreshing dynamic content. The back()
method navigates to the previous page in the browser history stack, simulating a user
clicking the browser back button. The forward() method navigates to the
next page in the browser history stack, simulating a user clicking the browser forward
button. All five navigation methods require an active adaptive mode session because
they operate on a real browser instance managed by the BBRE engine. This page provides
complete documentation for every navigation method, including method signatures,
parameter tables, wait condition explanations, practical code examples covering
multi-page crawling, SPA navigation, redirect handling, and navigation with custom
wait conditions, along with best practices, common issues, and links to related
documentation.
All BrowserAPI navigation 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 navigation, DOM interaction, and
page state management. If you attempt to call navigation 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.
session.browser.goto(url, options)
The goto() method is a convenience alias for navigate(). It
accepts exactly the same parameters, produces exactly the same behavior, and returns
exactly the same result. Internally, goto() simply calls
navigate() with the provided arguments and returns its result. The method
exists to provide a familiar API for developers who are accustomed to browser
automation libraries like Puppeteer and Playwright, where goto() is the
standard method name for URL navigation. You can use goto() and
navigate() interchangeably throughout your code. There is no performance
difference, no behavioral difference, and no reason to prefer one over the other
beyond personal or team coding style preferences.
Method Signature
const result = await session.browser.goto(url, options);
Parameters
The goto() method accepts the same parameters as
navigate(). Refer to the navigate() parameter
table above for complete details on each parameter.
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Required | The full URL to navigate to. Must include the protocol. Identical to the url parameter in navigate(). |
options |
object | Optional | Configuration object with waitUntil and timeout properties. Identical to the options parameter in navigate(). |
options.waitUntil |
string | Optional | Page readiness condition. Accepted values: "load", "domcontentloaded", "networkidle". Defaults to "load". |
options.timeout |
number | Optional | Maximum seconds to wait for the page to reach the readiness state. Defaults to 30. |
Basic Usage
Use goto() exactly as you would use navigate(). The
following example demonstrates basic URL loading with goto().
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function gotoExample() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.goto("https://example.com");
const title = await session.browser.getTitle();
console.log("Page title:", title);
await session.close();
}
gotoExample();
goto() with Options
Just like navigate(), you can pass waitUntil and
timeout options to goto() to control the navigation
behavior.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function gotoWithOptions() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.goto("https://dashboard.example.com", {
waitUntil: "networkidle",
timeout: 45
});
const url = await session.browser.getUrl();
console.log("Current URL:", url);
await session.close();
}
gotoWithOptions();
Interchangeable Usage with navigate()
The following example demonstrates that goto() and
navigate() can be used interchangeably within the same workflow. Both
methods produce identical results and maintain the same browser state.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function mixedNavigation() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/login");
console.log("Navigated to login page using navigate()");
await session.browser.fill("#username", "testuser");
await session.browser.fill("#password", "testpass");
await session.browser.click("#login-button");
await session.browser.goto("https://example.com/dashboard", {
waitUntil: "networkidle"
});
console.log("Navigated to dashboard using goto()");
await session.browser.navigate("https://example.com/settings");
console.log("Navigated to settings using navigate()");
await session.close();
}
mixedNavigation();
session.browser.reload(options)
The reload() method refreshes the current page in the browser. It sends a
reload action to the BBRE engine, which triggers a full page reload of
the currently loaded URL. Like navigate(), the method accepts an optional
options object with waitUntil and timeout
parameters that control when the reload is considered complete and how long to wait
before timing out. The reload() method does not accept a URL parameter
because it always reloads the current page. This method is particularly useful in
several scenarios: retrying a page load that returned incomplete or stale content,
refreshing a page after submitting a form to see updated data, reloading a page that
uses server-side rendering to get the latest version, and recovering from transient
page load errors where the initial navigation succeeded but the content was not fully
rendered. The browser maintains its current state (cookies, local storage, session
data) across reloads, so any authentication tokens or session cookies set during
previous navigations remain intact.
Method Signature
const result = await session.browser.reload(options);
Parameters
The reload() method accepts an optional options object that controls the
wait condition and timeout for the page reload. If no options are provided, the method
uses the default values of "load" for waitUntil and
30 seconds for timeout.
| Parameter | Type | Required | Description |
|---|---|---|---|
options |
object | Optional | Configuration object for the reload behavior. Contains waitUntil and timeout properties. |
options.waitUntil |
string | Optional | The page readiness condition to wait for after the reload. Accepted values: "load", "domcontentloaded", "networkidle". Defaults to "load". |
options.timeout |
number | Optional | Maximum number of seconds to wait for the page to finish reloading. Defaults to 30. |
Basic Reload
The simplest usage of reload() refreshes the current page with default
options. The browser waits for the load event with a 30-second timeout.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function basicReload() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/dashboard");
console.log("Initial page loaded");
await session.browser.reload();
console.log("Page reloaded successfully");
const title = await session.browser.getTitle();
console.log("Page title after reload:", title);
await session.close();
}
basicReload();
Reload After Form Submission
After submitting a form that modifies server-side data, you may need to reload the page to see the updated content. This pattern is common in admin panels, content management systems, and any application where form submissions trigger server-side changes that are reflected on the same page.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function reloadAfterFormSubmission() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://admin.example.com/settings");
await session.browser.fill("#company-name", "Acme Corporation");
await session.browser.fill("#contact-email", "[email protected]");
await session.browser.click("#save-settings");
await session.browser.wait(2);
await session.browser.reload({ waitUntil: "networkidle" });
console.log("Page reloaded with updated settings");
const companyName = await session.browser.getText("#company-name-display");
console.log("Updated company name:", companyName);
await session.close();
}
reloadAfterFormSubmission();
Reload with Retry Logic
When a page load returns incomplete content or encounters a transient error, you can
use reload() as part of a retry strategy. The following example reloads
the page up to a specified number of times until the expected content appears.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function reloadUntilContentReady(session, expectedSelector, maxRetries) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const elements = await session.browser.find(expectedSelector);
if (elements && elements.length > 0) {
console.log("Content found on attempt", attempt);
return true;
}
} catch (error) {
console.log("Attempt", attempt, "- content not found yet");
}
if (attempt < maxRetries) {
console.log("Reloading page, attempt", attempt + 1);
await session.browser.reload({ waitUntil: "networkidle", timeout: 20 });
}
}
console.log("Content not found after", maxRetries, "attempts");
return false;
}
async function main() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/reports");
const found = await reloadUntilContentReady(session, ".report-table tbody tr", 3);
if (found) {
const text = await session.browser.getText(".report-table");
console.log("Report data:", text);
}
await session.close();
}
main();
Reload for Dynamic Content Refresh
Some web applications display real-time data that changes frequently, such as stock
prices, order statuses, or live dashboards. Use reload() to periodically
refresh the page and capture the latest data.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function monitorDynamicContent() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://trading.example.com/portfolio", {
waitUntil: "networkidle"
});
const snapshots = [];
for (let i = 0; i < 5; i++) {
const portfolioValue = await session.browser.getText("#total-value");
const timestamp = new Date().toISOString();
snapshots.push({ timestamp, value: portfolioValue });
console.log("[" + timestamp + "] Portfolio value:", portfolioValue);
if (i < 4) {
await session.browser.wait(10);
await session.browser.reload({ waitUntil: "networkidle" });
}
}
console.log("Collected", snapshots.length, "snapshots");
await session.close();
return snapshots;
}
monitorDynamicContent();
session.browser.back()
The back() method navigates to the previous page in the browser's history
stack. It simulates a user clicking the browser's back button, moving one step backward
in the navigation history. This method does not accept any parameters. The browser
loads the previous URL from its history and restores the page state as it was when the
user last visited that page. The back() method is useful in automation
workflows where you need to return to a previous page after inspecting or interacting
with a detail page. For example, when crawling a list of items, you might navigate to
each item's detail page, extract data, and then call back() to return to
the list page before clicking the next item. The method relies on the browser's
internal history stack, so it only works if there is a previous page to go back to. If
the browser history is empty (for example, if the current page is the first page
loaded in the session), calling back() will have no effect or may produce
unexpected behavior. Always ensure that your navigation flow has established a history
before calling this method.
Method Signature
const result = await session.browser.back();
Parameters
The back() method does not accept any parameters. It navigates to the
previous page in the browser history stack using the browser's built-in back
navigation mechanism.
| Parameter | Type | Required | Description |
|---|---|---|---|
| This method does not accept any parameters. | |||
Basic Back Navigation
The simplest usage of back() navigates from a detail page back to the
previous page. After calling back(), the browser loads the previous URL
from its history stack.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function basicBackNavigation() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/products");
console.log("On products page");
await session.browser.navigate("https://example.com/products/laptop-pro");
console.log("On product detail page");
await session.browser.back();
console.log("Back on products page");
const url = await session.browser.getUrl();
console.log("Current URL:", url);
await session.close();
}
basicBackNavigation();
List-Detail Crawling Pattern
One of the most common use cases for back() is the list-detail crawling
pattern. In this pattern, you start on a list page, click on each item to visit its
detail page, extract the data you need, and then call back() to return to
the list page before clicking the next item. This approach preserves the list page
state (scroll position, loaded items, pagination) and avoids re-navigating to the list
URL, which would reset any dynamic state.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function listDetailCrawl() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://blog.example.com/articles", {
waitUntil: "networkidle"
});
const articleLinks = await session.browser.find("a.article-link");
const articleCount = articleLinks.length;
console.log("Found", articleCount, "articles");
const articles = [];
for (let i = 0; i < articleCount; i++) {
await session.browser.click("a.article-link:nth-child(" + (i + 1) + ")");
await session.browser.waitForSelector(".article-content");
const title = await session.browser.getText("h1.article-title");
const author = await session.browser.getText(".article-author");
const content = await session.browser.getText(".article-content");
articles.push({ title, author, contentLength: content.length });
console.log("Extracted article:", title);
await session.browser.back();
await session.browser.waitForSelector("a.article-link");
}
console.log("Extracted", articles.length, "articles");
await session.close();
return articles;
}
listDetailCrawl();
Multi-Step Workflow with Back Navigation
In complex workflows that involve navigating through multiple pages, you can use
back() to retrace your steps. This is useful when you need to explore
different branches of a website from a common starting point.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function multiStepWorkflow() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://store.example.com");
console.log("On homepage");
await session.browser.navigate("https://store.example.com/electronics");
const electronicsTitle = await session.browser.getTitle();
console.log("Electronics page:", electronicsTitle);
await session.browser.back();
console.log("Back on homepage");
await session.browser.navigate("https://store.example.com/clothing");
const clothingTitle = await session.browser.getTitle();
console.log("Clothing page:", clothingTitle);
await session.browser.back();
console.log("Back on homepage again");
await session.browser.navigate("https://store.example.com/books");
const booksTitle = await session.browser.getTitle();
console.log("Books page:", booksTitle);
await session.close();
}
multiStepWorkflow();
session.browser.forward()
The forward() method navigates to the next page in the browser's history
stack. It simulates a user clicking the browser's forward button, moving one step
forward in the navigation history. This method does not accept any parameters. The
forward() method is the counterpart to back() and is only
effective when the browser has a forward history entry, which exists after calling
back(). If you navigate to page A, then to page B, then call
back() to return to page A, calling forward() will take you
back to page B. If there is no forward history (for example, if you have not called
back() or if you navigated to a new URL after calling
back()), calling forward() will have no effect. This method
is useful in testing scenarios where you need to verify that forward navigation works
correctly, in workflows where you need to revisit a page you previously backed away
from, and in complex navigation patterns where you alternate between forward and
backward movement through a sequence of pages.
Method Signature
const result = await session.browser.forward();
Parameters
The forward() method does not accept any parameters. It navigates to the
next page in the browser history stack using the browser's built-in forward navigation
mechanism.
| Parameter | Type | Required | Description |
|---|---|---|---|
| This method does not accept any parameters. | |||
Basic Forward Navigation
The simplest usage of forward() moves forward in the browser history
after a back() call. The browser loads the next URL from its forward
history stack.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function basicForwardNavigation() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/page-one");
console.log("On page one");
await session.browser.navigate("https://example.com/page-two");
console.log("On page two");
await session.browser.back();
console.log("Back on page one");
await session.browser.forward();
console.log("Forward to page two again");
const url = await session.browser.getUrl();
console.log("Current URL:", url);
await session.close();
}
basicForwardNavigation();
Back and Forward Navigation Pattern
Combining back() and forward() allows you to move freely
through the browser history. This pattern is useful for testing navigation flows,
verifying page state persistence across history navigation, and building workflows
that need to revisit previously viewed pages without re-fetching them from the server.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function backAndForwardPattern() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://docs.example.com/introduction");
const introTitle = await session.browser.getTitle();
console.log("Step 1:", introTitle);
await session.browser.navigate("https://docs.example.com/getting-started");
const gettingStartedTitle = await session.browser.getTitle();
console.log("Step 2:", gettingStartedTitle);
await session.browser.navigate("https://docs.example.com/api-reference");
const apiRefTitle = await session.browser.getTitle();
console.log("Step 3:", apiRefTitle);
await session.browser.back();
const afterBack1 = await session.browser.getTitle();
console.log("After back():", afterBack1);
await session.browser.back();
const afterBack2 = await session.browser.getTitle();
console.log("After second back():", afterBack2);
await session.browser.forward();
const afterForward1 = await session.browser.getTitle();
console.log("After forward():", afterForward1);
await session.browser.forward();
const afterForward2 = await session.browser.getTitle();
console.log("After second forward():", afterForward2);
await session.close();
}
backAndForwardPattern();
History Navigation for Page Comparison
Use back() and forward() to compare content between two
pages without re-navigating to their URLs. This is useful for verifying that form
submissions changed the page content, comparing before and after states, or validating
that navigation does not lose page data.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function comparePages() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
await session.browser.navigate("https://example.com/pricing/basic");
const basicPrice = await session.browser.getText(".price-value");
const basicFeatures = await session.browser.getText(".features-list");
console.log("Basic plan price:", basicPrice);
await session.browser.navigate("https://example.com/pricing/premium");
const premiumPrice = await session.browser.getText(".price-value");
const premiumFeatures = await session.browser.getText(".features-list");
console.log("Premium plan price:", premiumPrice);
await session.browser.back();
const backToBasicPrice = await session.browser.getText(".price-value");
console.log("Back to basic, price:", backToBasicPrice);
await session.browser.forward();
const forwardToPremiumPrice = await session.browser.getText(".price-value");
console.log("Forward to premium, price:", forwardToPremiumPrice);
console.log("Comparison complete");
console.log("Basic:", basicPrice, "| Premium:", premiumPrice);
await session.close();
}
comparePages();
Error Handling
Navigation methods can fail for various reasons, including network errors, timeout expiration, invalid URLs, and session state issues. Understanding the different error scenarios and implementing appropriate error handling is essential for building reliable automation workflows. The following examples demonstrate how to handle navigation errors gracefully.
Error Types
The following table lists the common errors that can occur during navigation operations, along with their causes and recommended solutions.
| Error | Cause | Solution |
|---|---|---|
BROWSER_ACTION_FAILED |
The navigation action could not be executed by the browser engine. This can happen when the session is not in adaptive mode, the browser instance has crashed, or the session has expired. | Verify that your session is created with mode: "adaptive". Check the session status with session.status() to ensure it is still active. |
| Navigation timeout | The page did not reach the specified waitUntil condition within the timeout period. This commonly occurs with slow servers, heavy pages, or when using "networkidle" on pages with persistent network connections. |
Increase the timeout value, use a less strict waitUntil condition (e.g., "domcontentloaded" instead of "networkidle"), or check if the target server is responding. |
| Invalid URL | The provided URL is malformed, missing the protocol, or points to an unreachable address. | Ensure the URL includes the protocol (https:// or http://) and is a valid, reachable address. Validate URLs before passing them to navigate(). |
| Session expired | The BBRE session has expired due to inactivity or reaching its maximum lifetime. Navigation methods cannot operate on expired sessions. | Check the session status before navigating. If the session has expired, create a new session and restart your workflow. |
| Session closed | The session was explicitly closed with session.close() before the navigation method was called. |
Ensure you do not call navigation methods after closing the session. Structure your code so that session.close() is always the last operation. |
Robust Navigation with Error Recovery
The following example demonstrates a robust navigation function that handles different error types and implements retry logic for transient failures.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function robustNavigate(session, url, options, maxRetries) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await session.browser.navigate(url, options);
const finalUrl = await session.browser.getUrl();
console.log("Navigation successful on attempt", attempt);
console.log("Final URL:", finalUrl);
return { success: true, url: finalUrl, attempts: attempt };
} catch (error) {
lastError = error;
console.log("Attempt", attempt, "failed:", error.message);
const message = error.message.toLowerCase();
if (message.includes("session") && (message.includes("expired") || message.includes("closed"))) {
console.log("Session is no longer active, cannot retry");
return { success: false, error: error.message, recoverable: false };
}
if (attempt < maxRetries) {
const delay = 2000 * attempt;
console.log("Retrying in", delay, "ms");
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
return { success: false, error: lastError.message, attempts: maxRetries, recoverable: true };
}
async function main() {
const session = client.createSession({ mode: "adaptive" });
await session.start();
const result = await robustNavigate(
session,
"https://example.com/data",
{ waitUntil: "networkidle", timeout: 30 },
3
);
if (result.success) {
const title = await session.browser.getTitle();
console.log("Page title:", title);
} else {
console.log("Navigation failed after all retries:", result.error);
}
await session.close();
}
main();
Best Practices
The waitUntil parameter has a significant impact on both reliability
and performance. Use "load" (the default) for standard web pages
where you need all resources including images and stylesheets to be available. Use
"domcontentloaded" when you only need to interact with the DOM
structure and do not depend on images or external resources, as this is faster than
waiting for the full load event. Use "networkidle" for single-page
applications and pages that load content dynamically via JavaScript API calls,
since this ensures all asynchronous data fetching has completed. Avoid using
"networkidle" on pages with persistent WebSocket connections or
long-polling requests, as the network may never become truly idle on those pages.
The default timeout of 30 seconds works well for most pages, but you should adjust it based on the characteristics of the pages you are navigating to. For fast, lightweight pages (API documentation, static sites), reduce the timeout to 10 or 15 seconds to fail fast when something goes wrong. For heavy pages that perform server-side processing (report generators, data dashboards), increase the timeout to 45 or 60 seconds to accommodate longer load times. For pages behind slow networks or geographic proxies, consider even higher timeouts. Always set the timeout to the minimum value that reliably works for your target pages to avoid wasting session time on unresponsive servers.
For pages that load content progressively or render data asynchronously after the
initial page load, use a two-step approach: first call navigate()
with "domcontentloaded" or "load" to get the page
structure loaded, then use waitForSelector() or
waitForText() to wait for the specific content you need before
proceeding. This approach is more reliable than relying solely on
"networkidle" because it targets the exact content your automation
depends on, rather than waiting for all network activity to cease. It also handles
edge cases where the page makes background requests that are unrelated to the
content you need.
After calling navigate(), always use getUrl() to check
the final URL if your workflow depends on being on a specific page. Websites
frequently redirect users based on authentication status, geographic location,
A/B testing groups, or URL normalization rules. By verifying the final URL, you
can detect login redirects early and handle them appropriately, identify geographic
redirects that may serve different content, and catch unexpected redirects that
could break your automation flow. This is especially important for workflows that
navigate to protected pages that require authentication.
When you need to return to a previous page in a list-detail crawling pattern, use
back() instead of calling navigate() with the list page
URL. The back() method restores the page from the browser's history
cache, which preserves the scroll position, loaded dynamic content, and any
client-side state that was present when you left the page. Re-navigating to the
URL would trigger a fresh page load, resetting all dynamic state and potentially
losing pagination position, filter selections, or lazy-loaded content. However,
be aware that some websites may re-fetch data when navigating back, so test this
behavior with your specific target site.
Navigation is one of the most failure-prone operations in browser automation
because it depends on external factors like network connectivity, server
availability, DNS resolution, and page complexity. Always wrap
navigate(), goto(), reload(),
back(), and forward() calls in try-catch blocks. For
critical navigation steps, implement retry logic with increasing delays between
attempts. For non-critical navigation (such as crawling optional pages), log the
error and continue with the next page rather than crashing the entire workflow.
This defensive approach ensures your automation is resilient to transient failures.
When navigating to websites with advanced bot detection systems, create your
session with sensibility: "high" to enable the most thorough
anti-detection measures. High sensibility mode adds realistic delays between
actions, randomizes navigation timing, and applies additional fingerprint
protections that make the browser behavior appear more human-like. While high
sensibility is slower than low or medium, it significantly reduces the chance of
being detected and blocked during navigation. For websites without aggressive bot
detection, sensibility: "medium" or "low" provides
faster navigation with adequate protection.
Common Issues
Symptom: Calling navigate() with
waitUntil: "networkidle" times out even though the page appears to
be fully loaded.
Cause: The page maintains persistent network connections such as
WebSocket connections, long-polling requests, server-sent events, or periodic
heartbeat requests. The "networkidle" condition requires zero active
network connections for 500 milliseconds, which never occurs on pages with
persistent connections.
Solution: Switch to waitUntil: "load" or
"domcontentloaded" and then use
waitForSelector() to wait for the specific content you need. For
example: await session.browser.navigate(url, { waitUntil: "load" });
followed by
await session.browser.waitForSelector(".main-content");
Symptom: Calling any navigation method throws a
BROWSER_ACTION_FAILED error.
Cause: The session was created with mode: "passive"
instead of mode: "adaptive". Passive mode sessions do not launch a
browser instance and therefore cannot execute browser navigation actions. All
BrowserAPI methods, including navigate(), goto(),
reload(), back(), and forward(), require
an adaptive mode session.
Solution: Create your session with
mode: "adaptive":
const session = client.createSession({ mode: "adaptive" });. If you
only need to make HTTP requests without browser interaction, use the passive mode
session's request() method instead of browser navigation.
Symptom: Calling back() does not change the current
URL, and the browser remains on the same page.
Cause: The browser history stack is empty because the current
page is the first page loaded in the session. There is no previous page to
navigate back to. The back() method relies on the browser's internal
history, which only contains entries for pages that were navigated to within the
current session.
Solution: Ensure that you have navigated to at least two pages
before calling back(). Track your navigation history in your
application code if you need to verify that back navigation is possible before
calling the method. Alternatively, use navigate() with the desired
URL instead of relying on back() when the history state is uncertain.
Symptom: After calling back() and then navigating to
a new URL with navigate(), calling forward() does not
return to the page you were on before calling back().
Cause: This is standard browser behavior. When you navigate to a
new URL after calling back(), the forward history is cleared. The
browser replaces the forward history with the new navigation, so there is no
longer a forward entry to navigate to. This is the same behavior you would
experience in a regular browser.
Solution: If you need to return to a specific page after
navigating away, store the URL in a variable and use navigate() to
go back to it directly. Only use forward() when you have called
back() and have not navigated to any new URLs since then.
Symptom: After calling reload(), the page content
appears to be the same as before the reload, even though you expected it to
change.
Cause: The page may be served from the browser cache rather than
being fetched fresh from the server. Some websites set aggressive caching headers
that cause the browser to serve cached content even after a reload. Additionally,
if the page content is generated client-side by JavaScript, the reload may
re-execute the same JavaScript with the same cached data.
Solution: Use waitUntil: "networkidle" with
reload() to ensure the browser waits for all network requests to
complete after the reload. If the content is still cached, try navigating away
from the page and then navigating back to it, or clear the browser cookies with
session.browser.clearCookies() before reloading if the cached
content is tied to cookie-based sessions.
Symptom: Calling navigate("example.com") or
navigate("www.example.com") fails or navigates to an unexpected
location.
Cause: The URL is missing the protocol prefix
(https:// or http://). Without the protocol, the
browser may interpret the URL as a relative path or a search query rather than
an absolute URL.
Solution: Always include the full protocol in your URLs:
await session.browser.navigate("https://example.com");. If you are
working with URLs from external sources, validate and normalize them before
passing them to navigate(). A simple check like
if (!url.startsWith("http")) url = "https://" + url; can prevent
this issue.