Session Lifecycle Methods
The BBRESession class provides three core lifecycle methods that control
the entire lifespan of a browser session on the BBRE engine: start(),
close(), and status(). These methods are the foundation of
every session-based workflow in the mydisctsolver-bbre SDK. The
start() method creates a new server-side browser session, allocates a
dedicated browser instance with its own fingerprint profile and cookie store, and
returns session metadata including the session ID, expiration timestamp, and the
assigned browser profile. The close() method terminates the session,
releases the browser instance, and resets all local session state including the
session ID, expiration timestamp, cookies, and profile data. The status()
method queries the BBRE API for the current state of the active session, returning
real-time information about whether the session is still alive, when it expires, and
the profile assigned to it. Together, these three methods give you complete control
over session creation, monitoring, and teardown. This page documents each method in
detail, including method signatures, parameter tables, return types, internal behavior,
timeout calculation logic, practical code examples covering basic usage, advanced
patterns, error handling, session health monitoring, graceful shutdown, and retry
strategies. It also covers the two helper methods getSessionId() and
isActive() that provide quick access to session state without making
API calls. Whether you are building a simple login-and-scrape workflow or a complex
multi-session orchestration system, understanding these lifecycle methods is essential
for writing reliable, resource-efficient BBRE applications.
Every BBRESession workflow follows the same fundamental pattern: start a
session, perform your work (send requests, automate browser actions, submit forms),
and close the session when done. The BBRE engine allocates a dedicated browser instance
for each active session, which means sessions consume server resources. Always close
your sessions when you are finished to free those resources and avoid hitting the
10-session-per-account limit. Sessions also have a configurable timeout (between 0.5
and 5 minutes, set via the sessionTime constructor option) after which
they expire automatically if no activity is detected. The start() method
can override this timeout on a per-session basis through the timeout
option, capped at a maximum of 300 seconds.
session.start(options)
The start() method is the entry point for every session-based workflow.
It creates a new browser session on the BBRE engine by calling the inherited
createSession() method internally, then stores the returned session
metadata locally on the BBRESession instance. Once start()
completes, the session is active and ready to accept requests, browser actions, and
high-level workflows like form submission and multi-step interactions. The method
accepts an optional options object that lets you configure the session
timeout, browser speed, mode, sensibility, fingerprint, and proxy settings. If you
do not provide any options, the session uses the defaults configured in the
BBRESession constructor.
Internally, start() performs the following steps: it calculates the
timeout value (either from options.timeout capped at 300 seconds, or
from the constructor's sessionTime multiplied by 60), calls
createSession() with the merged options, stores the returned
sessionId, expiresAt, and profile on the
instance, optionally overrides the browserSpeed if provided in options,
and returns the full session data object. This means that after calling
start(), you can immediately use getSessionId(),
isActive(), and getProfile() to access the session state
without making additional API calls.
Method Signature
const sessionData = await session.start(options);
Parameters
The start() method accepts a single optional options object.
All properties within the options object are also optional. When a property is not
provided, the session falls back to the value configured in the
BBRESession constructor or the BBRE engine defaults.
| Parameter | Type | Required | Description |
|---|---|---|---|
options |
object | Optional | Configuration object for the session. All properties are optional. If omitted entirely, the session starts with constructor defaults. |
options.timeout |
number | Optional | Session timeout in seconds. The value is capped at a maximum of 300 seconds (5 minutes). If not provided, the timeout is calculated from the constructor's sessionTime value multiplied by 60. For example, a sessionTime of 2 (minutes) results in a timeout of 120 seconds. |
options.browserSpeed |
string | Optional | The browser interaction speed for this session. Valid values are "instant", "fast", and "human". If provided, this overrides the browserSpeed configured in the constructor. The "instant" speed executes actions immediately, "fast" adds minimal delays, and "human" simulates realistic human-like timing between actions. |
options.mode |
string | Optional | The operating mode for the session. Valid values are "passive" and "adaptive". Passive mode handles simple HTTP requests without browser automation. Adaptive mode enables full browser automation with navigation, clicking, form filling, and other browser actions. |
options.sensibility |
string | Optional | The sensibility level for the session. Valid values are "low", "medium", and "high". Higher sensibility levels make the browser behave more cautiously, adding extra delays and randomization to avoid detection, but requests take longer to complete. |
options.fingerprint |
object | Optional | A custom browser fingerprint object containing properties like userAgent, platform, screen, and timezone. If not provided, the BBRE engine generates a realistic fingerprint automatically. |
options.proxy |
string | Optional | A proxy URL to route the session traffic through. Format: protocol://user:pass@host:port. If not provided, the session uses the BBRE engine's default routing. |
Timeout Calculation Logic
The start() method uses a specific algorithm to determine the session
timeout value that gets sent to the BBRE API. Understanding this logic is important
for controlling how long your sessions stay alive on the server.
If you provide options.timeout, the method takes that value and caps it
at 300 seconds using Math.min(options.timeout, 300). This means you
cannot create a session that lasts longer than 5 minutes, regardless of the value
you pass. If you do not provide options.timeout, the method calculates
the timeout from the sessionTime constructor option using
Math.round(sessionTime * 60). The sessionTime value is
specified in minutes (between 0.5 and 5), so multiplying by 60 converts it to
seconds. The Math.round() ensures the result is a clean integer.
| Scenario | Calculation | Result |
|---|---|---|
options.timeout = 120 |
Math.min(120, 300) |
120 seconds |
options.timeout = 500 |
Math.min(500, 300) |
300 seconds (capped) |
sessionTime = 2 (no options.timeout) |
Math.round(2 * 60) |
120 seconds |
sessionTime = 0.5 (no options.timeout) |
Math.round(0.5 * 60) |
30 seconds |
sessionTime = 5 (no options.timeout) |
Math.round(5 * 60) |
300 seconds |
Return Type
The start() method returns a Promise that resolves to a
session data object containing the session ID, expiration timestamp, and the browser
profile assigned to the session. This is the same object returned by the underlying
createSession() method.
{
"success": true,
"sessionId": "sess_a1b2c3d4e5f6",
"expiresAt": "2025-01-15T14:35:00.000Z",
"profile": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"platform": "Win32",
"screen": {
"width": 1920,
"height": 1080
},
"timezone": "America/New_York",
"language": "en-US"
}
}
Return Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Indicates whether the session was created successfully. Always true when the method resolves without throwing. |
sessionId |
string | The unique identifier for the created session. This ID is stored locally on the instance and used automatically for all subsequent session operations. |
expiresAt |
string | An ISO 8601 timestamp indicating when the session will expire if no further activity occurs. The session is automatically closed by the server after this time. |
profile |
object | The browser fingerprint profile assigned to this session. Contains userAgent, platform, screen, timezone, and language properties that define the browser identity used for all requests in this session. |
What start() Stores Locally
After start() completes successfully, it stores three pieces of data on
the BBRESession instance that are used by other methods throughout the
session lifecycle. Understanding what gets stored helps you reason about the state of
your session object at any point in your code.
| Property | Source | Used By |
|---|---|---|
this.sessionId |
sessionData.sessionId |
close(), status(), request(), getSessionId(), isActive() |
this.sessionExpiresAt |
sessionData.expiresAt |
Used internally for expiration tracking. Reset to null when the session is closed. |
this.sessionProfile |
sessionData.profile |
getProfile(), getProfileSummary(), hasProfile() |
Additionally, if options.browserSpeed is provided, the instance's
browserSpeed property is updated to the new value. This affects all
subsequent browser actions performed through the session's BrowserAPI
instance.
Basic Start
The simplest way to start a session is to call start() without any
options. The session uses the defaults configured in the constructor, including the
sessionTime for timeout calculation and the default mode, sensibility,
and browser speed settings.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 2
});
async function basicStart() {
const sessionData = await session.start();
console.log("Session started:", sessionData.sessionId);
console.log("Expires at:", sessionData.expiresAt);
console.log("Profile user agent:", sessionData.profile.userAgent);
}
basicStart();
Start with Custom Options
You can override the constructor defaults by passing an options object to
start(). This is useful when you need different settings for different
sessions created from the same BBRESession instance, or when you want
to set a specific timeout for a particular workflow.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "low"
});
async function startWithOptions() {
const sessionData = await session.start({
timeout: 180,
browserSpeed: "human",
sensibility: "high",
proxy: "http://user:[email protected]:8080"
});
console.log("Session ID:", sessionData.sessionId);
console.log("Timeout set to 180 seconds");
console.log("Browser speed overridden to human");
console.log("Sensibility elevated to high for this session");
}
startWithOptions();
Start with Pre-flight Checks
Before starting a session, it is good practice to verify that your account is active,
has sufficient balance, and has available session slots. This prevents wasted API calls
and provides clear error messages when preconditions are not met. Since
BBRESession inherits from BBREClient, you can call
getAccountInfo() directly on the session instance.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function startWithPreFlightChecks() {
const { account, statistics } = await session.getAccountInfo();
if (account.status !== "active") {
console.log("Account is not active:", account.status);
return null;
}
if (account.balance < 5) {
console.log("Insufficient balance:", account.balance);
return null;
}
if (statistics.activeSessions >= 10) {
console.log("No available session slots:", statistics.activeSessions, "/ 10");
return null;
}
console.log("Pre-flight checks passed");
console.log("Balance:", account.balance);
console.log("Available slots:", 10 - statistics.activeSessions);
const sessionData = await session.start();
console.log("Session started:", sessionData.sessionId);
return sessionData;
}
startWithPreFlightChecks();
Start with Timeout Override
The timeout option lets you control exactly how long the session stays alive on the server. This is particularly useful when you know a workflow will be quick and you want to minimize resource usage, or when you need the maximum allowed time for a complex multi-step operation.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sessionTime: 2
});
async function quickSession() {
const data = await session.start({ timeout: 30 });
console.log("Quick session (30s):", data.sessionId);
const response = await session.request({
url: "https://example.com/api/data",
method: "GET"
});
console.log("Response status:", response.statusCode);
await session.close();
}
async function longSession() {
const data = await session.start({ timeout: 300 });
console.log("Long session (300s max):", data.sessionId);
const response = await session.request({
url: "https://example.com/login",
method: "POST",
body: { username: "user", password: "pass" }
});
console.log("Login response:", response.statusCode);
await session.close();
}
quickSession();
Error Handling for start()
The start() method can throw errors in several scenarios: when the API
key is invalid, when the account has insufficient balance, when the maximum session
limit (10 active sessions) has been reached, when the mode or sensibility values are
invalid, or when the BBRE service is temporarily unavailable. Always wrap
start() in a try-catch block to handle these failures gracefully.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium"
});
async function safeStart() {
try {
const sessionData = await session.start({ timeout: 120 });
console.log("Session started successfully:", sessionData.sessionId);
return sessionData;
} catch (error) {
console.log("Failed to start session:", error.message);
return null;
}
}
safeStart();
session.close()
The close() method terminates the active browser session on the BBRE
engine and resets all local session state on the BBRESession instance.
When you call close(), it sends a close request to the BBRE API using
the inherited closeSession() method, which tells the server to shut down
the dedicated browser instance, release its resources, and mark the session as closed.
After the API call completes, the method resets four local properties to their initial
values: sessionId is set to null,
sessionExpiresAt is set to null,
sessionCookies is set to an empty object {}, and
sessionProfile is set to null.
An important design detail of close() is that it only executes the close
logic if a sessionId exists on the instance. If sessionId
is already null (because the session was never started, was already
closed, or was reset for some other reason), the method does nothing and returns
silently. This makes close() safe to call multiple times without causing
errors or duplicate API calls. You can call it in a finally block without
worrying about whether the session was actually started, which simplifies cleanup
logic significantly.
Method Signature
await session.close();
Parameters
The close() method does not accept any parameters. It uses the
sessionId that was stored locally by the start() method
to identify which session to close on the server.
| Parameter | Type | Required | Description |
|---|---|---|---|
| This method does not accept any parameters. | |||
Return Type
The method returns a Promise that resolves to undefined.
It does not return any data. The purpose of the method is purely to perform the
side effect of closing the session and resetting local state.
What close() Resets
After close() completes, the following properties on the
BBRESession instance are reset to their initial values. This effectively
returns the instance to a "no active session" state, ready to start a new session
if needed.
| Property | Reset Value | Effect |
|---|---|---|
this.sessionId |
null |
isActive() returns false, getSessionId() returns null |
this.sessionExpiresAt |
null |
Expiration tracking is cleared |
this.sessionCookies |
{} |
All cookies accumulated during the session are discarded |
this.sessionProfile |
null |
getProfile() returns null, hasProfile() returns false |
Basic Close
The simplest usage of close() terminates the active session after your
work is done. Always close sessions when you are finished to free server resources
and make session slots available for future use.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium"
});
async function basicCloseExample() {
await session.start({ timeout: 120 });
console.log("Session active:", session.isActive());
const response = await session.request({
url: "https://example.com/data",
method: "GET"
});
console.log("Response status:", response.statusCode);
await session.close();
console.log("Session active after close:", session.isActive());
}
basicCloseExample();
Try-Finally Cleanup Pattern
The recommended way to use sessions is with a try-finally block that guarantees the
session is closed even if an error occurs during your workflow. Since
close() is safe to call when no session is active, you can place it in
the finally block without any conditional checks. This pattern prevents
session leaks that would consume your account's session slots.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function safeWorkflow() {
try {
await session.start();
console.log("Session started:", session.getSessionId());
const loginResponse = await session.request({
url: "https://example.com/login",
method: "POST",
body: { username: "user", password: "pass" }
});
console.log("Login status:", loginResponse.statusCode);
const dataResponse = await session.request({
url: "https://example.com/dashboard/data",
method: "GET"
});
console.log("Data retrieved:", dataResponse.statusCode);
return dataResponse;
} catch (error) {
console.log("Workflow error:", error.message);
return null;
} finally {
await session.close();
console.log("Session closed, resources released");
}
}
safeWorkflow();
Safe Close (Idempotent Behavior)
Because close() checks for the existence of sessionId
before making the API call, you can call it multiple times without errors. This is
useful in complex workflows where multiple code paths might attempt to close the
session, or when you want to add defensive cleanup calls at multiple points in your
code.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive"
});
async function demonstrateIdempotentClose() {
await session.start({ timeout: 60 });
console.log("Session active:", session.isActive());
await session.close();
console.log("First close: session active:", session.isActive());
await session.close();
console.log("Second close: no error, no API call made");
await session.close();
console.log("Third close: still safe, still no error");
}
demonstrateIdempotentClose();
Close and Restart Pattern
After closing a session, the BBRESession instance can be reused to start
a new session. This is useful for workflows that need to cycle through multiple
sessions, for example when you want a fresh browser identity for each batch of
requests.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium"
});
async function cycleSessionsForUrls(urls) {
const batchSize = 5;
const results = [];
for (let i = 0; i < urls.length; i += batchSize) {
const batch = urls.slice(i, i + batchSize);
try {
await session.start({ timeout: 120 });
console.log("New session for batch", Math.floor(i / batchSize) + 1);
for (const url of batch) {
const response = await session.request({ url, method: "GET" });
results.push({ url, status: response.statusCode });
}
} catch (error) {
console.log("Batch error:", error.message);
} finally {
await session.close();
}
}
return results;
}
const urls = [
"https://example.com/page/1",
"https://example.com/page/2",
"https://example.com/page/3",
"https://example.com/page/4",
"https://example.com/page/5",
"https://example.com/page/6",
"https://example.com/page/7"
];
cycleSessionsForUrls(urls);
session.status()
The status() method queries the BBRE API for the current state of the
active session. It returns real-time information about whether the session is still
alive, when it expires, and the profile assigned to it. Unlike
getSessionId() and isActive() which read locally cached
values, status() makes an actual API call to the BBRE server, giving
you the authoritative, server-side state of the session. This is important because
a session might have expired on the server even though the local
sessionId is still set, for example if the session timed out due to
inactivity.
The method throws an error if no session is currently active on the instance (when
sessionId is null). This is a deliberate design choice
that prevents you from accidentally querying a non-existent session. Always check
isActive() before calling status() if you are not sure
whether a session has been started, or wrap the call in a try-catch block.
Internally, status() calls the inherited getSessionStatus()
method with the locally stored sessionId. The
getSessionStatus() method sends a POST request to the
/session/status endpoint on the BBRE API and returns the response data.
Method Signature
const statusData = await session.status();
Parameters
The status() method does not accept any parameters. It uses the
sessionId stored locally by the start() method to identify
which session to query on the server.
| Parameter | Type | Required | Description |
|---|---|---|---|
| This method does not accept any parameters. | |||
Return Type
The method returns a Promise that resolves to a status data object
containing the session's current state, expiration timestamp, and profile information.
{
"success": true,
"status": "active",
"expiresAt": "2025-01-15T14:35:00.000Z",
"profile": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"platform": "Win32",
"screen": {
"width": 1920,
"height": 1080
},
"timezone": "America/New_York",
"language": "en-US"
}
}
Return Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Indicates whether the status query was successful. |
status |
string | The current state of the session on the server. Possible values include "active", "expired", and "closed". Only sessions with "active" status can accept new requests and browser actions. |
expiresAt |
string | An ISO 8601 timestamp indicating when the session will expire. This value is updated by the server each time the session receives activity, extending the expiration window. |
profile |
object | The browser fingerprint profile assigned to this session. Same structure as the profile returned by start(). |
Basic Status Check
The simplest usage of status() retrieves and displays the current state
of the active session. This is useful for debugging, logging, and verifying that a
session is still alive before performing operations.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium"
});
async function checkSessionStatus() {
await session.start({ timeout: 120 });
console.log("Session started:", session.getSessionId());
const statusData = await session.status();
console.log("Session status:", statusData.status);
console.log("Expires at:", statusData.expiresAt);
console.log("Profile platform:", statusData.profile.platform);
await session.close();
}
checkSessionStatus();
Remaining Time Calculation
You can calculate the remaining time before a session expires by comparing the
expiresAt timestamp from the status response with the current time.
This is useful for deciding whether to continue working in the current session or
start a new one, and for implementing proactive session renewal before expiration.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function checkRemainingTime() {
await session.start();
const statusData = await session.status();
const expiresAt = new Date(statusData.expiresAt);
const now = new Date();
const remainingMs = expiresAt.getTime() - now.getTime();
const remainingSeconds = Math.floor(remainingMs / 1000);
console.log("Session status:", statusData.status);
console.log("Expires at:", statusData.expiresAt);
console.log("Remaining time:", remainingSeconds, "seconds");
if (remainingSeconds < 30) {
console.log("Session is about to expire, consider closing and starting a new one");
} else {
console.log("Session has sufficient time remaining");
}
await session.close();
}
checkRemainingTime();
Session Health Monitoring Loop
For long-running workflows, you can implement a monitoring loop that periodically checks the session status and takes action when the session is about to expire or has already expired. This pattern is useful for automated pipelines that need to detect and recover from session expiration without manual intervention.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 5
});
async function monitorSessionHealth(checkIntervalMs) {
await session.start();
console.log("Session started:", session.getSessionId());
const monitorInterval = setInterval(async () => {
try {
if (!session.isActive()) {
console.log("Session is no longer active locally, stopping monitor");
clearInterval(monitorInterval);
return;
}
const statusData = await session.status();
const expiresAt = new Date(statusData.expiresAt);
const remainingSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);
console.log("Health check: status=" + statusData.status + ", remaining=" + remainingSeconds + "s");
if (statusData.status !== "active") {
console.log("Session is no longer active on server:", statusData.status);
clearInterval(monitorInterval);
await session.close();
} else if (remainingSeconds < 15) {
console.log("Session expiring soon, closing and restarting");
clearInterval(monitorInterval);
await session.close();
await session.start();
console.log("New session started:", session.getSessionId());
}
} catch (error) {
console.log("Health check failed:", error.message);
clearInterval(monitorInterval);
}
}, checkIntervalMs);
return monitorInterval;
}
monitorSessionHealth(10000);
Error Handling for status()
The status() method throws an error with the message
"No active session" if you call it when no session is active on the
instance. It can also throw errors if the session has expired on the server, if the
session ID is no longer valid, or if the BBRE service is temporarily unavailable.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive"
});
async function safeStatusCheck() {
if (!session.isActive()) {
console.log("No active session, cannot check status");
return null;
}
try {
const statusData = await session.status();
return statusData;
} catch (error) {
console.log("Status check failed:", error.message);
return null;
}
}
async function demonstrateStatusError() {
try {
await session.status();
} catch (error) {
console.log("Expected error:", error.message);
}
await session.start({ timeout: 60 });
const statusData = await session.status();
console.log("Status after start:", statusData.status);
await session.close();
try {
await session.status();
} catch (error) {
console.log("Expected error after close:", error.message);
}
}
demonstrateStatusError();
Helper Methods: getSessionId() and isActive()
The BBRESession class provides two synchronous helper methods that give
you quick access to the session state without making any API calls. These methods
read the locally cached sessionId property that is set by
start() and cleared by close(). They are useful for
conditional logic, logging, debugging, and guard checks before calling methods that
require an active session.
session.getSessionId()
Returns the current session ID as a string, or null if no session is
active. This method simply returns the value of this.sessionId without
any transformation or API call. The returned ID is the same value that was received
from the BBRE API when start() was called.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive"
});
async function demonstrateGetSessionId() {
console.log("Before start:", session.getSessionId());
await session.start({ timeout: 60 });
console.log("After start:", session.getSessionId());
await session.close();
console.log("After close:", session.getSessionId());
}
demonstrateGetSessionId();
session.isActive()
Returns true if a session ID exists on the instance, false
otherwise. This method evaluates !!this.sessionId, which means it returns
true for any truthy session ID value and false for
null, undefined, or an empty string. Note that
isActive() only checks the local state. It does not verify whether the
session is still alive on the server. A session might have expired on the server due
to inactivity while isActive() still returns true because
the local sessionId has not been cleared. To get the authoritative
server-side status, use the status() method instead.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive"
});
async function demonstrateIsActive() {
console.log("Before start:", session.isActive());
await session.start({ timeout: 60 });
console.log("After start:", session.isActive());
await session.close();
console.log("After close:", session.isActive());
}
demonstrateIsActive();
Using Helpers as Guard Checks
A common pattern is to use isActive() as a guard check before performing
session operations. This prevents unnecessary API calls and provides clear error
messages when the session is not in the expected state.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium"
});
async function fetchDataIfSessionActive(url) {
if (!session.isActive()) {
console.log("No active session. Call session.start() first.");
return null;
}
console.log("Fetching data with session:", session.getSessionId());
const response = await session.request({ url, method: "GET" });
return response;
}
async function workflow() {
const result1 = await fetchDataIfSessionActive("https://example.com/data");
console.log("Result without session:", result1);
await session.start({ timeout: 120 });
const result2 = await fetchDataIfSessionActive("https://example.com/data");
console.log("Result with session:", result2.statusCode);
await session.close();
}
workflow();
Helper Methods Reference
| Method | Returns | Makes API Call | Description |
|---|---|---|---|
getSessionId() |
string | null | No | Returns the locally stored session ID, or null if no session is active. |
isActive() |
boolean | No | Returns true if a session ID exists locally, false otherwise. Does not verify server-side status. |
status() |
object | Yes | Queries the BBRE API for the authoritative server-side session status. Throws if no session is active. |
Complete Lifecycle Patterns
This section presents complete, production-ready patterns that combine
start(), close(), status(), and the helper
methods into cohesive workflows. These patterns address common real-world scenarios
including guaranteed cleanup, retry logic, session rotation, and graceful shutdown
handling.
Standard Lifecycle Pattern
The standard lifecycle pattern is the foundation for all session-based workflows. It starts a session, performs work inside a try block, and guarantees cleanup in the finally block. This pattern should be your default approach for any session workflow.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function standardLifecycle(targetUrl) {
try {
const sessionData = await session.start();
console.log("Session:", sessionData.sessionId);
console.log("Profile:", sessionData.profile.userAgent);
const response = await session.request({
url: targetUrl,
method: "GET"
});
console.log("Status:", response.statusCode);
return response;
} finally {
await session.close();
console.log("Cleanup complete");
}
}
standardLifecycle("https://example.com/data");
Retry with New Session Pattern
When a session-based request fails due to session expiration, server errors, or transient network issues, you can retry the entire workflow with a fresh session. This pattern closes the failed session, starts a new one with a fresh browser identity, and retries the operation. The new session gets a different fingerprint profile, which can help when the failure was caused by the target website blocking the previous browser identity.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "high",
sessionTime: 2
});
async function requestWithRetry(url, maxRetries) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await session.start({ timeout: 120 });
console.log("Attempt", attempt, "- Session:", session.getSessionId());
const response = await session.request({ url, method: "GET" });
console.log("Success on attempt", attempt);
await session.close();
return response;
} catch (error) {
lastError = error;
console.log("Attempt", attempt, "failed:", error.message);
await session.close();
if (attempt < maxRetries) {
const delay = 2000 * attempt;
console.log("Waiting", delay, "ms before retry");
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
async function main() {
try {
const response = await requestWithRetry("https://example.com/protected-data", 3);
console.log("Final result:", response.statusCode);
} catch (error) {
console.log("All retries exhausted:", error.message);
}
}
main();
Session Health Monitoring with Auto-Renewal
For workflows that run for extended periods, implement a health monitoring system
that checks the session status periodically and automatically renews the session
before it expires. This pattern uses status() to get the remaining
time and proactively creates a new session when the current one is about to expire.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function ensureActiveSession(renewalThresholdSeconds) {
if (!session.isActive()) {
console.log("No active session, starting new one");
await session.start();
return;
}
try {
const statusData = await session.status();
if (statusData.status !== "active") {
console.log("Session expired on server, starting new one");
await session.close();
await session.start();
return;
}
const expiresAt = new Date(statusData.expiresAt);
const remainingSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);
if (remainingSeconds < renewalThresholdSeconds) {
console.log("Session expiring in", remainingSeconds, "seconds, renewing");
await session.close();
await session.start();
}
} catch (error) {
console.log("Status check failed, restarting session:", error.message);
await session.close();
await session.start();
}
}
async function longRunningWorkflow(urls) {
const results = [];
for (const url of urls) {
await ensureActiveSession(30);
try {
const response = await session.request({ url, method: "GET" });
results.push({ url, status: response.statusCode, success: true });
} catch (error) {
results.push({ url, error: error.message, success: false });
}
}
await session.close();
return results;
}
const urls = [
"https://example.com/page/1",
"https://example.com/page/2",
"https://example.com/page/3",
"https://example.com/page/4",
"https://example.com/page/5"
];
longRunningWorkflow(urls);
Graceful Shutdown with SIGINT Handler
When running session-based workflows in a Node.js process, it is important to handle process termination signals (like Ctrl+C) gracefully. If the process exits without closing the session, the server-side browser instance remains allocated until it times out, wasting resources and occupying one of your 10 session slots. The following pattern registers a SIGINT handler that closes the session before the process exits.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 5
});
let isShuttingDown = false;
process.on("SIGINT", async () => {
if (isShuttingDown) return;
isShuttingDown = true;
console.log("
Received SIGINT, shutting down gracefully...");
if (session.isActive()) {
console.log("Closing active session:", session.getSessionId());
try {
await session.close();
console.log("Session closed successfully");
} catch (error) {
console.log("Error closing session:", error.message);
}
}
process.exit(0);
});
async function longRunningProcess() {
await session.start({ timeout: 300 });
console.log("Session started:", session.getSessionId());
console.log("Press Ctrl+C to stop gracefully");
const urls = [
"https://example.com/page/1",
"https://example.com/page/2",
"https://example.com/page/3",
"https://example.com/page/4",
"https://example.com/page/5",
"https://example.com/page/6",
"https://example.com/page/7",
"https://example.com/page/8"
];
for (const url of urls) {
if (isShuttingDown) {
console.log("Shutdown requested, stopping work");
break;
}
try {
const response = await session.request({ url, method: "GET" });
console.log("Processed:", url, "Status:", response.statusCode);
} catch (error) {
console.log("Error processing:", url, error.message);
}
}
if (!isShuttingDown) {
await session.close();
console.log("All work completed, session closed");
}
}
longRunningProcess();
Multi-Step Form Submission with Lifecycle Management
A practical example that combines all lifecycle methods in a real-world scenario: logging into a website, navigating to a form, filling it out, and submitting it, all within a properly managed session lifecycle with error handling and cleanup.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "high",
browserSpeed: "human",
sessionTime: 4
});
async function submitApplicationForm(formData) {
try {
const sessionData = await session.start({ timeout: 240 });
console.log("Session ready:", sessionData.sessionId);
console.log("Browser identity:", sessionData.profile.userAgent);
const loginResponse = await session.request({
url: "https://portal.example.com/login",
method: "POST",
body: { email: formData.email, password: formData.password }
});
console.log("Login:", loginResponse.statusCode);
const statusCheck = await session.status();
console.log("Session still active:", statusCheck.status);
const formResponse = await session.request({
url: "https://portal.example.com/application/new",
method: "GET"
});
console.log("Form page loaded:", formResponse.statusCode);
const submitResponse = await session.request({
url: "https://portal.example.com/application/submit",
method: "POST",
body: {
firstName: formData.firstName,
lastName: formData.lastName,
phone: formData.phone,
address: formData.address
}
});
console.log("Form submitted:", submitResponse.statusCode);
return { success: true, response: submitResponse };
} catch (error) {
console.log("Form submission failed:", error.message);
return { success: false, error: error.message };
} finally {
await session.close();
console.log("Session closed");
}
}
submitApplicationForm({
email: "[email protected]",
password: "securepassword",
firstName: "Alice",
lastName: "Johnson",
phone: "+1234567890",
address: "123 Main Street"
});
Parallel Sessions with Independent Lifecycles
When you need to run multiple independent workflows simultaneously, create separate
BBRESession instances, each with its own lifecycle. Each instance
manages its own session ID, cookies, and profile independently. Be mindful of the
10-session-per-account limit when running parallel sessions.
const { BBRESession } = require("mydisctsolver-bbre");
async function processUrlWithSession(apiKey, url) {
const session = new BBRESession({
apiKey: apiKey,
mode: "adaptive",
sensibility: "medium",
sessionTime: 2
});
try {
await session.start({ timeout: 120 });
console.log("Session for", url, ":", session.getSessionId());
const response = await session.request({ url, method: "GET" });
return { url, status: response.statusCode, sessionId: session.getSessionId() };
} catch (error) {
return { url, error: error.message };
} finally {
await session.close();
}
}
async function parallelProcessing(apiKey, urls) {
const promises = urls.map(url => processUrlWithSession(apiKey, url));
const results = await Promise.all(promises);
for (const result of results) {
if (result.error) {
console.log("Failed:", result.url, result.error);
} else {
console.log("Success:", result.url, "Status:", result.status);
}
}
return results;
}
parallelProcessing("YOUR_API_KEY", [
"https://example.com/page/1",
"https://example.com/page/2",
"https://example.com/page/3"
]);
Error Handling
Each lifecycle method has its own set of potential errors. Understanding when and why each method throws helps you write robust error handling that distinguishes between recoverable and non-recoverable failures. The following table summarizes the error scenarios for each method and the recommended response.
Error Reference
| Method | Error Scenario | Recommended Action |
|---|---|---|
start() |
Invalid API key or authentication failure | Verify your API key configuration. Do not retry with the same key. |
start() |
Insufficient balance to create a session | Check your balance with getBalance() and recharge your account. |
start() |
Session limit reached (10 active sessions) | Close unused sessions before creating new ones. Use getAccountInfo() to check active session count. |
start() |
Invalid mode or sensibility value | Use valid values: mode must be "passive" or "adaptive", sensibility must be "low", "medium", or "high". |
start() |
Service temporarily unavailable | Retry after a short delay with exponential backoff. |
close() |
Network error during close request | The local state is still reset. The server-side session will expire on its own after the timeout. |
status() |
No active session (sessionId is null) |
Check isActive() before calling status(), or start a session first. |
status() |
Session expired or closed on server | Close the local session and start a new one if needed. |
status() |
Session not found (invalid session ID) | The session may have been closed from another process. Close locally and start fresh. |
Comprehensive Error Handling Example
The following example demonstrates a robust error handling pattern that categorizes errors by type and takes appropriate action for each category. Authentication and account errors are treated as non-recoverable, while service errors trigger a retry.
const { BBRESession } = require("mydisctsolver-bbre");
const session = new BBRESession({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "medium",
sessionTime: 3
});
async function resilientWorkflow(url) {
let result = null;
try {
await session.start({ timeout: 180 });
} catch (error) {
const msg = error.message.toLowerCase();
if (msg.includes("api key") || msg.includes("suspended") || msg.includes("inactive")) {
console.log("Non-recoverable auth error:", error.message);
return { success: false, errorType: "auth", message: error.message };
}
if (msg.includes("session_limit") || msg.includes("limit")) {
console.log("Session limit reached, cannot create new session");
return { success: false, errorType: "limit", message: error.message };
}
if (msg.includes("insufficient") || msg.includes("balance")) {
console.log("Insufficient balance:", error.message);
return { success: false, errorType: "balance", message: error.message };
}
console.log("Service error during start:", error.message);
return { success: false, errorType: "service", message: error.message };
}
try {
const response = await session.request({ url, method: "GET" });
result = { success: true, statusCode: response.statusCode, data: response };
} catch (error) {
console.log("Request error:", error.message);
result = { success: false, errorType: "request", message: error.message };
} finally {
await session.close();
}
return result;
}
resilientWorkflow("https://example.com/data");
Best Practices
Every session workflow should wrap the main logic in a try block with
session.close() in the finally block. This guarantees that the session
is closed and server resources are released even when errors occur during your
workflow. Since close() is safe to call when no session is active, you
do not need any conditional checks in the finally block. Failing to close sessions
leads to resource leaks where browser instances remain allocated on the server until
they time out, wasting your session slots and potentially blocking new session
creation when you hit the 10-session limit.
Choose your session timeout based on the expected duration of your workflow. For
quick data fetching operations, use a short timeout (30 to 60 seconds) to minimize
resource usage. For complex multi-step workflows like form submission or multi-page
navigation, use a longer timeout (120 to 300 seconds) to avoid premature expiration.
Remember that the timeout is capped at 300 seconds regardless of the value you pass
to start(). If your workflow might take longer than 5 minutes, break
it into multiple sessions or implement the auto-renewal pattern that checks
remaining time with status() and creates a new session before the
current one expires.
Use isActive() for quick, synchronous checks when you need to know
whether a session has been started locally. It is free (no API call) and fast. Use
status() when you need to verify the actual server-side state of the
session, for example before performing a critical operation where you need to be
certain the session has not expired. Avoid calling status() before
every request in a tight loop, as each call makes an API request. Instead, call it
periodically (every 30 to 60 seconds) or before important operations.
Before calling start(), verify that your account is in good standing
by calling getAccountInfo(). Check that the account status is active,
the balance is sufficient for your planned operations, and the number of active
sessions is below the 10-session limit. This prevents wasted API calls and provides
clear, actionable error messages instead of cryptic server errors. The pre-flight
check adds one extra API call but saves you from debugging failed session creation
attempts.
If your application runs as a long-lived Node.js process (a server, a worker, or
a CLI tool), register a handler for the SIGINT signal that closes any
active sessions before the process exits. Without this handler, pressing Ctrl+C
terminates the process immediately, leaving the server-side session allocated until
it times out. The graceful shutdown pattern ensures that your session slots are
freed immediately, making them available for other processes or future runs.
A single BBRESession instance can be used to start, close, and
restart sessions multiple times. After calling close(), the instance
is reset to its initial state and ready for a new start() call. This
is more efficient than creating a new BBRESession instance for each
session, because the constructor configuration (API key, mode, sensibility,
browser speed) is preserved across session cycles. Create separate instances only
when you need different constructor configurations or when running parallel
sessions.
When starting a session with options.browserSpeed, choose the speed
based on how aggressively the target website detects automated traffic. Use
"instant" for internal APIs and websites with no bot detection. Use
"fast" for most public websites where some timing variation is
sufficient. Use "human" for heavily protected websites that analyze
interaction timing patterns. You can override the browser speed at session start
time without changing the constructor configuration, which is useful when the same
application targets websites with different protection levels.
Common Issues
Symptom: Calling session.status() throws an error
with the message "No active session".
Cause: The status() method requires an active session
with a valid sessionId. This error occurs when you call
status() before calling start(), after calling
close(), or when the session was never started successfully.
Solution: Always check session.isActive() before
calling status(), or ensure that start() completed
successfully before attempting to check the status. If you need to handle this
gracefully, wrap the status() call in a try-catch block.
Symptom: Requests fail with session expired errors partway through
a multi-step workflow, even though the session was recently started.
Cause: The session timeout was set too low for the workflow
duration. If you use the default sessionTime of 0.5 minutes (30
seconds) and your workflow takes longer than that, the session expires on the
server while your code is still running. The local isActive() still
returns true because the local state has not been updated.
Solution: Increase the timeout by either setting a higher
sessionTime in the constructor (up to 5 minutes) or passing a
timeout value to start() (up to 300 seconds). For
workflows that might exceed 5 minutes, implement the auto-renewal pattern that
periodically checks status() and creates a new session before
expiration.
Symptom: Calling session.start() throws an error
indicating that the maximum session limit has been reached.
Cause: Your account already has 10 active sessions. This can
happen when previous sessions were not closed properly (process crashed, network
error during close, or missing finally block), or when multiple processes are
creating sessions concurrently.
Solution: Close unused sessions before creating new ones. Use
getAccountInfo() to check the statistics.activeSessions
count. If you have orphaned sessions from crashed processes, they will expire
automatically after their timeout period. To prevent this issue, always use the
try-finally pattern and register SIGINT handlers for graceful shutdown.
Symptom: You pass a timeout value greater than 300 to
start(), but the session expires after 5 minutes instead of the
expected longer duration.
Cause: The start() method caps the timeout at 300
seconds using Math.min(options.timeout, 300). Any value above 300 is
silently reduced to 300. This is a server-side limitation to prevent sessions from
consuming resources indefinitely.
Solution: Accept the 300-second maximum and design your workflows
accordingly. For workflows that need more than 5 minutes, implement session
rotation: close the current session and start a new one when the remaining time
drops below a threshold. The auto-renewal pattern documented in the lifecycle
patterns section handles this automatically.
Symptom: session.isActive() returns true,
but sending requests through the session fails with session expired or session not
found errors.
Cause: The isActive() method only checks the local
sessionId property. It does not verify the server-side state. If the
session expired on the server due to inactivity timeout, the local state still
shows an active session because close() was never called.
Solution: Use session.status() to verify the
server-side state before critical operations. If status() shows the
session is expired or closed, call session.close() to reset the local
state and then session.start() to create a new session.
Symptom: After closing a session and starting a new one, the
cookies from the previous session are gone, and authenticated pages return login
prompts.
Cause: The close() method resets
sessionCookies to an empty object {}. Each new session
starts with a clean cookie store and a new browser profile. This is by design:
sessions are independent, and each one represents a fresh browser identity.
Solution: If you need to maintain authentication across session
boundaries, re-authenticate (log in again) at the beginning of each new session.
Alternatively, if your workflow requires persistent cookies, keep the same session
alive instead of cycling sessions. Use the auto-renewal pattern to extend session
lifetime without losing cookies.