How camofox-browser Handles Rotating Sticky Sessions with Backconnect Proxies
camofox-browser rotates sticky sessions by embedding unique session identifiers directly into the proxy username, allowing a single backconnect endpoint to maintain isolated sessions per browser context without restarting the browser.
The camofox-browser open-source project implements a sophisticated proxy abstraction layer that supports residential backconnect proxies with session persistence. Unlike round-robin strategies that cycle through static ports, the backconnect approach generates per-context session IDs that are baked into proxy authentication credentials. This design enables granular traffic isolation while maintaining a single physical proxy endpoint.
Backconnect vs Round-Robin Proxy Strategies
camofox-browser supports two distinct proxy strategies defined in lib/proxy.js. The round-robin strategy rotates through a pool of static proxy ports, while the backconnect strategy uses a single residential proxy endpoint that maintains sticky sessions based on the username format.
When CONFIG.proxy.strategy is set to "backconnect", the library creates a pool with canRotateSessions: true. This flag signals that the pool can generate unique sessions per context rather than cycling through different physical endpoints.
Creating the Backconnect Proxy Pool
The proxy initialization occurs in server.js where the system reads the configuration and instantiates the pool using createProxyPool.
const proxyPool = createProxyPool(CONFIG.proxy);
// source: server.js lines 408-416
For backconnect configurations, this factory returns a pool object sized at exactly one endpoint, but with methods capable of accepting unique session identifiers. The pool recognizes it should rotate sessions rather than rotate servers.
How Session Rotation Works in lib/proxy.js
Pool Architecture with Single Endpoint
In lib/proxy.js, the backconnect pool implementation provides two key methods: getLaunchProxy(sessionId?) for browser initialization and getNext(sessionId?) for context switching. Both methods invoke buildBackconnectProxy but accept different session ID formats.
// source: lib/proxy.js lines 87-106
if (strategy === 'backconnect') {
// ...
return {
// ...
getLaunchProxy(sessionId = makeSessionId('browser')) {
return buildBackconnectProxy(config, provider, sessionId);
},
getNext(sessionId = makeSessionId('ctx')) {
return buildBackconnectProxy(config, provider, sessionId);
},
};
}
The makeSessionId function generates opaque identifiers prefixed with either browser- or ctx- depending on the calling context. These identifiers ensure that each logical session receives distinct treatment from the remote proxy service.
Building Sticky Session Proxies
The buildBackconnectProxy function composes the final proxy object by constructing a specialized username that includes the session identifier. This is the core mechanism that enables sticky sessions on a shared endpoint.
// source: lib/proxy.js lines 52-68
function buildBackconnectProxy(config, provider, sessionId) {
const username = provider.buildSessionUsername(config.username, {
// ...
sessionId,
});
return {
server: `http://${config.backconnectHost}:${config.backconnectPort}`,
username,
password: config.password,
sessionId,
};
}
The function returns an object containing the shared server endpoint, a username with embedded session data, the static password, and the opaque sessionId for logging purposes.
Provider-Specific Username DSL
camofox-browser uses provider plugins to format usernames according to each proxy service's requirements. The default decodoProvider constructs a domain-specific language (DSL) that embeds geography, session duration, and the critical sessionId into the username string.
// source: lib/proxy.js lines 72-93 (Decodo provider)
buildSessionUsername(baseUsername, options = {}) {
// ...
if (sessionId) parts.push(`session-${sessionId}`);
// ...
return parts.join('-');
}
This username format (e.g., user-test-country-us-session-ctx-42-test) signals the remote proxy service to isolate traffic for that specific session, effectively creating a sticky session without changing the physical endpoint.
Per-Context Session Isolation
When a Google-blocked tab requires rotation, the server requests a new proxy from the pool using a context-specific session identifier. The test suite in tests/unit/proxyRotation.test.js demonstrates this pattern through the assignContextProxy function.
// source: tests/unit/proxyRotation.test.js lines 24-30
function assignContextProxy(proxyPool, userId) {
if (proxyPool?.canRotateSessions) {
const key = normalizeUserId(userId);
return proxyPool.getNext(`ctx-${key}-test`);
} else if (proxyPool) {
return proxyPool.getNext();
}
return null;
}
Each distinct user receives a unique session ID (e.g., ctx-alice-test), ensuring that backconnect endpoints treat them as separate sticky sessions. This prevents one user's blocked session from affecting another's traffic.
Integrating with Playwright
The server injects the proxy configuration into Playwright's launch options after normalizing it through normalizePlaywrightProxy. For backconnect configurations, this includes the sticky-session username constructed earlier.
const launchProxy = proxyPool
? proxyPool.getLaunchProxy(proxyPool.canRotateSessions
? `browser-${crypto.randomUUID().replace(/-/g, '').slice(0,12)}`
: undefined)
: null;
options.proxy = normalizePlaywrightProxy(launchProxy);
// source: server.js lines 568-614
When canRotateSessions is true, the code generates a browser-scoped session ID (e.g., browser-abcd1234) that persists for the browser instance lifetime, while individual contexts within that browser can still rotate via getNext().
Summary
- camofox-browser uses a single backconnect endpoint with rotating session IDs embedded in usernames to create virtual sticky sessions.
- The
createProxyPoolfactory setscanRotateSessions: truefor backconnect strategies, enabling per-context session generation. - Session identifiers follow formats like
ctx-{userId}for context isolation orbrowser-{uuid}for launch-time sessions. - Provider plugins like Decodo construct DSL usernames that remote proxy services recognize as sticky session keys.
- Per-context rotation occurs via
getNext(sessionId)without requiring browser restarts, maintaining efficiency while ensuring isolation.
Frequently Asked Questions
What is the difference between backconnect and round-robin in camofox-browser?
Round-robin cycles through multiple static proxy ports, changing the physical endpoint for each request. Backconnect uses a single residential endpoint but rotates sticky sessions by changing the username format, embedding unique session IDs that tell the remote service to maintain IP persistence for that specific session identifier.
How does camofox-browser ensure session persistence across browser contexts?
The system generates unique session identifiers (e.g., ctx-user123-test) in assignContextProxy and passes them to buildBackconnectProxy. These IDs are embedded in the proxy username using the provider's buildSessionUsername method. The remote proxy service recognizes this username pattern and routes all traffic from that session through the same residential IP address.
Can I use custom proxy providers with camofox-browser's sticky session system?
Yes. The lib/proxy.js module exports registerProvider(name, provider), allowing you to implement custom buildSessionUsername logic. Your provider can format session IDs according to specific proxy service requirements (such as BrightData or Oxylabs) while maintaining the same canRotateSessions architecture.
Where does the session ID get injected when launching a browser instance?
In server.js lines 568-614, the code checks proxyPool.canRotateSessions and generates a browser-scoped session ID using crypto.randomUUID(). This ID is passed to getLaunchProxy(), which returns a proxy object containing the session-embedded username. The normalizePlaywrightProxy function then formats this for Playwright's proxy launch option.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →