Multi-Account Browser Isolation: Independent Identity Guide
How to run multiple isolated browser identities with independent fingerprints, proxies, storage, and geographic settings.
Introduction
Running multiple accounts or identities within a single browser is one of the most common privacy requirements. Whether you are managing social media accounts, testing localized content across regions, or running parallel research sessions, each identity needs to be truly independent. Shared cookies, fingerprint signals, or network paths between identities compromise isolation.
BotBrowser provides true per-context isolation where each browser context has its own fingerprint signals, proxy, geographic settings, cookies, and storage. This article covers the architecture of BotBrowser's isolation model, configuration approaches for both Playwright and Puppeteer, and best practices for maintaining clean identity separation.
Privacy Impact
When multiple identities share any aspect of their browser environment, correlation becomes possible. The risks include:
- Shared IP addresses: If two accounts use the same proxy, their traffic can be linked by IP
- Fingerprint overlap: If two contexts share Canvas, WebGL, or audio fingerprint values, they can be identified as coming from the same browser
- Cookie and storage leaks: Shared cookies or localStorage between contexts directly link identities
- Geographic inconsistency: An account claiming to be in Germany but sharing a timezone with a US-based account reveals the shared environment
- Timing correlation: Accounts that are always active at the same times from the same browser instance may be linked through activity patterns
True isolation requires independence across all these dimensions. BotBrowser's per-context isolation addresses each one.
Technical Background
Browser Contexts and Isolation Boundaries
In Chromium-based browsers, a browser context is an isolated browsing environment. Each context has its own:
- Cookie jar
- localStorage and sessionStorage
- IndexedDB
- Cache storage
- Service workers
- HTTP authentication credentials
Standard Chromium provides this storage isolation out of the box. However, many fingerprint signals are shared across contexts because they come from the hardware and OS: Canvas rendering, WebGL vendor/renderer strings, audio processing characteristics, screen dimensions, and navigator properties are identical across all contexts in a standard browser.
BotBrowser's Extended Isolation
BotBrowser extends the isolation boundary beyond storage to include fingerprint signals. When BotBrowser loads a profile, it configures fingerprint signals at the engine level. Combined with per-context proxy support, each context can present:
- Unique fingerprint signals: Different Canvas hashes, WebGL renderer strings, audio fingerprints, and navigator properties
- Independent network identity: Different proxy IP, with automatic geographic alignment
- Isolated storage: Standard Chromium context isolation for cookies, localStorage, and IndexedDB
- Matching geographic metadata: Timezone, locale, and language aligned with the context's proxy
Single Instance vs. Multiple Instances
There are two approaches to multi-identity operation:
Single browser instance with multiple contexts (Playwright): One browser process runs multiple contexts. Each context can have its own proxy. BotBrowser provides per-context fingerprint isolation within this single instance.
Multiple browser instances (Playwright or Puppeteer): Each instance is a separate browser process with its own profile, proxy, and user data directory. This provides the strongest isolation because the instances share nothing at the process level.
Both approaches are valid. Single-instance multi-context is more resource-efficient. Multiple instances provide stronger isolation at the cost of higher resource usage.
Common Approaches and Their Limitations
Browser Profile Directories
Standard browsers use profile directories to separate identities. Each profile has its own cookies and bookmarks but shares the same browser fingerprint. Canvas, WebGL, audio, and navigator signals are identical across profiles because they come from the same hardware.
Container Tabs (Firefox)
Firefox's Multi-Account Containers isolate cookies and storage per container. However, fingerprint signals are shared. All containers report the same Canvas hash, WebGL renderer, and audio fingerprint.
Separate Browser Installations
Running completely separate browser installations (different binary paths, different user data directories) provides strong isolation but is operationally expensive. Each installation needs its own update cycle, and there is no centralized management.
Virtual Machines
VMs provide the strongest isolation: separate OS, separate hardware profile, separate network stack. But VMs are resource-intensive. Running 10 identities means running 10 VMs, each consuming gigabytes of RAM and significant CPU.
BotBrowser's Approach
Per-Context Fingerprint Isolation
BotBrowser provides per-context fingerprint isolation through its profile system. Each browser instance loads a profile that defines the fingerprint. For multi-instance setups, each instance can load a different profile:
# Instance 1: US identity with Profile A
chrome --bot-profile="/profiles/profile-a.enc" \
--proxy-server="socks5://us-proxy:1080" \
--user-data-dir="/tmp/session-us"
# Instance 2: DE identity with Profile B
chrome --bot-profile="/profiles/profile-b.enc" \
--proxy-server="socks5://de-proxy:1080" \
--user-data-dir="/tmp/session-de"
Each instance reports different Canvas hashes, WebGL renderer strings, audio fingerprints, navigator properties, screen dimensions, and font availability.
Playwright Multi-Context Setup
For per-context isolation within a single browser instance:
const { chromium } = require('playwright-core');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-local-dns',
'--bot-webrtc-ice=google',
],
headless: true,
});
// Context 1: US identity
const usContext = await browser.newContext({
proxy: { server: 'socks5://us-proxy:1080', username: 'user', password: 'pass' },
locale: 'en-US',
timezoneId: 'America/New_York',
});
// Context 2: UK identity
const ukContext = await browser.newContext({
proxy: { server: 'socks5://uk-proxy:1080', username: 'user', password: 'pass' },
locale: 'en-GB',
timezoneId: 'Europe/London',
});
// Context 3: Japan identity
const jpContext = await browser.newContext({
proxy: { server: 'socks5://jp-proxy:1080', username: 'user', password: 'pass' },
locale: 'ja-JP',
timezoneId: 'Asia/Tokyo',
});
const page1 = await usContext.newPage();
const page2 = await ukContext.newPage();
const page3 = await jpContext.newPage();
Puppeteer Multi-Instance Setup
Puppeteer works best with separate browser instances for full fingerprint isolation:
const puppeteer = require('puppeteer-core');
async function createIdentity(profile, proxy, timezone, locale, languages) {
const userDataDir = '/tmp/session-' + Math.random().toString(36).slice(2);
return puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
`--bot-profile=${profile}`,
`--proxy-server=${proxy}`,
`--bot-config-timezone=${timezone}`,
`--bot-config-locale=${locale}`,
`--bot-config-languages=${languages}`,
`--user-data-dir=${userDataDir}`,
'--bot-local-dns',
'--bot-webrtc-ice=google',
],
headless: true,
defaultViewport: null,
});
}
const usBrowser = await createIdentity(
'/profiles/us.enc', 'socks5://us-proxy:1080',
'America/New_York', 'en-US', 'en-US,en'
);
const deBrowser = await createIdentity(
'/profiles/de.enc', 'socks5://de-proxy:1080',
'Europe/Berlin', 'de-DE', 'de-DE,de,en'
);
Deterministic Noise Seeds for Consistency
Use different --bot-noise-seed values per identity to produce consistent but unique fingerprint noise:
# Identity A
chrome --bot-profile="/profiles/profile.enc" \
--bot-noise-seed=12345 \
--proxy-server="socks5://proxy-a:1080"
# Identity B (same profile, different noise seed = different fingerprint noise)
chrome --bot-profile="/profiles/profile.enc" \
--bot-noise-seed=67890 \
--proxy-server="socks5://proxy-b:1080"
Each seed produces a unique, stable noise pattern. The same seed always produces the same noise, making identities reproducible across sessions.
Configuration and Usage
Complete Multi-Identity Configuration (CLI)
# Identity 1: US Chrome user
chrome --bot-profile="/profiles/us-chrome.enc" \
--proxy-server="socks5://user:pass@us-proxy:1080" \
--bot-config-timezone="America/New_York" \
--bot-config-locale="en-US" \
--bot-config-languages="en-US,en" \
--bot-noise-seed=11111 \
--bot-local-dns \
--bot-webrtc-ice=google \
--bot-port-protection \
--user-data-dir="/data/session-us"
# Identity 2: German Edge user
chrome --bot-profile="/profiles/de-edge.enc" \
--bot-config-browser-brand=edge \
--proxy-server="socks5://user:pass@de-proxy:1080" \
--bot-config-timezone="Europe/Berlin" \
--bot-config-locale="de-DE" \
--bot-config-languages="de-DE,de,en" \
--bot-noise-seed=22222 \
--bot-local-dns \
--bot-webrtc-ice=google \
--bot-port-protection \
--user-data-dir="/data/session-de"
Scaled Multi-Identity with Playwright
const { chromium } = require('playwright-core');
const identities = [
{
name: 'us-user',
proxy: 'socks5://us-proxy:1080',
locale: 'en-US',
timezone: 'America/New_York',
},
{
name: 'uk-user',
proxy: 'socks5://uk-proxy:1080',
locale: 'en-GB',
timezone: 'Europe/London',
},
{
name: 'jp-user',
proxy: 'socks5://jp-proxy:1080',
locale: 'ja-JP',
timezone: 'Asia/Tokyo',
},
];
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-local-dns',
'--bot-webrtc-ice=google',
],
headless: true,
});
for (const identity of identities) {
const context = await browser.newContext({
proxy: { server: identity.proxy, username: 'user', password: 'pass' },
locale: identity.locale,
timezoneId: identity.timezone,
});
const page = await context.newPage();
await page.goto('https://example.com');
console.log(`${identity.name}: loaded`);
// Perform identity-specific tasks...
}
Verification
After setting up multiple identities, verify isolation across all dimensions:
async function verifyIdentity(context, label) {
const page = await context.newPage();
// Check IP
await page.goto('https://httpbin.org/ip');
const ip = JSON.parse(await page.textContent('body'));
console.log(`${label} IP:`, ip.origin);
// Check timezone
const tz = await page.evaluate(() =>
Intl.DateTimeFormat().resolvedOptions().timeZone
);
console.log(`${label} Timezone:`, tz);
// Check Canvas hash
const canvasHash = await page.evaluate(() => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.fillText('test', 10, 10);
return canvas.toDataURL().slice(-20);
});
console.log(`${label} Canvas:`, canvasHash);
// Check WebGL renderer
const renderer = await page.evaluate(() => {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_debug_renderer_info');
return ext ? gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) : 'N/A';
});
console.log(`${label} WebGL:`, renderer);
await page.close();
}
await verifyIdentity(usContext, 'US');
await verifyIdentity(ukContext, 'UK');
await verifyIdentity(jpContext, 'JP');
Confirm that each identity shows:
- A different IP address
- A different timezone matching its proxy region
- Different Canvas hashes (when using different profiles or noise seeds)
- Different WebGL renderer strings (when using different profiles)
- No shared cookies or storage between contexts
Best Practices
-
Use separate profiles for separate identities. While noise seeds create variation within a profile, separate profiles provide the strongest fingerprint isolation.
-
Always match proxy geography with locale. A Japanese locale with a US proxy creates an obvious inconsistency.
-
Use separate user data directories. Each instance needs its own
--user-data-dirto prevent profile data conflicts. -
Enable DNS and WebRTC protection globally. Set
--bot-local-dnsand--bot-webrtc-iceon every instance to close network leak paths. -
Close contexts when no longer needed. Open contexts consume memory. Close them to free resources.
-
Do not share cookies between identities. Each identity should have its own cookie state. Never transfer cookies from one context to another.
Frequently Asked Questions
How many identities can I run simultaneously? There is no hard limit. Per-context isolation within a single browser instance is memory-efficient. In practice, the limit depends on available RAM and the complexity of pages loaded in each context.
Can I use the same profile for multiple identities?
Yes, when combined with different --bot-noise-seed values. The noise seed changes Canvas, WebGL, and audio fingerprint noise, creating distinct identities from the same base profile.
Do contexts share browser cache? No. Each context has its own cache, cookies, localStorage, and IndexedDB. There is no data sharing between contexts.
Should I use Playwright or Puppeteer for multi-identity setups? Playwright provides native per-context proxy support, making it the better choice for multi-context setups within a single browser instance. Puppeteer works best with separate browser instances per identity.
Can I persist identity state across sessions?
Yes. Use --user-data-dir with a persistent directory to retain cookies, cache, and storage between sessions. Each identity should use a separate directory.
How do I handle different browser brands across identities?
Use --bot-config-browser-brand to set different brands per instance. See Browser Brand Switching for details.
Does per-context isolation protect against GPU fingerprinting? BotBrowser controls WebGL and WebGPU signals through profiles. Each profile reports different GPU-related values. Per-context isolation ensures these values are consistent within each context.
Summary
Multi-account browser isolation requires independence across fingerprint signals, network identity, geographic metadata, and storage. BotBrowser provides all of these through its profile system, per-context proxy support, and engine-level fingerprint control. Whether you use Playwright's multi-context approach or Puppeteer's multi-instance approach, each identity presents a complete, independent browser environment.
For proxy setup, see Proxy Configuration and Dynamic Proxy Switching. For geographic configuration, see Timezone, Locale, and Language Configuration. For brand identity, see Browser Brand Switching.