Session Management Methods
The BBREClient class provides three session management methods that give
you full control over BBRE session lifecycles: createSession(),
closeSession(), and getSessionStatus(). Sessions are the
foundation of stateful browsing in the BBRE (Browser-Backed Request Engine) system.
When you create a session, the BBRE engine allocates a dedicated browser context that
maintains cookies, local storage, and a consistent browser fingerprint profile across
multiple requests. This is essential for workflows that require authentication,
multi-step form submissions, shopping cart interactions, or any scenario where the
target website tracks user state between page loads. The createSession()
method accepts an options object where you can specify the operating mode (passive or
adaptive), sensibility level (low, medium, or high), custom fingerprint overrides,
proxy configuration, and session timeout duration. It returns a session object
containing the unique session identifier, expiration timestamp, and the browser profile
assigned to the session. The closeSession() method terminates an active
session and releases its resources, accepting a session ID string and returning a
simple success indicator. The getSessionStatus() method queries the
current state of a session, returning its status, expiration time, and profile data.
Together, these three methods form the complete session lifecycle: create, use, monitor,
and close. Each account is limited to a maximum of 10 active sessions at any given
time, so proper session management is critical for applications that work with multiple
concurrent sessions. This page provides complete documentation for all three session
management methods, including method signatures, parameter descriptions, return types,
practical code examples covering basic and advanced usage patterns, session lifecycle
management, session pool implementations, error handling strategies, best practices,
common issues, and links to related documentation.
The session management methods communicate with the BBRE session API endpoints using
your API key for authentication. The createSession() method sends a POST
request to /session/create, the closeSession() method sends
a POST request to /session/close, and the
getSessionStatus() method sends a POST request to
/session/status. All three methods use the X-API-Key header
internally for authentication. Unlike the HTTP convenience methods that route requests
through the BBRE engine to external URLs, these methods interact directly with the
BBRE API server to manage session resources. Each account supports a maximum of 10
active sessions simultaneously. Session timeout values must be between 60 and 3600
seconds, with a default of 600 seconds (10 minutes).
client.createSession(options)
The createSession() method creates a new BBRE session with the specified
configuration. It sends a POST request to the /session/create endpoint
with your session options and returns an object containing the session ID, expiration
timestamp, and the browser profile assigned to the session. When you create a session,
the BBRE engine allocates a dedicated browser context that persists across all requests
made within that session. This means cookies set by one request are automatically
available to subsequent requests in the same session, and the browser fingerprint
remains consistent throughout the session lifetime. The method accepts an optional
configuration object where you can override the default mode, sensibility, fingerprint,
proxy, and timeout values. If you omit any option, the method falls back to the
defaults configured in the BBREClient constructor. The fingerprint option
is particularly interesting because it merges with the default fingerprint rather than
replacing it entirely, allowing you to override specific fingerprint fields while
keeping the rest of the default configuration intact.
Method Signature
const session = await client.createSession(options);
Parameters
The createSession() method accepts a single optional parameter: an options
object that configures the session. If you call createSession() without
any arguments, the session is created using the default values from the
BBREClient constructor configuration. Every property in the options object
is optional and falls back to either the client-level default or a built-in default
value.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
mode |
string | Optional | Client default | The operating mode for the session. Accepted values are "passive" and "adaptive". Passive mode handles simple HTTP requests without browser automation. Adaptive mode enables full browser automation with support for navigation, clicking, form filling, and other browser actions. If not specified, the session inherits the defaultMode from the BBREClient constructor. |
sensibility |
string | Optional | Client default | The sensibility level for the session. Accepted values are "low", "medium", and "high". Low sensibility prioritizes speed with minimal evasion techniques. Medium sensibility balances speed and detection avoidance. High sensibility applies maximum evasion techniques at the cost of slower request processing. If not specified, the session inherits the defaultSensibility from the BBREClient constructor. |
fingerprint |
object | Optional | {} |
Custom browser fingerprint overrides for this session. This object is merged with the defaultFingerprint from the BBREClient constructor using shallow merge. Properties you specify here override the corresponding properties in the default fingerprint, while unspecified properties retain their default values. Common fingerprint fields include userAgent, platform, screen, timezone, and language. |
proxy |
string | Optional | Client default | The proxy URL to use for all requests within this session. If you provide a proxy value (including null to explicitly disable proxying), it overrides the client default. If you omit this parameter entirely (leaving it as undefined), the session falls back to the defaultProxy configured in the BBREClient constructor. |
timeout |
number | Optional | 600 |
The session timeout in seconds. This defines how long the session remains active after creation. The BBRE API validates this value and accepts values between 60 and 3600 seconds (1 minute to 1 hour). The default is 600 seconds (10 minutes). After the timeout expires, the session is automatically closed by the server and any subsequent requests to that session will fail with a SESSION_EXPIRED error. |
Fingerprint Merging Behavior
The fingerprint parameter in createSession() does not replace the default
fingerprint entirely. Instead, it performs a shallow merge using the JavaScript spread
operator: { ...this.defaultFingerprint, ...fingerprint }. This means that
any fields you specify in the session-level fingerprint override the corresponding
fields in the default fingerprint, while all other default fingerprint fields remain
unchanged. This design lets you set a base fingerprint configuration in the BBREClient
constructor and then customize specific fields per session without repeating the entire
fingerprint object every time.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
fingerprint: {
platform: "Windows",
language: "en-US",
timezone: "America/New_York",
screen: { width: 1920, height: 1080 }
}
});
const session = await client.createSession({
fingerprint: {
timezone: "Europe/London",
language: "en-GB"
}
});
console.log("Session created:", session.sessionId);
In the example above, the session fingerprint sent to the API will contain
platform: "Windows" and screen: { width: 1920, height: 1080 }
from the default fingerprint, combined with timezone: "Europe/London" and
language: "en-GB" from the session-level override. The timezone and
language fields from the default fingerprint are replaced by the session-level values,
while platform and screen remain untouched.
Proxy Fallback Behavior
The proxy parameter has a specific fallback behavior that differs from other options.
The method checks whether the proxy parameter is strictly undefined (not
provided at all). If it is undefined, the method uses the defaultProxy
from the BBREClient constructor. If you explicitly pass null as the proxy
value, the session will be created without a proxy, even if a default proxy is
configured on the client. This distinction allows you to selectively disable proxying
for specific sessions while keeping a default proxy for others.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
proxy: "http://proxy.example.com:8080"
});
const sessionWithDefaultProxy = await client.createSession();
console.log("Uses default proxy: http://proxy.example.com:8080");
const sessionWithCustomProxy = await client.createSession({
proxy: "http://other-proxy.example.com:9090"
});
console.log("Uses custom proxy: http://other-proxy.example.com:9090");
const sessionWithoutProxy = await client.createSession({
proxy: null
});
console.log("No proxy used for this session");
Return Type
The createSession() method returns a Promise that resolves to
an object containing the session creation result. The returned object includes the
session ID that you will use for all subsequent operations on this session, the
expiration timestamp indicating when the session will automatically close, and the
browser profile assigned to the session (if available).
{
"success": true,
"sessionId": "sess_a1b2c3d4e5f6",
"expiresAt": "2024-12-15T14:30:00.000Z",
"profile": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"platform": "Windows",
"language": "en-US",
"screen": { "width": 1920, "height": 1080 },
"timezone": "America/New_York"
}
}
Return Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true when the session is created successfully. If the creation fails, the method throws an error instead of returning an object with success: false. |
sessionId |
string | The unique identifier for the created session. Use this ID when making requests within the session, checking session status, or closing the session. The format is a server-generated string that uniquely identifies this session instance. |
expiresAt |
string | The ISO 8601 timestamp indicating when the session will automatically expire. After this time, the session is closed by the server and any requests to it will fail with a SESSION_EXPIRED error. The expiration time is calculated as the creation time plus the timeout value you specified (or the default 600 seconds). |
profile |
object | null | The browser profile assigned to this session by the BBRE engine. Contains fingerprint details such as userAgent, platform, language, screen dimensions, and timezone. This value may be null if the profile is not yet available at session creation time. The profile becomes fully populated after the first request is processed within the session. |
Basic Session Creation
The simplest way to create a session is to call createSession() without
any arguments. The session will use all the default values from the BBREClient
constructor configuration, including the default mode, sensibility, fingerprint, and
proxy. The timeout defaults to 600 seconds (10 minutes).
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function createBasicSession() {
const session = await client.createSession();
console.log("Session ID:", session.sessionId);
console.log("Expires at:", session.expiresAt);
console.log("Profile:", session.profile);
return session;
}
createBasicSession();
Session Creation with Custom Options
For more control over the session behavior, pass an options object with the desired configuration. This example creates a session in adaptive mode with high sensibility, a custom fingerprint, and a longer timeout. Adaptive mode is required when you plan to use browser actions like navigation, clicking, and form filling within the session. High sensibility applies maximum evasion techniques, which is useful for target websites with aggressive bot detection.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function createCustomSession() {
const session = await client.createSession({
mode: "adaptive",
sensibility: "high",
fingerprint: {
platform: "MacIntel",
language: "en-US",
timezone: "America/Los_Angeles",
screen: { width: 2560, height: 1440 }
},
proxy: "http://us-west.proxy.example.com:8080",
timeout: 1800
});
console.log("Session ID:", session.sessionId);
console.log("Expires at:", session.expiresAt);
console.log("Mode: adaptive, Sensibility: high");
console.log("Timeout: 1800 seconds (30 minutes)");
return session;
}
createCustomSession();
Session Creation with Error Handling
The createSession() method throws an error when the session cannot be
created. Common failure reasons include reaching the maximum session limit (10 active
sessions per account), insufficient account balance, invalid mode or sensibility
values, and timeout values outside the allowed range (60 to 3600 seconds). Always wrap
the call in a try-catch block to handle these scenarios gracefully.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function safeCreateSession(options) {
try {
const session = await client.createSession(options);
console.log("Session created successfully:", session.sessionId);
return session;
} catch (error) {
const message = error.message.toLowerCase();
if (message.includes("limit") || message.includes("maximum")) {
console.log("Session limit reached. Close existing sessions before creating new ones.");
} else if (message.includes("balance") || message.includes("insufficient")) {
console.log("Insufficient balance to create a session. Recharge your account.");
} else if (message.includes("mode")) {
console.log("Invalid mode specified. Use 'passive' or 'adaptive'.");
} else if (message.includes("sensibility")) {
console.log("Invalid sensibility specified. Use 'low', 'medium', or 'high'.");
} else {
console.log("Session creation failed:", error.message);
}
return null;
}
}
safeCreateSession({ mode: "adaptive", sensibility: "medium" });
client.closeSession(sessionId)
The closeSession() method terminates an active BBRE session and releases
all resources associated with it. It sends a POST request to the
/session/close endpoint with the session ID in the request body. When a
session is closed, the BBRE engine destroys the browser context, clears all cookies
and local storage, and frees the session slot so it can be used for a new session.
Closing sessions promptly when you are done with them is important because each account
is limited to 10 active sessions. If you do not close sessions manually, they will
remain active until their timeout expires, occupying session slots that could be used
for other work. The method returns a simple object with a success boolean
indicating whether the close operation completed successfully.
Method Signature
const result = await client.closeSession(sessionId);
Parameters
The closeSession() method accepts a single required parameter: the session
ID string that identifies the session you want to close. This is the same
sessionId value that was returned by createSession() when the
session was originally created.
| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string | Required | The unique identifier of the session to close. This value is obtained from the sessionId field in the createSession() response. The session must exist and be in an active or expired state. Attempting to close a session that has already been closed will result in a SESSION_CLOSED error. |
Return Type
The method returns a Promise that resolves to an object with a single
success field. If the session is closed successfully, success
is true. If the close operation fails, the method throws an error with a
descriptive message rather than returning an object with success: false.
{
"success": true
}
Return Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Indicates whether the session was closed successfully. Always true when the method returns without throwing. The value is extracted directly from the API response. |
Basic Usage
The simplest usage of closeSession() passes the session ID obtained from
a previous createSession() call. After closing, the session slot is freed
and the session ID becomes invalid for further operations.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function createAndCloseSession() {
const session = await client.createSession({ mode: "passive" });
console.log("Session created:", session.sessionId);
const result = await client.closeSession(session.sessionId);
console.log("Session closed:", result.success);
}
createAndCloseSession();
Error Handling for closeSession()
The closeSession() method throws an error when the session cannot be
closed. The most common error scenarios are attempting to close a session that does not
exist (SESSION_NOT_FOUND), a session that has already expired (SESSION_EXPIRED), or a
session that has already been closed (SESSION_CLOSED). Always wrap the call in a
try-catch block, especially in cleanup code where you want to ensure graceful shutdown
regardless of the session state.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function safeCloseSession(sessionId) {
try {
const result = await client.closeSession(sessionId);
console.log("Session closed successfully");
return true;
} catch (error) {
const message = error.message.toLowerCase();
if (message.includes("not found")) {
console.log("Session does not exist. It may have already been cleaned up.");
} else if (message.includes("expired")) {
console.log("Session has already expired. No action needed.");
} else if (message.includes("closed")) {
console.log("Session was already closed.");
} else {
console.log("Failed to close session:", error.message);
}
return false;
}
}
safeCloseSession("sess_a1b2c3d4e5f6");
Error Types for closeSession()
| Error Code | Cause | Solution |
|---|---|---|
SESSION_NOT_FOUND |
The provided session ID does not match any session in the system. The session may have been automatically cleaned up after expiration. | Verify the session ID is correct. If the session was created long ago, it may have expired and been removed from the system. |
SESSION_EXPIRED |
The session timeout has elapsed and the session was automatically closed by the server. | No action needed. The session resources have already been released. Create a new session if you need to continue working. |
SESSION_CLOSED |
The session has already been closed by a previous closeSession() call. |
No action needed. The session is already terminated. Avoid calling closeSession() multiple times on the same session ID. |
client.getSessionStatus(sessionId)
The getSessionStatus() method queries the current state of an existing
BBRE session. It sends a POST request to the /session/status endpoint
with the session ID and returns an object containing the session status, expiration
timestamp, and browser profile data. This method is useful for monitoring session
health in long-running workflows, verifying that a session is still active before
sending requests through it, checking the remaining time before a session expires, and
retrieving the browser profile that was assigned to the session after the first request
was processed. The method does not modify the session in any way and does not extend
the session timeout. It is a read-only operation that simply reports the current state
of the session.
Method Signature
const status = await client.getSessionStatus(sessionId);
Parameters
The getSessionStatus() method accepts a single required parameter: the
session ID string that identifies the session you want to query. This is the same
sessionId value that was returned by createSession().
| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
string | Required | The unique identifier of the session to query. This value is obtained from the sessionId field in the createSession() response. The session must exist in the system. Querying a non-existent session will result in a SESSION_NOT_FOUND error. |
Return Type
The method returns a Promise that resolves to an object containing the
session status information. The returned object includes the current status of the
session, the expiration timestamp, and the browser profile data. If the session does
not exist or the query fails, the method throws an error.
{
"success": true,
"status": "active",
"expiresAt": "2024-12-15T14:30:00.000Z",
"profile": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"platform": "Windows",
"language": "en-US",
"screen": { "width": 1920, "height": 1080 },
"timezone": "America/New_York"
}
}
Return Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true when the status query completes successfully. If the query fails, the method throws an error instead of returning an object with success: false. |
status |
string | The current status of the session. Possible values include "active" (session is running and accepting requests), "expired" (session timeout has elapsed), and "closed" (session was explicitly closed via closeSession()). Only sessions with "active" status can accept new requests. |
expiresAt |
string | The ISO 8601 timestamp indicating when the session will expire (or when it expired, if the status is "expired"). Use this value to calculate the remaining session lifetime and decide whether to extend your workflow or create a new session. |
profile |
object | null | The browser profile assigned to this session. Contains fingerprint details such as userAgent, platform, language, screen dimensions, and timezone. This value may be null if no requests have been processed in the session yet, as the profile is fully populated after the first request. |
Session Status Values
The status field in the response indicates the current lifecycle state of
the session. Understanding these states is important for building robust session
management logic in your application.
| Status | Description | Can Accept Requests |
|---|---|---|
active |
The session is running and ready to accept requests. The browser context is allocated and maintaining state (cookies, local storage, fingerprint). | Yes |
expired |
The session timeout has elapsed. The server automatically closed the session and released its resources. The session data (cookies, profile) is no longer available. | No |
closed |
The session was explicitly terminated by a closeSession() call. All resources have been released and the session slot is available for reuse. |
No |
Basic Usage
The simplest usage of getSessionStatus() retrieves and displays the
current state of a session. This is useful for debugging and monitoring session health
during development.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function checkSessionHealth(sessionId) {
const status = await client.getSessionStatus(sessionId);
console.log("Session status:", status.status);
console.log("Expires at:", status.expiresAt);
console.log("Profile:", status.profile);
return status;
}
checkSessionHealth("sess_a1b2c3d4e5f6");
Check Remaining Session Time
Use the expiresAt field to calculate how much time remains before the
session expires. This is useful for deciding whether to continue using an existing
session or create a new one when the remaining time is too short for your workflow.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function getRemainingTime(sessionId) {
const status = await client.getSessionStatus(sessionId);
if (status.status !== "active") {
console.log("Session is not active. Status:", status.status);
return 0;
}
const expiresAt = new Date(status.expiresAt);
const now = new Date();
const remainingMs = expiresAt.getTime() - now.getTime();
const remainingSeconds = Math.max(0, Math.floor(remainingMs / 1000));
console.log("Remaining time:", remainingSeconds, "seconds");
return remainingSeconds;
}
async function shouldCreateNewSession(sessionId, minimumSecondsNeeded) {
const remaining = await getRemainingTime(sessionId);
if (remaining < minimumSecondsNeeded) {
console.log("Session has insufficient time remaining. Creating a new session.");
return true;
}
console.log("Session has enough time remaining. Continuing with existing session.");
return false;
}
shouldCreateNewSession("sess_a1b2c3d4e5f6", 120);
Error Handling for getSessionStatus()
The getSessionStatus() method throws an error when the session cannot be
found or the query fails. The most common error is SESSION_NOT_FOUND, which occurs
when the session ID is invalid or the session has been removed from the system after
expiration.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function safeGetSessionStatus(sessionId) {
try {
const status = await client.getSessionStatus(sessionId);
return { available: true, data: status };
} catch (error) {
const message = error.message.toLowerCase();
if (message.includes("not found")) {
console.log("Session not found. It may have expired and been cleaned up.");
} else {
console.log("Failed to get session status:", error.message);
}
return { available: false, error: error.message };
}
}
safeGetSessionStatus("sess_a1b2c3d4e5f6");
Session Lifecycle Pattern
The complete session lifecycle follows a predictable pattern: create a session, send one or more requests through it, optionally check its status, and close it when done. This pattern ensures that session resources are properly allocated and released, and that your application does not leak session slots over time. The following examples demonstrate the full lifecycle in different scenarios.
Complete Session Lifecycle
This example demonstrates the full session lifecycle from creation to closure, including sending a request through the session and checking its status. The session is always closed in a finally block to ensure cleanup happens even if an error occurs during the workflow.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive",
sensibility: "medium"
});
async function sessionLifecycleExample() {
let sessionId = null;
try {
const session = await client.createSession({ timeout: 900 });
sessionId = session.sessionId;
console.log("1. Session created:", sessionId);
console.log(" Expires at:", session.expiresAt);
const response = await client.request({
url: "https://api.example.com/data",
method: "GET",
sessionId: sessionId
});
console.log("2. Request completed. Status:", response.statusCode);
const status = await client.getSessionStatus(sessionId);
console.log("3. Session status:", status.status);
console.log(" Profile available:", status.profile !== null);
} catch (error) {
console.log("Workflow error:", error.message);
} finally {
if (sessionId) {
try {
await client.closeSession(sessionId);
console.log("4. Session closed successfully");
} catch (closeError) {
console.log("4. Session cleanup note:", closeError.message);
}
}
}
}
sessionLifecycleExample();
Multi-Step Workflow with Session
Sessions are most valuable when you need to perform multiple related requests that share state. This example demonstrates a multi-step workflow where the session maintains cookies and browser state across a login, data retrieval, and logout sequence.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "high"
});
async function authenticatedDataRetrieval() {
let sessionId = null;
try {
const session = await client.createSession({
mode: "adaptive",
sensibility: "high",
timeout: 1200,
fingerprint: {
platform: "MacIntel",
language: "en-US"
}
});
sessionId = session.sessionId;
console.log("Session created:", sessionId);
const loginResponse = await client.request({
url: "https://app.example.com/login",
method: "POST",
body: {
username: "[email protected]",
password: "secure_password"
},
sessionId: sessionId
});
console.log("Login status:", loginResponse.statusCode);
const dataResponse = await client.request({
url: "https://app.example.com/api/dashboard",
method: "GET",
sessionId: sessionId
});
console.log("Dashboard data retrieved:", dataResponse.statusCode);
const logoutResponse = await client.request({
url: "https://app.example.com/logout",
method: "POST",
sessionId: sessionId
});
console.log("Logout status:", logoutResponse.statusCode);
return dataResponse.data;
} catch (error) {
console.log("Workflow failed:", error.message);
return null;
} finally {
if (sessionId) {
try {
await client.closeSession(sessionId);
console.log("Session closed");
} catch (closeError) {
console.log("Session cleanup:", closeError.message);
}
}
}
}
authenticatedDataRetrieval();
Session with Timeout Awareness
For long-running workflows, periodically check the session status to ensure it has not expired. This pattern is especially important when processing large batches of requests where the total processing time might exceed the session timeout.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function isSessionAlive(sessionId) {
try {
const status = await client.getSessionStatus(sessionId);
if (status.status !== "active") {
return false;
}
const expiresAt = new Date(status.expiresAt);
const now = new Date();
const remainingMs = expiresAt.getTime() - now.getTime();
return remainingMs > 30000;
} catch (error) {
return false;
}
}
async function processUrlsWithSession(urls) {
let sessionId = null;
const results = [];
try {
const session = await client.createSession({ timeout: 1800 });
sessionId = session.sessionId;
console.log("Session created:", sessionId);
for (let i = 0; i < urls.length; i++) {
const alive = await isSessionAlive(sessionId);
if (!alive) {
console.log("Session expired or closing soon. Creating a new session.");
try { await client.closeSession(sessionId); } catch (e) {}
const newSession = await client.createSession({ timeout: 1800 });
sessionId = newSession.sessionId;
console.log("New session created:", sessionId);
}
const response = await client.request({
url: urls[i],
method: "GET",
sessionId: sessionId
});
results.push({ url: urls[i], status: response.statusCode });
console.log("Processed", i + 1, "of", urls.length);
}
} catch (error) {
console.log("Processing error:", error.message);
} finally {
if (sessionId) {
try { await client.closeSession(sessionId); } catch (e) {}
}
}
return results;
}
const urls = [
"https://api.example.com/products/1",
"https://api.example.com/products/2",
"https://api.example.com/products/3"
];
processUrlsWithSession(urls);
Session Pool Management Pattern
When your application needs to handle multiple concurrent workflows, managing individual sessions manually becomes complex and error-prone. A session pool pattern centralizes session creation, allocation, and cleanup into a single manager that ensures you never exceed the 10-session limit, properly closes sessions when they are no longer needed, and reuses existing sessions when possible. The following example demonstrates a practical session pool implementation that you can adapt for your own applications.
Simple Session Pool
This session pool implementation maintains a list of available sessions and provides methods to acquire and release sessions. When a session is acquired, it is removed from the available pool. When it is released, it is returned to the pool for reuse. The pool automatically creates new sessions when the available pool is empty and the total session count is below the maximum limit.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive",
sensibility: "medium"
});
function createSessionPool(maxSize) {
const available = [];
const inUse = new Set();
async function acquire(options) {
if (available.length > 0) {
const sessionId = available.pop();
try {
const status = await client.getSessionStatus(sessionId);
if (status.status === "active") {
inUse.add(sessionId);
console.log("Reusing session:", sessionId);
return sessionId;
}
} catch (error) {
console.log("Stale session removed:", sessionId);
}
}
if (inUse.size >= maxSize) {
throw new Error("Session pool exhausted. All " + maxSize + " sessions are in use.");
}
const session = await client.createSession(options || {});
inUse.add(session.sessionId);
console.log("New session created:", session.sessionId);
return session.sessionId;
}
async function release(sessionId) {
if (inUse.has(sessionId)) {
inUse.delete(sessionId);
available.push(sessionId);
console.log("Session released back to pool:", sessionId);
}
}
async function destroy(sessionId) {
inUse.delete(sessionId);
const index = available.indexOf(sessionId);
if (index !== -1) {
available.splice(index, 1);
}
try {
await client.closeSession(sessionId);
console.log("Session destroyed:", sessionId);
} catch (error) {
console.log("Session destroy note:", error.message);
}
}
async function destroyAll() {
const allSessions = [...available, ...inUse];
available.length = 0;
inUse.clear();
for (const sessionId of allSessions) {
try {
await client.closeSession(sessionId);
} catch (error) {
console.log("Cleanup note for", sessionId, ":", error.message);
}
}
console.log("All sessions destroyed. Pool is empty.");
}
function stats() {
return {
available: available.length,
inUse: inUse.size,
total: available.length + inUse.size,
maxSize: maxSize
};
}
return { acquire, release, destroy, destroyAll, stats };
}
async function useSessionPool() {
const pool = createSessionPool(5);
const session1 = await pool.acquire({ mode: "passive" });
const session2 = await pool.acquire({ mode: "passive" });
console.log("Pool stats:", pool.stats());
await client.request({
url: "https://api.example.com/data",
method: "GET",
sessionId: session1
});
await pool.release(session1);
console.log("Pool stats after release:", pool.stats());
const session3 = await pool.acquire();
console.log("Acquired session (may reuse):", session3);
await pool.destroyAll();
console.log("Final pool stats:", pool.stats());
}
useSessionPool();
Concurrent Workflow with Session Pool
This example demonstrates how to use the session pool to process multiple URLs concurrently, with each concurrent worker acquiring its own session from the pool. The pool ensures that the total number of active sessions never exceeds the configured maximum, and sessions are properly reused across workers.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive",
sensibility: "medium"
});
async function processWithPool(urls, concurrency, pool) {
const results = [];
let index = 0;
async function worker() {
while (index < urls.length) {
const currentIndex = index;
index++;
const url = urls[currentIndex];
let sessionId = null;
try {
sessionId = await pool.acquire({ timeout: 600 });
const response = await client.request({
url: url,
method: "GET",
sessionId: sessionId
});
results[currentIndex] = {
url: url,
status: response.statusCode,
success: true
};
} catch (error) {
results[currentIndex] = {
url: url,
error: error.message,
success: false
};
} finally {
if (sessionId) {
await pool.release(sessionId);
}
}
}
}
const workers = [];
for (let i = 0; i < concurrency; i++) {
workers.push(worker());
}
await Promise.all(workers);
return results;
}
async function main() {
const pool = createSessionPool(3);
const urls = [
"https://api.example.com/products/1",
"https://api.example.com/products/2",
"https://api.example.com/products/3",
"https://api.example.com/products/4",
"https://api.example.com/products/5"
];
const results = await processWithPool(urls, 3, pool);
console.log("Results:", results);
await pool.destroyAll();
}
main();
Error Handling
All three session management methods throw errors when the underlying API request fails. The error message contains a description of what went wrong, extracted from the API response when available. Common error scenarios include authentication failures, session limit violations, invalid parameters, and session state conflicts. The following sections describe the error types for each method and demonstrate robust error handling patterns.
Error Types Overview
The following table lists all error codes that can be returned by the session management methods, along with their causes and recommended solutions.
| Error Code | Method | Cause | Solution |
|---|---|---|---|
API_KEY_REQUIRED |
All | The X-API-Key header is missing because no API key was provided to the BBREClient constructor. |
Pass a valid API key when creating the BBREClient instance. |
INVALID_API_KEY |
All | The provided API key does not match any active account in the BBRE system. | Verify that your API key is correct and has not been revoked. |
INSUFFICIENT_BALANCE |
createSession | Your account does not have enough credits to create a new session. | Recharge your account balance before creating sessions. |
SESSION_LIMIT_REACHED |
createSession | Your account already has 10 active sessions, which is the maximum allowed. | Close one or more existing sessions before creating a new one. Use getAccountInfo() to check the current active session count. |
INVALID_MODE |
createSession | The mode parameter contains an invalid value. Only "passive" and "adaptive" are accepted. |
Use either "passive" or "adaptive" as the mode value. |
INVALID_SENSIBILITY |
createSession | The sensibility parameter contains an invalid value. Only "low", "medium", and "high" are accepted. |
Use "low", "medium", or "high" as the sensibility value. |
SESSION_NOT_FOUND |
closeSession, getSessionStatus | The provided session ID does not match any session in the system. | Verify the session ID is correct. The session may have been automatically removed after expiration. |
SESSION_EXPIRED |
closeSession | The session timeout has elapsed and the session was automatically closed by the server. | No action needed. Create a new session if you need to continue working. |
SESSION_CLOSED |
closeSession | The session has already been closed by a previous closeSession() call. |
No action needed. Avoid calling closeSession() multiple times on the same session. |
SERVICE_UNAVAILABLE |
All | The BBRE service is temporarily unavailable due to maintenance or high load. | Retry the request after a short delay. Implement exponential backoff for repeated failures. |
Comprehensive Error Handling Pattern
The following example demonstrates a robust error handling pattern that categorizes errors by type and takes appropriate action for each category. This pattern is useful for production applications that need to handle all possible failure scenarios gracefully.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
function classifySessionError(error) {
const message = error.message.toLowerCase();
if (message.includes("api key") || message.includes("invalid")) {
return { type: "auth", retryable: false };
}
if (message.includes("limit") || message.includes("maximum")) {
return { type: "limit", retryable: false };
}
if (message.includes("balance") || message.includes("insufficient")) {
return { type: "balance", retryable: false };
}
if (message.includes("not found")) {
return { type: "not_found", retryable: false };
}
if (message.includes("expired")) {
return { type: "expired", retryable: false };
}
if (message.includes("closed")) {
return { type: "already_closed", retryable: false };
}
if (message.includes("unavailable") || message.includes("timeout")) {
return { type: "service", retryable: true };
}
return { type: "unknown", retryable: true };
}
async function createSessionWithRetry(options, maxRetries) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const session = await client.createSession(options);
return session;
} catch (error) {
lastError = error;
const classification = classifySessionError(error);
if (!classification.retryable) {
console.log("Non-retryable error:", classification.type, "-", error.message);
throw error;
}
if (attempt < maxRetries) {
const delay = 1000 * Math.pow(2, attempt - 1);
console.log("Attempt", attempt, "failed. Retrying in", delay, "ms");
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
async function main() {
try {
const session = await createSessionWithRetry({ mode: "passive" }, 3);
console.log("Session created:", session.sessionId);
} catch (error) {
console.log("All attempts failed:", error.message);
}
}
main();
Session Cleanup Patterns
Proper session cleanup is critical for maintaining healthy session slot usage across your account. Leaked sessions (sessions that are created but never closed) occupy session slots until their timeout expires, which can prevent your application from creating new sessions when needed. The following patterns demonstrate different approaches to ensuring sessions are always cleaned up, even when errors occur.
Try-Finally Cleanup
The most reliable cleanup pattern uses a try-finally block to ensure the session is closed regardless of whether the workflow succeeds or fails. The finally block executes even if an exception is thrown, guaranteeing that the session resources are released.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function withSession(options, workFn) {
const session = await client.createSession(options);
const sessionId = session.sessionId;
try {
const result = await workFn(sessionId, session);
return result;
} finally {
try {
await client.closeSession(sessionId);
console.log("Session cleaned up:", sessionId);
} catch (closeError) {
console.log("Session cleanup note:", closeError.message);
}
}
}
async function main() {
const data = await withSession({ mode: "passive", timeout: 600 }, async (sessionId) => {
const response = await client.request({
url: "https://api.example.com/data",
method: "GET",
sessionId: sessionId
});
return response.data;
});
console.log("Retrieved data:", data);
}
main();
Process Exit Cleanup
For long-running Node.js applications, register cleanup handlers for process exit events to ensure sessions are closed when the application shuts down unexpectedly. This prevents session leaks caused by crashes, unhandled exceptions, or manual process termination.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
const activeSessions = new Set();
async function createTrackedSession(options) {
const session = await client.createSession(options);
activeSessions.add(session.sessionId);
return session;
}
async function closeTrackedSession(sessionId) {
try {
await client.closeSession(sessionId);
} catch (error) {
console.log("Close error for", sessionId, ":", error.message);
}
activeSessions.delete(sessionId);
}
async function cleanupAllSessions() {
console.log("Cleaning up", activeSessions.size, "active sessions");
const promises = [];
for (const sessionId of activeSessions) {
promises.push(closeTrackedSession(sessionId));
}
await Promise.all(promises);
console.log("All sessions cleaned up");
}
process.on("SIGINT", async () => {
await cleanupAllSessions();
process.exit(0);
});
process.on("SIGTERM", async () => {
await cleanupAllSessions();
process.exit(0);
});
async function main() {
const session = await createTrackedSession({ mode: "passive" });
console.log("Session created:", session.sessionId);
const response = await client.request({
url: "https://api.example.com/data",
method: "GET",
sessionId: session.sessionId
});
console.log("Response status:", response.statusCode);
await closeTrackedSession(session.sessionId);
}
main();
Best Practices
Wrap your session workflow in a try-finally block and close the session in the
finally clause. This guarantees that the session is closed even if an error occurs
during your workflow, preventing session slot leaks. Each account is limited to 10
active sessions, and leaked sessions remain active until their timeout expires,
which can block your application from creating new sessions when needed. The
withSession() helper pattern shown in the Session Cleanup Patterns
section is a clean way to enforce this practice across your codebase.
Before calling createSession(), use
client.getAccountInfo() to check the
statistics.activeSessions count. If the count is at or near the
maximum of 10, close unused sessions first. This prevents
SESSION_LIMIT_REACHED errors and gives your application a clear
picture of available capacity. For high-throughput applications, consider
implementing a session pool that manages session allocation and reuse
automatically.
Choose a session timeout that matches the expected duration of your workflow plus a reasonable buffer. For quick data retrieval tasks, a timeout of 120 to 300 seconds is usually sufficient. For multi-step workflows involving login, navigation, and data extraction, use 600 to 1200 seconds. For complex browser automation workflows with many steps, consider 1800 to 3600 seconds. Setting the timeout too low risks session expiration mid-workflow, while setting it too high wastes session slots if you forget to close the session manually. The valid range is 60 to 3600 seconds.
Adaptive mode allocates a full browser instance for the session, which consumes more resources and credits than passive mode. If your workflow only needs to send HTTP requests and maintain cookies across them, use passive mode. Switch to adaptive mode only when you need browser actions like navigation, clicking, form filling, or JavaScript execution. This reduces costs and improves session creation speed. You can check the mode requirement for your target website by starting with passive mode and switching to adaptive mode if you encounter detection issues.
Creating a new session for every request is wasteful and slow. Sessions are designed to be reused across multiple related requests. When you need to make several requests to the same website, create a single session and send all requests through it. This maintains cookie state, reduces session creation overhead, and provides a more natural browsing pattern that is less likely to trigger bot detection. Only create separate sessions when you need isolated browser contexts (for example, when simulating different users or testing different configurations).
Set a base fingerprint in the BBREClient constructor with common settings like
platform and screen resolution, then override specific fields per session using the
fingerprint option in createSession(). The shallow merge behavior
means you only need to specify the fields you want to change, keeping your code
clean and maintainable. This is especially useful when you need sessions with
different geographic identities (different timezones and languages) but the same
base browser configuration.
For workflows that run for extended periods, periodically call
getSessionStatus() to verify the session is still active. Check the
expiresAt timestamp and calculate the remaining time. If the remaining
time is less than what you need to complete the next batch of operations, close the
current session and create a new one with a fresh timeout. This prevents unexpected
SESSION_EXPIRED errors in the middle of your workflow.
Common Issues
Symptom: Calling createSession() throws an error
with a message about reaching the session limit.
Cause: Your account already has 10 active sessions, which is the
maximum allowed per account. This often happens when sessions are created but not
properly closed, either because the close call was skipped due to an error, or
because the application exited without cleaning up. Sessions remain active until
their timeout expires, so leaked sessions with long timeouts can block new session
creation for extended periods.
Solution: Close unused sessions by calling
closeSession() for each session you no longer need. Use
getAccountInfo() to check the current active session count. Implement
the try-finally cleanup pattern to ensure sessions are always closed. For
applications that create many sessions, use a session pool to manage allocation
and cleanup automatically.
Symptom: Requests sent through a session fail with a
SESSION_EXPIRED error, even though the session was recently created.
Cause: The session timeout has elapsed. The default timeout is
600 seconds (10 minutes), which may not be enough for complex workflows that
involve many sequential requests with processing time between them. The timeout
starts counting from the moment the session is created, not from the last
request.
Solution: Increase the timeout value when creating the session.
Use timeout: 1800 for workflows that take up to 30 minutes, or
timeout: 3600 for the maximum allowed duration of 1 hour. For very
long workflows, implement the session renewal pattern: periodically check the
remaining time with getSessionStatus() and create a new session
before the current one expires.
Symptom: The profile field in the
createSession() response is null, even though you
expected it to contain browser fingerprint data.
Cause: The browser profile is not always available immediately
at session creation time. The BBRE engine assigns and populates the profile after
the first request is processed within the session. At creation time, the session
exists but the browser context may not have generated its full profile yet.
Solution: If you need the profile data, send at least one request
through the session first, then call getSessionStatus() to retrieve
the populated profile. Do not rely on the profile being available in the
createSession() response.
Symptom: You pass a fingerprint object to
createSession(), but the session profile shows different values than
what you specified.
Cause: The fingerprint parameter is a hint to the BBRE engine,
not an absolute override. The engine may adjust certain fingerprint values to
maintain consistency and avoid detection. For example, if you specify a Windows
platform but a macOS-specific user agent, the engine may correct the mismatch.
Additionally, the fingerprint is merged with the default fingerprint from the
BBREClient constructor, so default values may be applied for fields you did not
explicitly set.
Solution: Provide consistent fingerprint values that do not
conflict with each other. Check the actual profile assigned to the session by
calling getSessionStatus() after the first request. If specific
fingerprint fields are critical for your use case, verify them in the profile
response and create a new session with adjusted values if needed.
Symptom: Calling closeSession() in your cleanup code
throws a SESSION_EXPIRED or SESSION_NOT_FOUND error.
Cause: The session has already expired due to timeout, or it was
automatically cleaned up by the server after expiration. When a session expires,
the server releases its resources, and subsequent close attempts will fail because
the session no longer exists in an active state.
Solution: Always wrap closeSession() calls in a
try-catch block, especially in cleanup code. Treat SESSION_EXPIRED and
SESSION_NOT_FOUND errors as non-critical in cleanup contexts, since the session
resources have already been released. The safeCloseSession() pattern
shown earlier in this page handles this scenario gracefully.
Symptom: You pass a proxy URL to createSession(),
but requests within the session do not appear to use the specified proxy.
Cause: The proxy fallback behavior distinguishes between
undefined (not provided) and null (explicitly no proxy).
If you pass proxy: undefined or omit the proxy field entirely, the
session uses the defaultProxy from the BBREClient constructor. If you
pass proxy: null, the session explicitly disables proxying. Make sure
you are passing the proxy value correctly and not accidentally passing
undefined when you intend to set a specific proxy.
Solution: Explicitly set the proxy value in the options object.
If you want to use a specific proxy, pass it as a string:
proxy: "http://proxy.example.com:8080". If you want to disable
proxying, pass proxy: null. If you want to use the client default,
omit the proxy field entirely.