Default Configuration Methods
The BBREClient class provides four default setter methods that let you
change the client's default configuration after construction:
setDefaultFingerprint(), setDefaultProxy(),
setDefaultMode(), and setDefaultSensibility(). These methods
modify the internal default values that the client uses as fallbacks when you call
request(), createSession(), or any of the HTTP convenience
methods (get(), post(), etc.) without explicitly specifying
those parameters. The initial defaults are set through the constructor's config object,
but the setter methods give you the ability to adjust them at any point during your
application's lifecycle without creating a new client instance. This is particularly
useful for applications that need to switch between different proxy servers based on
geographic region, change the operating mode from passive to adaptive mid-workflow,
adjust sensibility levels based on target site behavior, or update fingerprint profiles
to rotate browser identities. Each setter method directly overwrites the corresponding
internal property on the client instance, and the new value takes effect immediately
for all subsequent requests that do not provide their own override. This page documents
all four default setter methods with complete method signatures, parameter descriptions,
detailed explanations of how defaults interact with per-request overrides, practical
code examples for real-world scenarios, best practices, common issues, and links to
related documentation.
When you create a BBREClient instance, the constructor sets initial
defaults from the config object: mode defaults to
"passive", sensibility defaults to
"medium", fingerprint defaults to {}, and
proxy defaults to null. Every time you call
request() or createSession(), the client uses these defaults
as fallback values for any parameter you do not explicitly provide. The four setter
methods documented on this page let you change these defaults after construction. The
new defaults apply to all future calls, but they never retroactively affect requests
that are already in progress. Per-request parameters always take priority over defaults,
so you can override any default on a case-by-case basis without changing the client
configuration.
client.setDefaultFingerprint(fingerprint)
The setDefaultFingerprint() method sets the default browser fingerprint
profile that the client uses for all subsequent requests and sessions. A fingerprint
object describes the browser identity that the BBRE engine should emulate when
processing your request, including properties like userAgent,
platform, screen resolution, timezone, and
language. When you call request() or
createSession(), the client merges the default fingerprint with any
per-request fingerprint you provide using the JavaScript spread operator. The
per-request fingerprint properties take priority, so you can selectively override
specific fields while keeping the rest of the default profile intact. If you pass a
falsy value (such as null, undefined, or false)
to this method, the default fingerprint resets to an empty object {},
which means the BBRE engine will use its own automatically generated fingerprint
profile for subsequent requests.
Method Signature
client.setDefaultFingerprint(fingerprint);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
fingerprint |
object | Optional |
A fingerprint object containing browser identity properties such as
userAgent, platform, screen,
timezone, and language. If a falsy value is
provided, the default fingerprint resets to an empty object
{}.
|
Return Type
This method does not return a value. It modifies the internal
defaultFingerprint property on the client instance directly.
Fingerprint Merge Behavior
Understanding how the default fingerprint merges with per-request fingerprints is
critical for using this method effectively. When you call request() or
createSession(), the client creates a merged fingerprint using the
JavaScript spread operator:
{ ...this.defaultFingerprint, ...fingerprint }. This means the default
fingerprint serves as the base layer, and any properties you specify in the per-request
fingerprint object overwrite the corresponding default properties. Properties that
exist only in the default fingerprint are preserved in the merged result. Properties
that exist only in the per-request fingerprint are added to the merged result. If both
objects define the same property, the per-request value wins.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultFingerprint({
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
platform: "Win32",
language: "en-US",
timezone: "America/New_York"
});
const response = await client.request({
url: "https://httpbin.org/headers",
fingerprint: {
timezone: "Europe/London",
screen: { width: 1920, height: 1080 }
}
});
console.log("Request sent with merged fingerprint:");
console.log(" userAgent: from default (Mozilla/5.0 ...)");
console.log(" platform: from default (Win32)");
console.log(" language: from default (en-US)");
console.log(" timezone: overridden to Europe/London");
console.log(" screen: added from per-request (1920x1080)");
Setting a Complete Fingerprint Profile
The most common use case is setting a complete fingerprint profile that represents a specific browser identity. This profile will be used as the base for all requests unless overridden.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultFingerprint({
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
platform: "MacIntel",
language: "en-US",
timezone: "America/Los_Angeles",
screen: { width: 2560, height: 1440 }
});
const response = await client.get("https://httpbin.org/headers");
console.log("Status:", response.statusCode);
Rotating Fingerprint Profiles
For applications that need to rotate browser identities across requests, you can call
setDefaultFingerprint() before each batch of requests to switch the
active profile. This is useful when scraping multiple websites that might correlate
requests based on fingerprint consistency.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
const profiles = [
{
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
platform: "Win32",
language: "en-US",
timezone: "America/New_York"
},
{
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
platform: "MacIntel",
language: "en-GB",
timezone: "Europe/London"
},
{
userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
platform: "Linux x86_64",
language: "de-DE",
timezone: "Europe/Berlin"
}
];
async function scrapeWithRotation(urls) {
const results = [];
for (let i = 0; i < urls.length; i++) {
const profile = profiles[i % profiles.length];
client.setDefaultFingerprint(profile);
console.log("Using profile:", profile.platform, "-", profile.timezone);
const response = await client.get(urls[i]);
results.push({ url: urls[i], status: response.statusCode });
}
return results;
}
const urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3"
];
scrapeWithRotation(urls);
Resetting the Default Fingerprint
To clear the default fingerprint and let the BBRE engine generate its own fingerprint
profile automatically, pass a falsy value to the method. The internal implementation
uses fingerprint || {}, so passing null,
undefined, false, 0, or an empty string all
result in the default fingerprint being reset to an empty object.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
fingerprint: {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
platform: "Win32"
}
});
const response1 = await client.get("https://httpbin.org/headers");
console.log("Request 1: used custom fingerprint from constructor");
client.setDefaultFingerprint(null);
const response2 = await client.get("https://httpbin.org/headers");
console.log("Request 2: BBRE engine generates its own fingerprint");
client.setDefaultProxy(proxy)
The setDefaultProxy() method sets the default proxy server URL that the
client uses for all subsequent requests and sessions. The proxy value is a string
containing the full proxy URL including the protocol, authentication credentials (if
needed), host, and port. When you call request() or
createSession() without specifying a proxy parameter, the
client uses this default proxy. You can also pass null to explicitly
indicate that no proxy should be used by default. Understanding the distinction between
undefined and null in the proxy resolution logic is important:
when a per-request proxy parameter is undefined (meaning it
was not provided at all), the client falls back to the default proxy. When a per-request
proxy parameter is explicitly set to null, it overrides the
default and tells the BBRE engine to make the request without any proxy, regardless of
what the default is set to.
Method Signature
client.setDefaultProxy(proxy);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
proxy |
string | null | Required |
The proxy server URL in the format
protocol://user:pass@host:port or
protocol://host:port. Pass null to explicitly
clear the default proxy and make requests without a proxy.
|
Return Type
This method does not return a value. It modifies the internal
defaultProxy property on the client instance directly.
Proxy Resolution Logic
The proxy resolution in request() and createSession() uses a
specific pattern that distinguishes between "not provided" and "explicitly null". The
internal logic is: const finalProxy = proxy !== undefined ? proxy : this.defaultProxy;.
This means if you pass proxy: "http://myproxy:8080" in the request
options, that proxy is used regardless of the default. If you pass
proxy: null, no proxy is used regardless of the default. If you omit the
proxy parameter entirely (so it is undefined), the default
proxy is used. This three-state logic gives you full control over proxy behavior at
both the client level and the individual request level.
| Per-request proxy | Default proxy | Final proxy used |
|---|---|---|
"http://proxy-a:8080" |
"http://proxy-b:8080" |
"http://proxy-a:8080" (per-request wins) |
null |
"http://proxy-b:8080" |
null (no proxy, explicit override) |
undefined (not provided) |
"http://proxy-b:8080" |
"http://proxy-b:8080" (default used) |
undefined (not provided) |
null |
null (no proxy) |
Setting a Default Proxy
The most straightforward use case is setting a proxy that all requests should route
through. Once set, every call to request(), get(),
post(), and other HTTP methods will use this proxy unless explicitly
overridden.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultProxy("http://user:[email protected]:8080");
const response1 = await client.get("https://httpbin.org/ip");
console.log("Request 1 routed through proxy.example.com");
const response2 = await client.get("https://httpbin.org/headers");
console.log("Request 2 also routed through proxy.example.com");
Overriding the Default Proxy Per Request
Even with a default proxy set, you can override it for individual requests by passing
a proxy parameter in the request options. You can also explicitly bypass
the proxy by passing null.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultProxy("http://us-proxy.example.com:8080");
const response1 = await client.get("https://httpbin.org/ip");
console.log("Used default US proxy");
const response2 = await client.request({
url: "https://httpbin.org/ip",
proxy: "http://eu-proxy.example.com:8080"
});
console.log("Used EU proxy override for this request");
const response3 = await client.request({
url: "https://httpbin.org/ip",
proxy: null
});
console.log("No proxy used for this request (explicit null override)");
Multi-Region Proxy Rotation
For applications that need to distribute requests across different geographic regions, you can rotate the default proxy between batches of requests. This pattern is useful for geo-targeted scraping, load distribution across proxy providers, and avoiding rate limits on specific proxy IP addresses.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
const regionProxies = {
us: "http://user:[email protected]:8080",
eu: "http://user:[email protected]:8080",
asia: "http://user:[email protected]:8080"
};
async function scrapeByRegion(regionUrls) {
const results = {};
for (const [region, urls] of Object.entries(regionUrls)) {
client.setDefaultProxy(regionProxies[region]);
console.log("Switched to", region, "proxy");
results[region] = [];
for (const url of urls) {
const response = await client.get(url);
results[region].push({ url, status: response.statusCode });
}
}
return results;
}
const regionUrls = {
us: ["https://us-store.example.com/products", "https://us-store.example.com/prices"],
eu: ["https://eu-store.example.com/products", "https://eu-store.example.com/prices"],
asia: ["https://asia-store.example.com/products", "https://asia-store.example.com/prices"]
};
scrapeByRegion(regionUrls);
Clearing the Default Proxy
To remove the default proxy and make all subsequent requests go directly through the
BBRE engine without a proxy, pass null to the method.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
proxy: "http://user:[email protected]:8080"
});
const response1 = await client.get("https://httpbin.org/ip");
console.log("Request 1: routed through constructor proxy");
client.setDefaultProxy(null);
const response2 = await client.get("https://httpbin.org/ip");
console.log("Request 2: no proxy, direct BBRE engine connection");
client.setDefaultMode(mode)
The setDefaultMode() method sets the default operating mode that the
client uses for all subsequent requests and sessions. The BBRE engine supports two
operating modes: "passive" and "adaptive". Passive mode
handles requests through a lightweight HTTP pipeline without launching a full browser
instance, making it faster and cheaper for simple data retrieval tasks. Adaptive mode
launches a full browser environment with JavaScript execution, DOM rendering, and
anti-detection measures, making it suitable for websites that require browser-level
interaction or have sophisticated bot detection. When you call request()
or createSession() without specifying a mode parameter, the
client uses this default mode. The constructor sets the initial default mode to
"passive" unless you specify a different value in the config object.
Calling setDefaultMode() lets you switch the default mode at any point
during your application's lifecycle, which is particularly useful for workflows that
start with passive mode for initial data gathering and then switch to adaptive mode
when they encounter pages that require full browser rendering.
Method Signature
client.setDefaultMode(mode);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
mode |
string | Required |
The operating mode to use as the default. Must be either
"passive" for lightweight HTTP requests or
"adaptive" for full browser-based requests. Passing an
invalid value will cause the BBRE API to return an
INVALID_MODE error when the next request is submitted.
|
Return Type
This method does not return a value. It modifies the internal
defaultMode property on the client instance directly.
Mode Comparison
The following table summarizes the key differences between passive and adaptive modes to help you decide which mode to set as your default.
| Characteristic | Passive Mode | Adaptive Mode |
|---|---|---|
| Browser instance | No browser launched | Full browser environment |
| JavaScript execution | Not supported | Full JavaScript support |
| Browser actions (click, fill, navigate) | Not available | Fully supported |
| Speed | Faster (no browser overhead) | Slower (browser startup and rendering) |
| Cost per request | Lower | Higher |
| Anti-detection level | Basic HTTP-level | Full browser-level fingerprinting |
| Best for | APIs, static pages, simple data retrieval | SPAs, JavaScript-heavy sites, form interactions |
Switching from Passive to Adaptive Mid-Workflow
A common pattern is to start with passive mode for initial page discovery and data gathering, then switch to adaptive mode when you encounter pages that require full browser rendering. This approach minimizes cost by using the cheaper passive mode wherever possible.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive"
});
async function smartScrape(url) {
const passiveResponse = await client.get(url);
if (passiveResponse.body && passiveResponse.body.includes("Enable JavaScript")) {
console.log("Page requires JavaScript, switching to adaptive mode");
client.setDefaultMode("adaptive");
const adaptiveResponse = await client.get(url);
console.log("Adaptive response status:", adaptiveResponse.statusCode);
return adaptiveResponse;
}
console.log("Passive mode worked, status:", passiveResponse.statusCode);
return passiveResponse;
}
smartScrape("https://example.com/dynamic-page");
Environment-Based Mode Configuration
In development and testing environments, you might want to use passive mode for speed, while production environments use adaptive mode for reliability against bot detection. Set the default mode based on an environment variable after constructing the client.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: process.env.BBRE_API_KEY });
const environment = process.env.NODE_ENV || "development";
if (environment === "production") {
client.setDefaultMode("adaptive");
console.log("Production mode: using adaptive for maximum reliability");
} else {
client.setDefaultMode("passive");
console.log("Development mode: using passive for faster iteration");
}
const response = await client.get("https://example.com/data");
console.log("Response status:", response.statusCode);
Per-Request Mode Override
Even with a default mode set, you can override it for individual requests by passing
a mode parameter in the request options. This is useful when most of your
requests work fine in passive mode but a few specific URLs require adaptive mode.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive"
});
const apiResponse = await client.get("https://api.example.com/data");
console.log("API call used passive mode (default)");
const spaResponse = await client.request({
url: "https://spa.example.com/dashboard",
mode: "adaptive"
});
console.log("SPA page used adaptive mode (per-request override)");
const anotherApiResponse = await client.get("https://api.example.com/users");
console.log("Another API call used passive mode (default still active)");
client.setDefaultSensibility(sensibility)
The setDefaultSensibility() method sets the default sensibility level
that the client uses for all subsequent requests and sessions. Sensibility controls
how carefully the BBRE engine processes your request in terms of anti-detection
measures, timing patterns, and behavioral simulation. The three available levels are
"low", "medium", and "high". Low sensibility
processes requests quickly with minimal anti-detection overhead, making it suitable
for targets with no or basic bot protection. Medium sensibility applies a balanced
set of anti-detection measures and is the default level set by the constructor. High
sensibility applies the most thorough anti-detection measures including realistic
timing delays, human-like behavioral patterns, and advanced fingerprint consistency
checks, making it suitable for heavily protected websites but at the cost of slower
request processing. When you call request() or
createSession() without specifying a sensibility parameter,
the client uses this default sensibility level. Calling
setDefaultSensibility() lets you adjust the protection level dynamically
based on the target website's detection capabilities.
Method Signature
client.setDefaultSensibility(sensibility);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
sensibility |
string | Required |
The sensibility level to use as the default. Must be one of
"low", "medium", or "high".
Passing an invalid value will cause the BBRE API to return an
INVALID_SENSIBILITY error when the next request is submitted.
|
Return Type
This method does not return a value. It modifies the internal
defaultSensibility property on the client instance directly.
Sensibility Level Comparison
The following table summarizes the trade-offs between the three sensibility levels to help you choose the right default for your use case.
| Characteristic | Low | Medium | High |
|---|---|---|---|
| Processing speed | Fastest | Moderate | Slowest |
| Anti-detection measures | Minimal | Balanced | Maximum |
| Timing simulation | No artificial delays | Basic timing patterns | Human-like timing with randomization |
| Fingerprint consistency | Basic | Standard checks | Advanced consistency validation |
| Cost per request | Lowest | Standard | Highest |
| Best for | Friendly APIs, internal tools, testing | Most websites, general scraping | Heavily protected sites, Cloudflare, Akamai |
Adjusting Sensibility Based on Target
Different target websites have different levels of bot protection. You can adjust the default sensibility based on which website you are targeting to optimize the balance between speed and detection avoidance.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
const siteSensibility = {
"api.example.com": "low",
"shop.example.com": "medium",
"bank.example.com": "high"
};
async function scrapeMultipleSites(siteUrls) {
const results = {};
for (const [site, urls] of Object.entries(siteUrls)) {
const level = siteSensibility[site] || "medium";
client.setDefaultSensibility(level);
console.log("Set sensibility to", level, "for", site);
results[site] = [];
for (const url of urls) {
const response = await client.get(url);
results[site].push({ url, status: response.statusCode });
}
}
return results;
}
const siteUrls = {
"api.example.com": ["https://api.example.com/v1/products", "https://api.example.com/v1/categories"],
"shop.example.com": ["https://shop.example.com/deals", "https://shop.example.com/new-arrivals"],
"bank.example.com": ["https://bank.example.com/rates", "https://bank.example.com/exchange"]
};
scrapeMultipleSites(siteUrls);
Escalating Sensibility on Failure
A practical pattern is to start with low sensibility for speed and automatically escalate to higher levels when requests fail due to bot detection. This approach gives you the best performance for easy targets while still handling protected sites.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function requestWithEscalation(url) {
const levels = ["low", "medium", "high"];
for (const level of levels) {
client.setDefaultSensibility(level);
console.log("Trying with sensibility:", level);
try {
const response = await client.get(url);
if (response.statusCode === 200) {
console.log("Success with sensibility:", level);
return response;
}
if (response.statusCode === 403 || response.statusCode === 429) {
console.log("Blocked with sensibility:", level, "- escalating");
continue;
}
return response;
} catch (error) {
console.log("Error with sensibility:", level, "-", error.message);
continue;
}
}
console.log("All sensibility levels failed for:", url);
return null;
}
requestWithEscalation("https://protected-site.example.com/data");
Per-Request Sensibility Override
Like all default settings, the sensibility can be overridden on a per-request basis. This is useful when most of your requests target sites with moderate protection but a few specific endpoints require higher sensibility.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
sensibility: "medium"
});
const regularPage = await client.get("https://example.com/products");
console.log("Regular page: used medium sensibility (default)");
const protectedPage = await client.request({
url: "https://example.com/checkout",
sensibility: "high"
});
console.log("Checkout page: used high sensibility (per-request override)");
const apiEndpoint = await client.request({
url: "https://api.example.com/v1/data",
sensibility: "low"
});
console.log("API endpoint: used low sensibility (per-request override)");
Combining Multiple Defaults
In real-world applications, you rarely change just one default at a time. The four setter methods work together to define a complete request profile. You can call them in any order, and each one independently modifies its corresponding default value. The following examples demonstrate common patterns for configuring multiple defaults together.
Full Configuration After Construction
Sometimes you want to create the client with just the API key and configure all defaults separately, perhaps because the configuration values come from different sources (environment variables, config files, database records).
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: process.env.BBRE_API_KEY });
client.setDefaultMode(process.env.BBRE_MODE || "passive");
client.setDefaultSensibility(process.env.BBRE_SENSIBILITY || "medium");
client.setDefaultProxy(process.env.BBRE_PROXY || null);
client.setDefaultFingerprint({
userAgent: process.env.BBRE_USER_AGENT || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
platform: process.env.BBRE_PLATFORM || "Win32",
language: process.env.BBRE_LANGUAGE || "en-US"
});
console.log("Client configured from environment variables");
const response = await client.get("https://example.com/data");
console.log("Response status:", response.statusCode);
Target-Specific Configuration Profiles
When your application scrapes multiple websites with different protection levels, you can define configuration profiles for each target and apply them by calling all four setter methods together before processing each target's URLs.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
const targetProfiles = {
"simple-api": {
mode: "passive",
sensibility: "low",
proxy: null,
fingerprint: {}
},
"ecommerce-site": {
mode: "passive",
sensibility: "medium",
proxy: "http://user:[email protected]:8080",
fingerprint: {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
platform: "Win32",
language: "en-US"
}
},
"protected-portal": {
mode: "adaptive",
sensibility: "high",
proxy: "http://user:[email protected]:8080",
fingerprint: {
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
platform: "MacIntel",
language: "en-US",
timezone: "America/New_York",
screen: { width: 1920, height: 1080 }
}
}
};
function applyProfile(profileName) {
const profile = targetProfiles[profileName];
if (!profile) {
console.log("Unknown profile:", profileName);
return;
}
client.setDefaultMode(profile.mode);
client.setDefaultSensibility(profile.sensibility);
client.setDefaultProxy(profile.proxy);
client.setDefaultFingerprint(profile.fingerprint);
console.log("Applied profile:", profileName);
}
async function scrapeWithProfiles(tasks) {
const results = [];
for (const task of tasks) {
applyProfile(task.profile);
for (const url of task.urls) {
const response = await client.get(url);
results.push({ profile: task.profile, url, status: response.statusCode });
}
}
return results;
}
const tasks = [
{
profile: "simple-api",
urls: ["https://api.example.com/v1/products", "https://api.example.com/v1/categories"]
},
{
profile: "ecommerce-site",
urls: ["https://shop.example.com/deals", "https://shop.example.com/bestsellers"]
},
{
profile: "protected-portal",
urls: ["https://portal.example.com/dashboard"]
}
];
scrapeWithProfiles(tasks);
Defaults with Session Creation
The default values also apply when creating sessions with createSession().
The session inherits the default mode, sensibility, fingerprint, and proxy from the
client unless you override them in the session options. This means you can configure
the client once and create multiple sessions that all share the same configuration.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultMode("adaptive");
client.setDefaultSensibility("high");
client.setDefaultProxy("http://user:[email protected]:8080");
client.setDefaultFingerprint({
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
platform: "Win32",
language: "en-US"
});
const session1 = await client.createSession();
console.log("Session 1 created with all defaults (adaptive, high, proxy, fingerprint)");
const session2 = await client.createSession({
mode: "passive",
sensibility: "low"
});
console.log("Session 2 created with mode/sensibility overrides but default proxy/fingerprint");
await client.closeSession(session1.sessionId);
await client.closeSession(session2.sessionId);
Dynamic Reconfiguration During Long-Running Tasks
For long-running scraping tasks that process thousands of URLs, you might need to reconfigure the client mid-execution based on observed results. For example, if you notice an increase in blocked requests, you can escalate the sensibility and switch to a different proxy without stopping the process.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive",
sensibility: "low"
});
async function adaptiveScrape(urls) {
let successCount = 0;
let failCount = 0;
const results = [];
for (let i = 0; i < urls.length; i++) {
const response = await client.get(urls[i]);
results.push({ url: urls[i], status: response.statusCode });
if (response.statusCode === 200) {
successCount++;
} else {
failCount++;
}
if ((i + 1) % 50 === 0) {
const recentResults = results.slice(-50);
const recentFailRate = recentResults.filter(r => r.status !== 200).length / 50;
if (recentFailRate > 0.3) {
console.log("High failure rate detected:", (recentFailRate * 100).toFixed(1) + "%");
console.log("Escalating configuration...");
client.setDefaultSensibility("high");
client.setDefaultMode("adaptive");
client.setDefaultProxy("http://user:[email protected]:8080");
console.log("Switched to adaptive mode with high sensibility and premium proxy");
}
}
}
console.log("Completed:", urls.length, "URLs");
console.log("Success:", successCount, "Failed:", failCount);
return results;
}
Constructor Config vs. Setter Methods
You can set default values in two ways: through the constructor config object when creating the client, or by calling the setter methods after construction. Both approaches produce the same result. The constructor approach is convenient when you know all your configuration values upfront. The setter approach is useful when configuration values are loaded asynchronously, come from different sources, or need to change during the application's lifecycle. You can also combine both approaches by setting initial values in the constructor and adjusting them later with the setters.
Equivalent Configuration Examples
The following two code blocks produce identical client configurations. The first uses the constructor config object, and the second uses the setter methods.
const BBREClient = require("mydisctsolver-bbre");
const clientA = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "adaptive",
sensibility: "high",
proxy: "http://user:[email protected]:8080",
fingerprint: {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
platform: "Win32"
}
});
const BBREClient = require("mydisctsolver-bbre");
const clientB = new BBREClient({ apiKey: "YOUR_API_KEY" });
clientB.setDefaultMode("adaptive");
clientB.setDefaultSensibility("high");
clientB.setDefaultProxy("http://user:[email protected]:8080");
clientB.setDefaultFingerprint({
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
platform: "Win32"
});
Async Configuration Loading
When your configuration values come from an asynchronous source such as a database, remote config service, or encrypted vault, you need to create the client first and then apply the configuration after the async operation completes. The setter methods are designed for exactly this scenario.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
async function loadAndApplyConfig() {
const config = await fetchConfigFromDatabase();
if (config.mode) {
client.setDefaultMode(config.mode);
}
if (config.sensibility) {
client.setDefaultSensibility(config.sensibility);
}
if (config.proxy) {
client.setDefaultProxy(config.proxy);
}
if (config.fingerprint) {
client.setDefaultFingerprint(config.fingerprint);
}
console.log("Configuration loaded and applied");
}
async function fetchConfigFromDatabase() {
return {
mode: "adaptive",
sensibility: "high",
proxy: "http://user:[email protected]:8080",
fingerprint: {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
platform: "Win32"
}
};
}
loadAndApplyConfig();
Override Priority Chain
When the client processes a request, it resolves each configuration value through a priority chain. Understanding this chain is essential for predicting which value will be used in any given scenario. The priority order from highest to lowest is: per-request parameter, then client default (set via constructor or setter method), then built-in fallback. The following table shows the complete resolution chain for each configuration value.
| Configuration | Priority 1 (Highest) | Priority 2 | Priority 3 (Lowest) |
|---|---|---|---|
| Mode | Per-request mode parameter |
this.defaultMode (setter or constructor) |
"passive" (built-in fallback) |
| Sensibility | Per-request sensibility parameter |
this.defaultSensibility (setter or constructor) |
"medium" (built-in fallback) |
| Proxy | Per-request proxy parameter (including null) |
this.defaultProxy (setter or constructor) |
null (no proxy) |
| Fingerprint | Merged: { ...defaultFingerprint, ...requestFingerprint } |
this.defaultFingerprint (setter or constructor) |
{} (engine auto-generates) |
Notice that fingerprint behaves differently from the other three configuration values. Mode, sensibility, and proxy use a simple override pattern where the per-request value completely replaces the default. Fingerprint uses a merge pattern where the default fingerprint and per-request fingerprint are combined using the spread operator. This means per-request fingerprint properties override matching default properties, but non-overlapping default properties are preserved. If you want to completely replace the default fingerprint for a specific request, you need to include all desired properties in the per-request fingerprint object.
Priority Chain in Action
The following example demonstrates how the priority chain resolves each configuration value across three different requests using the same client.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({ apiKey: "YOUR_API_KEY" });
client.setDefaultMode("passive");
client.setDefaultSensibility("medium");
client.setDefaultProxy("http://default-proxy:8080");
client.setDefaultFingerprint({ userAgent: "DefaultUA", platform: "Win32" });
const response1 = await client.get("https://example.com/page1");
console.log("Request 1 uses: passive, medium, default-proxy, {userAgent: DefaultUA, platform: Win32}");
const response2 = await client.request({
url: "https://example.com/page2",
mode: "adaptive",
sensibility: "high"
});
console.log("Request 2 uses: adaptive (override), high (override), default-proxy, {userAgent: DefaultUA, platform: Win32}");
const response3 = await client.request({
url: "https://example.com/page3",
proxy: null,
fingerprint: { userAgent: "CustomUA", timezone: "Europe/Berlin" }
});
console.log("Request 3 uses: passive, medium, no proxy (null override), {userAgent: CustomUA, platform: Win32, timezone: Europe/Berlin}");
Best Practices
If you know your configuration values at the time of client creation, pass them through the constructor config object instead of calling setter methods separately. This makes your code more readable and ensures the client is fully configured from the first request. Reserve the setter methods for scenarios where configuration values are loaded asynchronously, change during runtime, or come from different sources that are not all available at construction time.
When most of your requests share the same configuration but a few need different settings, set the common configuration as defaults and use per-request overrides for the exceptions. Avoid calling setter methods back and forth between individual requests, as this makes the code harder to follow and introduces the risk of forgetting to reset the default after a special request. The per-request override pattern is cleaner because it does not modify the client state.
Set the default sensibility to "low" or "medium" and
only escalate to "high" when you encounter bot detection issues.
Higher sensibility levels add processing overhead and increase request latency.
Many websites work perfectly fine with low sensibility, so starting high wastes
resources. Implement an escalation pattern that automatically increases sensibility
when requests fail with 403 or 429 status codes, and you will get the best balance
between speed and reliability.
When rotating browser identities to avoid detection, always change the fingerprint and proxy together. A consistent fingerprint coming from different IP addresses, or different fingerprints coming from the same IP address, can trigger bot detection systems that correlate these signals. Create complete profiles that pair a specific fingerprint with a specific proxy and rotate the entire profile as a unit using the setter methods.
Keep "passive" as your default mode and switch to
"adaptive" only for targets that require full browser rendering.
Passive mode is significantly faster and cheaper than adaptive mode. If you set
adaptive as the default, every request pays the browser startup cost even when it
is not needed. Use per-request overrides or change the default temporarily when
processing a batch of URLs that require adaptive mode, then switch back to passive
when done.
The setter methods modify the client instance directly, and the changes affect all
subsequent requests made through that instance. In applications that process
multiple tasks concurrently (for example, using Promise.all()), calling
a setter method in one task can unexpectedly affect requests in another task that
shares the same client instance. To avoid this, either use per-request overrides
instead of setter methods in concurrent code, or create separate client instances
for each concurrent task.
Common Issues
Symptom: You set a default proxy with
setDefaultProxy(), but some requests are not using it even though you
did not intend to override it.
Cause: The proxy resolution logic distinguishes between
undefined (not provided) and null (explicitly no proxy).
If you pass proxy: null in your request options, even accidentally,
the default proxy is bypassed. This can happen when you destructure an options
object that has a proxy property set to null.
Solution: Only include the proxy property in your
request options when you intentionally want to override the default. If you are
building request options dynamically, omit the proxy key entirely
(do not set it to null) when you want the default to apply. Use
delete options.proxy or conditional object spreading to exclude the
property.
Symptom: You call setDefaultFingerprint() but
requests that were initiated before the call still use the old fingerprint.
Cause: The fingerprint merge happens at the moment
request() or createSession() is called, not when the
BBRE engine processes the request. If you fire multiple async requests and then
change the default fingerprint, requests that were already initiated have already
captured the old default value.
Solution: Call setDefaultFingerprint() before
initiating the requests that should use the new fingerprint. If you need to change
fingerprints between requests in a concurrent batch, use per-request fingerprint
overrides instead of changing the default.
Symptom: After calling setDefaultMode(), all
subsequent requests fail with an INVALID_MODE error from the BBRE
API.
Cause: The setDefaultMode() method does not validate
the mode value locally. It simply stores whatever string you pass. The validation
happens on the server side when the request is submitted. If you pass a typo like
"pasive" or "Adaptive" (case-sensitive), the error only
appears when the next request is made.
Solution: Always use lowercase strings: "passive" or
"adaptive". Consider defining constants in your application to avoid
typos: const MODES = { PASSIVE: "passive", ADAPTIVE: "adaptive" };.
The same applies to setDefaultSensibility() with values
"low", "medium", and "high".
Symptom: You pass a per-request fingerprint to override specific
properties, but the default fingerprint properties still appear in the merged
result.
Cause: The spread operator merge
({ ...defaultFingerprint, ...requestFingerprint }) only performs a
shallow merge. If your default fingerprint has a nested object like
screen: { width: 1920, height: 1080 } and your per-request
fingerprint has screen: { width: 1366 }, the entire
screen object is replaced, not deep-merged. The resulting fingerprint
will have screen: { width: 1366 } without the height
property.
Solution: When overriding nested fingerprint properties, include
all the nested properties you want to keep in the per-request fingerprint object.
For example:
fingerprint: { screen: { width: 1366, height: 768 } }. The shallow
merge behavior is by design and matches standard JavaScript spread operator
semantics.
Symptom: In a concurrent workflow using
Promise.all(), some requests use unexpected default values because
another concurrent task changed the defaults mid-execution.
Cause: The setter methods modify the client instance state
immediately, and all concurrent requests share the same client instance. If Task A
calls setDefaultMode("adaptive") while Task B's requests are being
initiated, Task B's requests may unexpectedly use adaptive mode.
Solution: Avoid calling setter methods in concurrent code paths.
Instead, use per-request overrides to specify configuration for each request
independently. Alternatively, create separate BBREClient instances
for each concurrent task so they do not share state.