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

Session Lifecycle Methods

The BBRESession class provides three core lifecycle methods that control the entire lifespan of a browser session on the BBRE engine: start(), close(), and status(). These methods are the foundation of every session-based workflow in the mydisctsolver-bbre SDK. The start() method creates a new server-side browser session, allocates a dedicated browser instance with its own fingerprint profile and cookie store, and returns session metadata including the session ID, expiration timestamp, and the assigned browser profile. The close() method terminates the session, releases the browser instance, and resets all local session state including the session ID, expiration timestamp, cookies, and profile data. The status() method queries the BBRE API for the current state of the active session, returning real-time information about whether the session is still alive, when it expires, and the profile assigned to it. Together, these three methods give you complete control over session creation, monitoring, and teardown. This page documents each method in detail, including method signatures, parameter tables, return types, internal behavior, timeout calculation logic, practical code examples covering basic usage, advanced patterns, error handling, session health monitoring, graceful shutdown, and retry strategies. It also covers the two helper methods getSessionId() and isActive() that provide quick access to session state without making API calls. Whether you are building a simple login-and-scrape workflow or a complex multi-session orchestration system, understanding these lifecycle methods is essential for writing reliable, resource-efficient BBRE applications.

About Session Lifecycle

Every BBRESession workflow follows the same fundamental pattern: start a session, perform your work (send requests, automate browser actions, submit forms), and close the session when done. The BBRE engine allocates a dedicated browser instance for each active session, which means sessions consume server resources. Always close your sessions when you are finished to free those resources and avoid hitting the 10-session-per-account limit. Sessions also have a configurable timeout (between 0.5 and 5 minutes, set via the sessionTime constructor option) after which they expire automatically if no activity is detected. The start() method can override this timeout on a per-session basis through the timeout option, capped at a maximum of 300 seconds.

session.start(options)

The start() method is the entry point for every session-based workflow. It creates a new browser session on the BBRE engine by calling the inherited createSession() method internally, then stores the returned session metadata locally on the BBRESession instance. Once start() completes, the session is active and ready to accept requests, browser actions, and high-level workflows like form submission and multi-step interactions. The method accepts an optional options object that lets you configure the session timeout, browser speed, mode, sensibility, fingerprint, and proxy settings. If you do not provide any options, the session uses the defaults configured in the BBRESession constructor.

Internally, start() performs the following steps: it calculates the timeout value (either from options.timeout capped at 300 seconds, or from the constructor's sessionTime multiplied by 60), calls createSession() with the merged options, stores the returned sessionId, expiresAt, and profile on the instance, optionally overrides the browserSpeed if provided in options, and returns the full session data object. This means that after calling start(), you can immediately use getSessionId(), isActive(), and getProfile() to access the session state without making additional API calls.

Method Signature

JavaScript
const sessionData = await session.start(options);

Parameters

The start() method accepts a single optional options object. All properties within the options object are also optional. When a property is not provided, the session falls back to the value configured in the BBRESession constructor or the BBRE engine defaults.

Parameter Type Required Description
options object Optional Configuration object for the session. All properties are optional. If omitted entirely, the session starts with constructor defaults.
options.timeout number Optional Session timeout in seconds. The value is capped at a maximum of 300 seconds (5 minutes). If not provided, the timeout is calculated from the constructor's sessionTime value multiplied by 60. For example, a sessionTime of 2 (minutes) results in a timeout of 120 seconds.
options.browserSpeed string Optional The browser interaction speed for this session. Valid values are "instant", "fast", and "human". If provided, this overrides the browserSpeed configured in the constructor. The "instant" speed executes actions immediately, "fast" adds minimal delays, and "human" simulates realistic human-like timing between actions.
options.mode string Optional The operating mode for the session. Valid values are "passive" and "adaptive". Passive mode handles simple HTTP requests without browser automation. Adaptive mode enables full browser automation with navigation, clicking, form filling, and other browser actions.
options.sensibility string Optional The sensibility level for the session. Valid values are "low", "medium", and "high". Higher sensibility levels make the browser behave more cautiously, adding extra delays and randomization to avoid detection, but requests take longer to complete.
options.fingerprint object Optional A custom browser fingerprint object containing properties like userAgent, platform, screen, and timezone. If not provided, the BBRE engine generates a realistic fingerprint automatically.
options.proxy string Optional A proxy URL to route the session traffic through. Format: protocol://user:pass@host:port. If not provided, the session uses the BBRE engine's default routing.

Timeout Calculation Logic

The start() method uses a specific algorithm to determine the session timeout value that gets sent to the BBRE API. Understanding this logic is important for controlling how long your sessions stay alive on the server.

If you provide options.timeout, the method takes that value and caps it at 300 seconds using Math.min(options.timeout, 300). This means you cannot create a session that lasts longer than 5 minutes, regardless of the value you pass. If you do not provide options.timeout, the method calculates the timeout from the sessionTime constructor option using Math.round(sessionTime * 60). The sessionTime value is specified in minutes (between 0.5 and 5), so multiplying by 60 converts it to seconds. The Math.round() ensures the result is a clean integer.

Scenario Calculation Result
options.timeout = 120 Math.min(120, 300) 120 seconds
options.timeout = 500 Math.min(500, 300) 300 seconds (capped)
sessionTime = 2 (no options.timeout) Math.round(2 * 60) 120 seconds
sessionTime = 0.5 (no options.timeout) Math.round(0.5 * 60) 30 seconds
sessionTime = 5 (no options.timeout) Math.round(5 * 60) 300 seconds

Return Type

The start() method returns a Promise that resolves to a session data object containing the session ID, expiration timestamp, and the browser profile assigned to the session. This is the same object returned by the underlying createSession() method.

JSON
{
  "success": true,
  "sessionId": "sess_a1b2c3d4e5f6",
  "expiresAt": "2025-01-15T14:35:00.000Z",
  "profile": {
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "platform": "Win32",
    "screen": {
      "width": 1920,
      "height": 1080
    },
    "timezone": "America/New_York",
    "language": "en-US"
  }
}

Return Fields

Field Type Description
success boolean Indicates whether the session was created successfully. Always true when the method resolves without throwing.
sessionId string The unique identifier for the created session. This ID is stored locally on the instance and used automatically for all subsequent session operations.
expiresAt string An ISO 8601 timestamp indicating when the session will expire if no further activity occurs. The session is automatically closed by the server after this time.
profile object The browser fingerprint profile assigned to this session. Contains userAgent, platform, screen, timezone, and language properties that define the browser identity used for all requests in this session.

What start() Stores Locally

After start() completes successfully, it stores three pieces of data on the BBRESession instance that are used by other methods throughout the session lifecycle. Understanding what gets stored helps you reason about the state of your session object at any point in your code.

Property Source Used By
this.sessionId sessionData.sessionId close(), status(), request(), getSessionId(), isActive()
this.sessionExpiresAt sessionData.expiresAt Used internally for expiration tracking. Reset to null when the session is closed.
this.sessionProfile sessionData.profile getProfile(), getProfileSummary(), hasProfile()

Additionally, if options.browserSpeed is provided, the instance's browserSpeed property is updated to the new value. This affects all subsequent browser actions performed through the session's BrowserAPI instance.

Basic Start

The simplest way to start a session is to call start() without any options. The session uses the defaults configured in the constructor, including the sessionTime for timeout calculation and the default mode, sensibility, and browser speed settings.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 2
});

async function basicStart() {
  const sessionData = await session.start();

  console.log("Session started:", sessionData.sessionId);
  console.log("Expires at:", sessionData.expiresAt);
  console.log("Profile user agent:", sessionData.profile.userAgent);
}

basicStart();

Start with Custom Options

You can override the constructor defaults by passing an options object to start(). This is useful when you need different settings for different sessions created from the same BBRESession instance, or when you want to set a specific timeout for a particular workflow.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "low"
});

async function startWithOptions() {
  const sessionData = await session.start({
    timeout: 180,
    browserSpeed: "human",
    sensibility: "high",
    proxy: "http://user:[email protected]:8080"
  });

  console.log("Session ID:", sessionData.sessionId);
  console.log("Timeout set to 180 seconds");
  console.log("Browser speed overridden to human");
  console.log("Sensibility elevated to high for this session");
}

startWithOptions();

Start with Pre-flight Checks

Before starting a session, it is good practice to verify that your account is active, has sufficient balance, and has available session slots. This prevents wasted API calls and provides clear error messages when preconditions are not met. Since BBRESession inherits from BBREClient, you can call getAccountInfo() directly on the session instance.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function startWithPreFlightChecks() {
  const { account, statistics } = await session.getAccountInfo();

  if (account.status !== "active") {
    console.log("Account is not active:", account.status);
    return null;
  }

  if (account.balance < 5) {
    console.log("Insufficient balance:", account.balance);
    return null;
  }

  if (statistics.activeSessions >= 10) {
    console.log("No available session slots:", statistics.activeSessions, "/ 10");
    return null;
  }

  console.log("Pre-flight checks passed");
  console.log("Balance:", account.balance);
  console.log("Available slots:", 10 - statistics.activeSessions);

  const sessionData = await session.start();
  console.log("Session started:", sessionData.sessionId);
  return sessionData;
}

startWithPreFlightChecks();

Start with Timeout Override

The timeout option lets you control exactly how long the session stays alive on the server. This is particularly useful when you know a workflow will be quick and you want to minimize resource usage, or when you need the maximum allowed time for a complex multi-step operation.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sessionTime: 2
});

async function quickSession() {
  const data = await session.start({ timeout: 30 });
  console.log("Quick session (30s):", data.sessionId);

  const response = await session.request({
    url: "https://example.com/api/data",
    method: "GET"
  });

  console.log("Response status:", response.statusCode);
  await session.close();
}

async function longSession() {
  const data = await session.start({ timeout: 300 });
  console.log("Long session (300s max):", data.sessionId);

  const response = await session.request({
    url: "https://example.com/login",
    method: "POST",
    body: { username: "user", password: "pass" }
  });

  console.log("Login response:", response.statusCode);
  await session.close();
}

quickSession();

Error Handling for start()

The start() method can throw errors in several scenarios: when the API key is invalid, when the account has insufficient balance, when the maximum session limit (10 active sessions) has been reached, when the mode or sensibility values are invalid, or when the BBRE service is temporarily unavailable. Always wrap start() in a try-catch block to handle these failures gracefully.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium"
});

async function safeStart() {
  try {
    const sessionData = await session.start({ timeout: 120 });
    console.log("Session started successfully:", sessionData.sessionId);
    return sessionData;
  } catch (error) {
    console.log("Failed to start session:", error.message);
    return null;
  }
}

safeStart();

session.close()

The close() method terminates the active browser session on the BBRE engine and resets all local session state on the BBRESession instance. When you call close(), it sends a close request to the BBRE API using the inherited closeSession() method, which tells the server to shut down the dedicated browser instance, release its resources, and mark the session as closed. After the API call completes, the method resets four local properties to their initial values: sessionId is set to null, sessionExpiresAt is set to null, sessionCookies is set to an empty object {}, and sessionProfile is set to null.

An important design detail of close() is that it only executes the close logic if a sessionId exists on the instance. If sessionId is already null (because the session was never started, was already closed, or was reset for some other reason), the method does nothing and returns silently. This makes close() safe to call multiple times without causing errors or duplicate API calls. You can call it in a finally block without worrying about whether the session was actually started, which simplifies cleanup logic significantly.

Method Signature

JavaScript
await session.close();

Parameters

The close() method does not accept any parameters. It uses the sessionId that was stored locally by the start() method to identify which session to close on the server.

Parameter Type Required Description
This method does not accept any parameters.

Return Type

The method returns a Promise that resolves to undefined. It does not return any data. The purpose of the method is purely to perform the side effect of closing the session and resetting local state.

What close() Resets

After close() completes, the following properties on the BBRESession instance are reset to their initial values. This effectively returns the instance to a "no active session" state, ready to start a new session if needed.

Property Reset Value Effect
this.sessionId null isActive() returns false, getSessionId() returns null
this.sessionExpiresAt null Expiration tracking is cleared
this.sessionCookies {} All cookies accumulated during the session are discarded
this.sessionProfile null getProfile() returns null, hasProfile() returns false

Basic Close

The simplest usage of close() terminates the active session after your work is done. Always close sessions when you are finished to free server resources and make session slots available for future use.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium"
});

async function basicCloseExample() {
  await session.start({ timeout: 120 });
  console.log("Session active:", session.isActive());

  const response = await session.request({
    url: "https://example.com/data",
    method: "GET"
  });
  console.log("Response status:", response.statusCode);

  await session.close();
  console.log("Session active after close:", session.isActive());
}

basicCloseExample();

Try-Finally Cleanup Pattern

The recommended way to use sessions is with a try-finally block that guarantees the session is closed even if an error occurs during your workflow. Since close() is safe to call when no session is active, you can place it in the finally block without any conditional checks. This pattern prevents session leaks that would consume your account's session slots.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function safeWorkflow() {
  try {
    await session.start();
    console.log("Session started:", session.getSessionId());

    const loginResponse = await session.request({
      url: "https://example.com/login",
      method: "POST",
      body: { username: "user", password: "pass" }
    });
    console.log("Login status:", loginResponse.statusCode);

    const dataResponse = await session.request({
      url: "https://example.com/dashboard/data",
      method: "GET"
    });
    console.log("Data retrieved:", dataResponse.statusCode);

    return dataResponse;
  } catch (error) {
    console.log("Workflow error:", error.message);
    return null;
  } finally {
    await session.close();
    console.log("Session closed, resources released");
  }
}

safeWorkflow();

Safe Close (Idempotent Behavior)

Because close() checks for the existence of sessionId before making the API call, you can call it multiple times without errors. This is useful in complex workflows where multiple code paths might attempt to close the session, or when you want to add defensive cleanup calls at multiple points in your code.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive"
});

async function demonstrateIdempotentClose() {
  await session.start({ timeout: 60 });
  console.log("Session active:", session.isActive());

  await session.close();
  console.log("First close: session active:", session.isActive());

  await session.close();
  console.log("Second close: no error, no API call made");

  await session.close();
  console.log("Third close: still safe, still no error");
}

demonstrateIdempotentClose();

Close and Restart Pattern

After closing a session, the BBRESession instance can be reused to start a new session. This is useful for workflows that need to cycle through multiple sessions, for example when you want a fresh browser identity for each batch of requests.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium"
});

async function cycleSessionsForUrls(urls) {
  const batchSize = 5;
  const results = [];

  for (let i = 0; i < urls.length; i += batchSize) {
    const batch = urls.slice(i, i + batchSize);

    try {
      await session.start({ timeout: 120 });
      console.log("New session for batch", Math.floor(i / batchSize) + 1);

      for (const url of batch) {
        const response = await session.request({ url, method: "GET" });
        results.push({ url, status: response.statusCode });
      }
    } catch (error) {
      console.log("Batch error:", error.message);
    } finally {
      await session.close();
    }
  }

  return results;
}

const urls = [
  "https://example.com/page/1",
  "https://example.com/page/2",
  "https://example.com/page/3",
  "https://example.com/page/4",
  "https://example.com/page/5",
  "https://example.com/page/6",
  "https://example.com/page/7"
];

cycleSessionsForUrls(urls);

session.status()

The status() method queries the BBRE API for the current state of the active session. It returns real-time information about whether the session is still alive, when it expires, and the profile assigned to it. Unlike getSessionId() and isActive() which read locally cached values, status() makes an actual API call to the BBRE server, giving you the authoritative, server-side state of the session. This is important because a session might have expired on the server even though the local sessionId is still set, for example if the session timed out due to inactivity.

The method throws an error if no session is currently active on the instance (when sessionId is null). This is a deliberate design choice that prevents you from accidentally querying a non-existent session. Always check isActive() before calling status() if you are not sure whether a session has been started, or wrap the call in a try-catch block.

Internally, status() calls the inherited getSessionStatus() method with the locally stored sessionId. The getSessionStatus() method sends a POST request to the /session/status endpoint on the BBRE API and returns the response data.

Method Signature

JavaScript
const statusData = await session.status();

Parameters

The status() method does not accept any parameters. It uses the sessionId stored locally by the start() method to identify which session to query on the server.

Parameter Type Required Description
This method does not accept any parameters.

Return Type

The method returns a Promise that resolves to a status data object containing the session's current state, expiration timestamp, and profile information.

JSON
{
  "success": true,
  "status": "active",
  "expiresAt": "2025-01-15T14:35:00.000Z",
  "profile": {
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "platform": "Win32",
    "screen": {
      "width": 1920,
      "height": 1080
    },
    "timezone": "America/New_York",
    "language": "en-US"
  }
}

Return Fields

Field Type Description
success boolean Indicates whether the status query was successful.
status string The current state of the session on the server. Possible values include "active", "expired", and "closed". Only sessions with "active" status can accept new requests and browser actions.
expiresAt string An ISO 8601 timestamp indicating when the session will expire. This value is updated by the server each time the session receives activity, extending the expiration window.
profile object The browser fingerprint profile assigned to this session. Same structure as the profile returned by start().

Basic Status Check

The simplest usage of status() retrieves and displays the current state of the active session. This is useful for debugging, logging, and verifying that a session is still alive before performing operations.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium"
});

async function checkSessionStatus() {
  await session.start({ timeout: 120 });
  console.log("Session started:", session.getSessionId());

  const statusData = await session.status();
  console.log("Session status:", statusData.status);
  console.log("Expires at:", statusData.expiresAt);
  console.log("Profile platform:", statusData.profile.platform);

  await session.close();
}

checkSessionStatus();

Remaining Time Calculation

You can calculate the remaining time before a session expires by comparing the expiresAt timestamp from the status response with the current time. This is useful for deciding whether to continue working in the current session or start a new one, and for implementing proactive session renewal before expiration.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function checkRemainingTime() {
  await session.start();

  const statusData = await session.status();
  const expiresAt = new Date(statusData.expiresAt);
  const now = new Date();
  const remainingMs = expiresAt.getTime() - now.getTime();
  const remainingSeconds = Math.floor(remainingMs / 1000);

  console.log("Session status:", statusData.status);
  console.log("Expires at:", statusData.expiresAt);
  console.log("Remaining time:", remainingSeconds, "seconds");

  if (remainingSeconds < 30) {
    console.log("Session is about to expire, consider closing and starting a new one");
  } else {
    console.log("Session has sufficient time remaining");
  }

  await session.close();
}

checkRemainingTime();

Session Health Monitoring Loop

For long-running workflows, you can implement a monitoring loop that periodically checks the session status and takes action when the session is about to expire or has already expired. This pattern is useful for automated pipelines that need to detect and recover from session expiration without manual intervention.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 5
});

async function monitorSessionHealth(checkIntervalMs) {
  await session.start();
  console.log("Session started:", session.getSessionId());

  const monitorInterval = setInterval(async () => {
    try {
      if (!session.isActive()) {
        console.log("Session is no longer active locally, stopping monitor");
        clearInterval(monitorInterval);
        return;
      }

      const statusData = await session.status();
      const expiresAt = new Date(statusData.expiresAt);
      const remainingSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);

      console.log("Health check: status=" + statusData.status + ", remaining=" + remainingSeconds + "s");

      if (statusData.status !== "active") {
        console.log("Session is no longer active on server:", statusData.status);
        clearInterval(monitorInterval);
        await session.close();
      } else if (remainingSeconds < 15) {
        console.log("Session expiring soon, closing and restarting");
        clearInterval(monitorInterval);
        await session.close();
        await session.start();
        console.log("New session started:", session.getSessionId());
      }
    } catch (error) {
      console.log("Health check failed:", error.message);
      clearInterval(monitorInterval);
    }
  }, checkIntervalMs);

  return monitorInterval;
}

monitorSessionHealth(10000);

Error Handling for status()

The status() method throws an error with the message "No active session" if you call it when no session is active on the instance. It can also throw errors if the session has expired on the server, if the session ID is no longer valid, or if the BBRE service is temporarily unavailable.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive"
});

async function safeStatusCheck() {
  if (!session.isActive()) {
    console.log("No active session, cannot check status");
    return null;
  }

  try {
    const statusData = await session.status();
    return statusData;
  } catch (error) {
    console.log("Status check failed:", error.message);
    return null;
  }
}

async function demonstrateStatusError() {
  try {
    await session.status();
  } catch (error) {
    console.log("Expected error:", error.message);
  }

  await session.start({ timeout: 60 });
  const statusData = await session.status();
  console.log("Status after start:", statusData.status);

  await session.close();

  try {
    await session.status();
  } catch (error) {
    console.log("Expected error after close:", error.message);
  }
}

demonstrateStatusError();

Helper Methods: getSessionId() and isActive()

The BBRESession class provides two synchronous helper methods that give you quick access to the session state without making any API calls. These methods read the locally cached sessionId property that is set by start() and cleared by close(). They are useful for conditional logic, logging, debugging, and guard checks before calling methods that require an active session.

session.getSessionId()

Returns the current session ID as a string, or null if no session is active. This method simply returns the value of this.sessionId without any transformation or API call. The returned ID is the same value that was received from the BBRE API when start() was called.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive"
});

async function demonstrateGetSessionId() {
  console.log("Before start:", session.getSessionId());

  await session.start({ timeout: 60 });
  console.log("After start:", session.getSessionId());

  await session.close();
  console.log("After close:", session.getSessionId());
}

demonstrateGetSessionId();

session.isActive()

Returns true if a session ID exists on the instance, false otherwise. This method evaluates !!this.sessionId, which means it returns true for any truthy session ID value and false for null, undefined, or an empty string. Note that isActive() only checks the local state. It does not verify whether the session is still alive on the server. A session might have expired on the server due to inactivity while isActive() still returns true because the local sessionId has not been cleared. To get the authoritative server-side status, use the status() method instead.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive"
});

async function demonstrateIsActive() {
  console.log("Before start:", session.isActive());

  await session.start({ timeout: 60 });
  console.log("After start:", session.isActive());

  await session.close();
  console.log("After close:", session.isActive());
}

demonstrateIsActive();

Using Helpers as Guard Checks

A common pattern is to use isActive() as a guard check before performing session operations. This prevents unnecessary API calls and provides clear error messages when the session is not in the expected state.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium"
});

async function fetchDataIfSessionActive(url) {
  if (!session.isActive()) {
    console.log("No active session. Call session.start() first.");
    return null;
  }

  console.log("Fetching data with session:", session.getSessionId());
  const response = await session.request({ url, method: "GET" });
  return response;
}

async function workflow() {
  const result1 = await fetchDataIfSessionActive("https://example.com/data");
  console.log("Result without session:", result1);

  await session.start({ timeout: 120 });

  const result2 = await fetchDataIfSessionActive("https://example.com/data");
  console.log("Result with session:", result2.statusCode);

  await session.close();
}

workflow();

Helper Methods Reference

Method Returns Makes API Call Description
getSessionId() string | null No Returns the locally stored session ID, or null if no session is active.
isActive() boolean No Returns true if a session ID exists locally, false otherwise. Does not verify server-side status.
status() object Yes Queries the BBRE API for the authoritative server-side session status. Throws if no session is active.

Complete Lifecycle Patterns

This section presents complete, production-ready patterns that combine start(), close(), status(), and the helper methods into cohesive workflows. These patterns address common real-world scenarios including guaranteed cleanup, retry logic, session rotation, and graceful shutdown handling.

Standard Lifecycle Pattern

The standard lifecycle pattern is the foundation for all session-based workflows. It starts a session, performs work inside a try block, and guarantees cleanup in the finally block. This pattern should be your default approach for any session workflow.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function standardLifecycle(targetUrl) {
  try {
    const sessionData = await session.start();
    console.log("Session:", sessionData.sessionId);
    console.log("Profile:", sessionData.profile.userAgent);

    const response = await session.request({
      url: targetUrl,
      method: "GET"
    });

    console.log("Status:", response.statusCode);
    return response;
  } finally {
    await session.close();
    console.log("Cleanup complete");
  }
}

standardLifecycle("https://example.com/data");

Retry with New Session Pattern

When a session-based request fails due to session expiration, server errors, or transient network issues, you can retry the entire workflow with a fresh session. This pattern closes the failed session, starts a new one with a fresh browser identity, and retries the operation. The new session gets a different fingerprint profile, which can help when the failure was caused by the target website blocking the previous browser identity.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "high",
  sessionTime: 2
});

async function requestWithRetry(url, maxRetries) {
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await session.start({ timeout: 120 });
      console.log("Attempt", attempt, "- Session:", session.getSessionId());

      const response = await session.request({ url, method: "GET" });
      console.log("Success on attempt", attempt);

      await session.close();
      return response;
    } catch (error) {
      lastError = error;
      console.log("Attempt", attempt, "failed:", error.message);
      await session.close();

      if (attempt < maxRetries) {
        const delay = 2000 * attempt;
        console.log("Waiting", delay, "ms before retry");
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  throw lastError;
}

async function main() {
  try {
    const response = await requestWithRetry("https://example.com/protected-data", 3);
    console.log("Final result:", response.statusCode);
  } catch (error) {
    console.log("All retries exhausted:", error.message);
  }
}

main();

Session Health Monitoring with Auto-Renewal

For workflows that run for extended periods, implement a health monitoring system that checks the session status periodically and automatically renews the session before it expires. This pattern uses status() to get the remaining time and proactively creates a new session when the current one is about to expire.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function ensureActiveSession(renewalThresholdSeconds) {
  if (!session.isActive()) {
    console.log("No active session, starting new one");
    await session.start();
    return;
  }

  try {
    const statusData = await session.status();

    if (statusData.status !== "active") {
      console.log("Session expired on server, starting new one");
      await session.close();
      await session.start();
      return;
    }

    const expiresAt = new Date(statusData.expiresAt);
    const remainingSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);

    if (remainingSeconds < renewalThresholdSeconds) {
      console.log("Session expiring in", remainingSeconds, "seconds, renewing");
      await session.close();
      await session.start();
    }
  } catch (error) {
    console.log("Status check failed, restarting session:", error.message);
    await session.close();
    await session.start();
  }
}

async function longRunningWorkflow(urls) {
  const results = [];

  for (const url of urls) {
    await ensureActiveSession(30);

    try {
      const response = await session.request({ url, method: "GET" });
      results.push({ url, status: response.statusCode, success: true });
    } catch (error) {
      results.push({ url, error: error.message, success: false });
    }
  }

  await session.close();
  return results;
}

const urls = [
  "https://example.com/page/1",
  "https://example.com/page/2",
  "https://example.com/page/3",
  "https://example.com/page/4",
  "https://example.com/page/5"
];

longRunningWorkflow(urls);

Graceful Shutdown with SIGINT Handler

When running session-based workflows in a Node.js process, it is important to handle process termination signals (like Ctrl+C) gracefully. If the process exits without closing the session, the server-side browser instance remains allocated until it times out, wasting resources and occupying one of your 10 session slots. The following pattern registers a SIGINT handler that closes the session before the process exits.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 5
});

let isShuttingDown = false;

process.on("SIGINT", async () => {
  if (isShuttingDown) return;
  isShuttingDown = true;

  console.log("
Received SIGINT, shutting down gracefully...");

  if (session.isActive()) {
    console.log("Closing active session:", session.getSessionId());
    try {
      await session.close();
      console.log("Session closed successfully");
    } catch (error) {
      console.log("Error closing session:", error.message);
    }
  }

  process.exit(0);
});

async function longRunningProcess() {
  await session.start({ timeout: 300 });
  console.log("Session started:", session.getSessionId());
  console.log("Press Ctrl+C to stop gracefully");

  const urls = [
    "https://example.com/page/1",
    "https://example.com/page/2",
    "https://example.com/page/3",
    "https://example.com/page/4",
    "https://example.com/page/5",
    "https://example.com/page/6",
    "https://example.com/page/7",
    "https://example.com/page/8"
  ];

  for (const url of urls) {
    if (isShuttingDown) {
      console.log("Shutdown requested, stopping work");
      break;
    }

    try {
      const response = await session.request({ url, method: "GET" });
      console.log("Processed:", url, "Status:", response.statusCode);
    } catch (error) {
      console.log("Error processing:", url, error.message);
    }
  }

  if (!isShuttingDown) {
    await session.close();
    console.log("All work completed, session closed");
  }
}

longRunningProcess();

Multi-Step Form Submission with Lifecycle Management

A practical example that combines all lifecycle methods in a real-world scenario: logging into a website, navigating to a form, filling it out, and submitting it, all within a properly managed session lifecycle with error handling and cleanup.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "high",
  browserSpeed: "human",
  sessionTime: 4
});

async function submitApplicationForm(formData) {
  try {
    const sessionData = await session.start({ timeout: 240 });
    console.log("Session ready:", sessionData.sessionId);
    console.log("Browser identity:", sessionData.profile.userAgent);

    const loginResponse = await session.request({
      url: "https://portal.example.com/login",
      method: "POST",
      body: { email: formData.email, password: formData.password }
    });
    console.log("Login:", loginResponse.statusCode);

    const statusCheck = await session.status();
    console.log("Session still active:", statusCheck.status);

    const formResponse = await session.request({
      url: "https://portal.example.com/application/new",
      method: "GET"
    });
    console.log("Form page loaded:", formResponse.statusCode);

    const submitResponse = await session.request({
      url: "https://portal.example.com/application/submit",
      method: "POST",
      body: {
        firstName: formData.firstName,
        lastName: formData.lastName,
        phone: formData.phone,
        address: formData.address
      }
    });
    console.log("Form submitted:", submitResponse.statusCode);

    return { success: true, response: submitResponse };
  } catch (error) {
    console.log("Form submission failed:", error.message);
    return { success: false, error: error.message };
  } finally {
    await session.close();
    console.log("Session closed");
  }
}

submitApplicationForm({
  email: "[email protected]",
  password: "securepassword",
  firstName: "Alice",
  lastName: "Johnson",
  phone: "+1234567890",
  address: "123 Main Street"
});

Parallel Sessions with Independent Lifecycles

When you need to run multiple independent workflows simultaneously, create separate BBRESession instances, each with its own lifecycle. Each instance manages its own session ID, cookies, and profile independently. Be mindful of the 10-session-per-account limit when running parallel sessions.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

async function processUrlWithSession(apiKey, url) {
  const session = new BBRESession({
    apiKey: apiKey,
    mode: "adaptive",
    sensibility: "medium",
    sessionTime: 2
  });

  try {
    await session.start({ timeout: 120 });
    console.log("Session for", url, ":", session.getSessionId());

    const response = await session.request({ url, method: "GET" });
    return { url, status: response.statusCode, sessionId: session.getSessionId() };
  } catch (error) {
    return { url, error: error.message };
  } finally {
    await session.close();
  }
}

async function parallelProcessing(apiKey, urls) {
  const promises = urls.map(url => processUrlWithSession(apiKey, url));
  const results = await Promise.all(promises);

  for (const result of results) {
    if (result.error) {
      console.log("Failed:", result.url, result.error);
    } else {
      console.log("Success:", result.url, "Status:", result.status);
    }
  }

  return results;
}

parallelProcessing("YOUR_API_KEY", [
  "https://example.com/page/1",
  "https://example.com/page/2",
  "https://example.com/page/3"
]);

Error Handling

Each lifecycle method has its own set of potential errors. Understanding when and why each method throws helps you write robust error handling that distinguishes between recoverable and non-recoverable failures. The following table summarizes the error scenarios for each method and the recommended response.

Error Reference

Method Error Scenario Recommended Action
start() Invalid API key or authentication failure Verify your API key configuration. Do not retry with the same key.
start() Insufficient balance to create a session Check your balance with getBalance() and recharge your account.
start() Session limit reached (10 active sessions) Close unused sessions before creating new ones. Use getAccountInfo() to check active session count.
start() Invalid mode or sensibility value Use valid values: mode must be "passive" or "adaptive", sensibility must be "low", "medium", or "high".
start() Service temporarily unavailable Retry after a short delay with exponential backoff.
close() Network error during close request The local state is still reset. The server-side session will expire on its own after the timeout.
status() No active session (sessionId is null) Check isActive() before calling status(), or start a session first.
status() Session expired or closed on server Close the local session and start a new one if needed.
status() Session not found (invalid session ID) The session may have been closed from another process. Close locally and start fresh.

Comprehensive Error Handling Example

The following example demonstrates a robust error handling pattern that categorizes errors by type and takes appropriate action for each category. Authentication and account errors are treated as non-recoverable, while service errors trigger a retry.

JavaScript
const { BBRESession } = require("mydisctsolver-bbre");

const session = new BBRESession({
  apiKey: "YOUR_API_KEY",
  mode: "adaptive",
  sensibility: "medium",
  sessionTime: 3
});

async function resilientWorkflow(url) {
  let result = null;

  try {
    await session.start({ timeout: 180 });
  } catch (error) {
    const msg = error.message.toLowerCase();

    if (msg.includes("api key") || msg.includes("suspended") || msg.includes("inactive")) {
      console.log("Non-recoverable auth error:", error.message);
      return { success: false, errorType: "auth", message: error.message };
    }

    if (msg.includes("session_limit") || msg.includes("limit")) {
      console.log("Session limit reached, cannot create new session");
      return { success: false, errorType: "limit", message: error.message };
    }

    if (msg.includes("insufficient") || msg.includes("balance")) {
      console.log("Insufficient balance:", error.message);
      return { success: false, errorType: "balance", message: error.message };
    }

    console.log("Service error during start:", error.message);
    return { success: false, errorType: "service", message: error.message };
  }

  try {
    const response = await session.request({ url, method: "GET" });
    result = { success: true, statusCode: response.statusCode, data: response };
  } catch (error) {
    console.log("Request error:", error.message);
    result = { success: false, errorType: "request", message: error.message };
  } finally {
    await session.close();
  }

  return result;
}

resilientWorkflow("https://example.com/data");

Best Practices

Always Use Try-Finally for Session Cleanup

Every session workflow should wrap the main logic in a try block with session.close() in the finally block. This guarantees that the session is closed and server resources are released even when errors occur during your workflow. Since close() is safe to call when no session is active, you do not need any conditional checks in the finally block. Failing to close sessions leads to resource leaks where browser instances remain allocated on the server until they time out, wasting your session slots and potentially blocking new session creation when you hit the 10-session limit.

Set Appropriate Timeout Values Based on Your Workflow

Choose your session timeout based on the expected duration of your workflow. For quick data fetching operations, use a short timeout (30 to 60 seconds) to minimize resource usage. For complex multi-step workflows like form submission or multi-page navigation, use a longer timeout (120 to 300 seconds) to avoid premature expiration. Remember that the timeout is capped at 300 seconds regardless of the value you pass to start(). If your workflow might take longer than 5 minutes, break it into multiple sessions or implement the auto-renewal pattern that checks remaining time with status() and creates a new session before the current one expires.

Use isActive() for Local Checks, status() for Server Verification

Use isActive() for quick, synchronous checks when you need to know whether a session has been started locally. It is free (no API call) and fast. Use status() when you need to verify the actual server-side state of the session, for example before performing a critical operation where you need to be certain the session has not expired. Avoid calling status() before every request in a tight loop, as each call makes an API request. Instead, call it periodically (every 30 to 60 seconds) or before important operations.

Implement Pre-flight Checks Before Starting Sessions

Before calling start(), verify that your account is in good standing by calling getAccountInfo(). Check that the account status is active, the balance is sufficient for your planned operations, and the number of active sessions is below the 10-session limit. This prevents wasted API calls and provides clear, actionable error messages instead of cryptic server errors. The pre-flight check adds one extra API call but saves you from debugging failed session creation attempts.

Register SIGINT Handlers for Long-Running Processes

If your application runs as a long-lived Node.js process (a server, a worker, or a CLI tool), register a handler for the SIGINT signal that closes any active sessions before the process exits. Without this handler, pressing Ctrl+C terminates the process immediately, leaving the server-side session allocated until it times out. The graceful shutdown pattern ensures that your session slots are freed immediately, making them available for other processes or future runs.

Reuse BBRESession Instances Across Multiple Sessions

A single BBRESession instance can be used to start, close, and restart sessions multiple times. After calling close(), the instance is reset to its initial state and ready for a new start() call. This is more efficient than creating a new BBRESession instance for each session, because the constructor configuration (API key, mode, sensibility, browser speed) is preserved across session cycles. Create separate instances only when you need different constructor configurations or when running parallel sessions.

Choose Browser Speed Based on Target Website Sensitivity

When starting a session with options.browserSpeed, choose the speed based on how aggressively the target website detects automated traffic. Use "instant" for internal APIs and websites with no bot detection. Use "fast" for most public websites where some timing variation is sufficient. Use "human" for heavily protected websites that analyze interaction timing patterns. You can override the browser speed at session start time without changing the constructor configuration, which is useful when the same application targets websites with different protection levels.

Common Issues

"No active session" Error When Calling status()

Symptom: Calling session.status() throws an error with the message "No active session".
Cause: The status() method requires an active session with a valid sessionId. This error occurs when you call status() before calling start(), after calling close(), or when the session was never started successfully.
Solution: Always check session.isActive() before calling status(), or ensure that start() completed successfully before attempting to check the status. If you need to handle this gracefully, wrap the status() call in a try-catch block.

Session Expires Before Workflow Completes

Symptom: Requests fail with session expired errors partway through a multi-step workflow, even though the session was recently started.
Cause: The session timeout was set too low for the workflow duration. If you use the default sessionTime of 0.5 minutes (30 seconds) and your workflow takes longer than that, the session expires on the server while your code is still running. The local isActive() still returns true because the local state has not been updated.
Solution: Increase the timeout by either setting a higher sessionTime in the constructor (up to 5 minutes) or passing a timeout value to start() (up to 300 seconds). For workflows that might exceed 5 minutes, implement the auto-renewal pattern that periodically checks status() and creates a new session before expiration.

SESSION_LIMIT_REACHED When Starting a New Session

Symptom: Calling session.start() throws an error indicating that the maximum session limit has been reached.
Cause: Your account already has 10 active sessions. This can happen when previous sessions were not closed properly (process crashed, network error during close, or missing finally block), or when multiple processes are creating sessions concurrently.
Solution: Close unused sessions before creating new ones. Use getAccountInfo() to check the statistics.activeSessions count. If you have orphaned sessions from crashed processes, they will expire automatically after their timeout period. To prevent this issue, always use the try-finally pattern and register SIGINT handlers for graceful shutdown.

Timeout Value Ignored or Capped at 300

Symptom: You pass a timeout value greater than 300 to start(), but the session expires after 5 minutes instead of the expected longer duration.
Cause: The start() method caps the timeout at 300 seconds using Math.min(options.timeout, 300). Any value above 300 is silently reduced to 300. This is a server-side limitation to prevent sessions from consuming resources indefinitely.
Solution: Accept the 300-second maximum and design your workflows accordingly. For workflows that need more than 5 minutes, implement session rotation: close the current session and start a new one when the remaining time drops below a threshold. The auto-renewal pattern documented in the lifecycle patterns section handles this automatically.

isActive() Returns True But Requests Fail

Symptom: session.isActive() returns true, but sending requests through the session fails with session expired or session not found errors.
Cause: The isActive() method only checks the local sessionId property. It does not verify the server-side state. If the session expired on the server due to inactivity timeout, the local state still shows an active session because close() was never called.
Solution: Use session.status() to verify the server-side state before critical operations. If status() shows the session is expired or closed, call session.close() to reset the local state and then session.start() to create a new session.

Cookies Lost After close() and start() Cycle

Symptom: After closing a session and starting a new one, the cookies from the previous session are gone, and authenticated pages return login prompts.
Cause: The close() method resets sessionCookies to an empty object {}. Each new session starts with a clean cookie store and a new browser profile. This is by design: sessions are independent, and each one represents a fresh browser identity.
Solution: If you need to maintain authentication across session boundaries, re-authenticate (log in again) at the beginning of each new session. Alternatively, if your workflow requires persistent cookies, keep the same session alive instead of cycling sessions. Use the auto-renewal pattern to extend session lifetime without losing cookies.