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

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.

About Session Management Methods

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

JavaScript
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.

JavaScript
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.

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

JSON
{
  "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).

JavaScript
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.

JavaScript
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.

JavaScript
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

JavaScript
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.

JSON
{
  "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.

JavaScript
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.

JavaScript
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

JavaScript
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.

JSON
{
  "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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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

Always Close Sessions in a Finally Block

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.

Check Active Session Count Before Creating New Sessions

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.

Set Appropriate Timeout Values Based on Your Workflow

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.

Use Adaptive Mode Only When You Need Browser Actions

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.

Reuse Sessions Across Related Requests

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

Use Fingerprint Merging to Customize Per-Session Identity

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.

Monitor Session Status for Long-Running Workflows

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

SESSION_LIMIT_REACHED When Creating Sessions

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.

SESSION_EXPIRED During Workflow Execution

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.

createSession() Returns null Profile

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.

Fingerprint Overrides Not Taking Effect

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.

closeSession() Throws Error for Already Expired Session

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.

Proxy Setting Not Applied to Session

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.