How to Run Multiple Browser Identities from a Single Docker Container Using CloakBrowser

CloakBrowser's cloakserve binary runs a single Chromium process that multiplexes independent browser instances through CDP connections, each configured via unique fingerprint seeds passed as URL query parameters.

CloakBrowser is a stealth browser automation platform that isolates browser identities through fingerprint randomization. By leveraging the cloakserve multiplexer inside a Docker container, you can spawn dozens of isolated browser contexts from one lightweight process rather than managing separate containers for each identity.

Understanding the CloakBrowser Architecture

The cloakserve CDP Multiplexer

At the core of this deployment is cloakserve, a lightweight binary located in bin/cloakserve within the CloakBrowser repository. Unlike traditional browser automation setups that launch a new Chromium instance per container, cloakserve initializes a single stealth-patched Chromium process that acts as a CDP (Chrome DevTools Protocol) multiplexer.

According to the CloakBrowser source code, when cloakserve receives an incoming WebSocket connection, it parses query parameters to determine the browser identity. Each unique connection spawns a new browser process (or reuses an existing one if the same fingerprint seed is supplied), allowing multiple simultaneous identities to operate from the same container without cross-contamination.

Configuring Browser Identities via Query Parameters

Fingerprint Seeds and Isolation

The fingerprint query parameter acts as the primary seed for generating browser identity characteristics. When you connect to http://localhost:9222?fingerprint=12345, CloakBrowser:

  • Generates unique canvas noise patterns
  • Randomizes WebGL parameters and hardware concurrency values
  • Sets timezone, locale, and platform attributes

As implemented in cloakbrowser/browser.py, these parameters translate into --fingerprint-* arguments passed to the Chromium binary. Two connections using different seeds operate as completely independent identities, while identical seeds share processes to conserve resources.

Additional Configuration Flags

You can extend identity customization through additional query parameters:

  • timezone – Override the browser's timezone (e.g., timezone=Asia/Tokyo)
  • locale – Set Accept-Language headers and navigator.language
  • platform – Manipulate navigator.platform and user-agent OS indicators
  • proxy – Route traffic through specific proxies (HTTP/SOCKS5)
  • user-data-dir – Persist cookies and localStorage across sessions
  • geoip – Enable automatic geolocation spoofing based on IP

Docker Deployment Strategies

Docker Compose Setup

Create a docker-compose.yml file that exposes the CDP port and starts the multiplexer:

services:
  cloakbrowser:
    image: cloakhq/cloakbrowser
    command: cloakserve
    ports:
      - "127.0.0.1:9222:9222"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9222/json/version"]
      interval: 30s
      timeout: 5s
      retries: 3

This configuration makes the CDP endpoint available at http://localhost:9222, ready to accept multiple simultaneous connections with varying identity parameters.

Per-Connection Identity Isolation

The multiplexer distinguishes identities solely through URL query parameters. This architecture eliminates the need to spawn separate Docker containers for each browser profile, significantly reducing overhead while maintaining strict isolation between contexts.

Practical Implementation Examples

Python Playwright Integration

Connect multiple independent identities from a single Python script using Playwright:

from playwright.sync_api import sync_playwright

def launch_identity(seed, extra_params=""):
    url = f"http://localhost:9222?fingerprint={seed}{extra_params}"
    playwright = sync_playwright().start()
    browser = playwright.chromium.connect_over_cdp(url)
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://example.com")
    print(f"Seed {seed} → title:", page.title())
    context.close()
    browser.close()
    playwright.stop()

# Launch three completely isolated browser identities

launch_identity(11111)
launch_identity(22222, "&timezone=Europe/London&proxy=http://proxy:8080")
launch_identity(33333, "&user-data-dir=/profile&geoip=true")

Node.js JavaScript Example

The same pattern works for Node.js automation using Playwright or Puppeteer:

import { chromium } from 'playwright';

async function launchIdentity(seed, extraParams = '') {
  const url = `http://localhost:9222?fingerprint=${seed}${extraParams}`;
  const browser = await chromium.connectOverCDP(url);
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com');
  console.log(`Seed ${seed} → title:`, await page.title());
  await context.close();
  await browser.close();
}

// Execute multiple identities concurrently
await launchIdentity(11111);
await launchIdentity(22222, '&timezone=America/New_York&proxy=socks5://user:pass@proxy:1080');
await launchIdentity(33333, '&user-data-dir=/profile&locale=en-US');

One-Off Execution with docker run

For ephemeral automation tasks without Compose, mount a profile volume and execute inline:

docker run --rm -v $(pwd)/my-profile:/profile \
  cloakhq/cloakbrowser python - <<'PY'
from cloakbrowser import launch

browser = launch(args=["--fingerprint=55555",
                       "--user-data-dir=/profile"])
page = browser.new_page()
page.goto('https://example.com')
print(page.title())
browser.close()
PY

This pattern mounts $(pwd)/my-profile to /profile inside the container, enabling cookie and session persistence across container restarts.

Persisting Profiles Across Sessions

When you need persistent storage rather than fresh incognito contexts, mount a host volume to /profile (or your preferred path) and pass the user-data-dir parameter. The examples/persistent_context.py file in the repository demonstrates mounting volumes to preserve:

  • Cookies and localStorage data
  • Browser cache and IndexedDB
  • Authentication sessions

This configuration proves essential for workflows requiring "warm" profiles with existing login states, while still allowing multiple distinct profiles to operate simultaneously through different fingerprint seeds.

Resource Efficiency and Performance

Running multiple identities from a single container offers substantial resource savings compared to per-container deployments. According to the CloakBrowser documentation:

  • One Chromium instance consumes approximately 190 MiB RAM when idle
  • Each additional tab adds roughly 30 MiB of memory overhead

Rather than multiplying these costs across separate Docker containers, cloakserve amortizes the base memory requirement across all active identities, making it feasible to run 50+ concurrent browser contexts on modest hardware.

Summary

  • Single-process architecture: The cloakserve binary in bin/cloakserve runs one Chromium instance that multiplexes multiple browser identities via CDP connections
  • Seed-based isolation: The fingerprint query parameter generates unique browser characteristics (canvas noise, WebGL, hardware specs) per connection
  • Query parameter configuration: Pass timezone, proxy, locale, and user-data-dir directly in the connection URL to customize each identity
  • Volume persistence: Mount host directories to /profile and specify user-data-dir to maintain state across container restarts
  • Resource efficiency: Share ~190 MiB base memory across unlimited identities rather than spawning separate containers

Frequently Asked Questions

What makes cloakserve more efficient than running separate Docker containers per browser?

cloakserve eliminates the overhead of multiple Chromium binaries and container layers by running a single stealth-patched process that handles all CDP connections. This architecture reduces base RAM consumption from multiples of ~190 MiB to a single instance, while the cloakbrowser wrapper in cloakbrowser/browser.py automatically manages process isolation through fingerprint seeds.

How does CloakBrowser ensure identities remain isolated when sharing the same Chromium process?

Each CDP connection receives a unique browser context determined by the fingerprint seed and other query parameters. The source code in bin/cloakserve parses these parameters to generate distinct browser fingerprints (canvas noise, WebGL signatures, hardware concurrency) and optionally spawns separate processes per seed, ensuring cookies, localStorage, and cache remain isolated between identities.

Can I persist browser profiles when running multiple identities from one container?

Yes. Mount a host volume to any container path (commonly /profile) and pass user-data-dir=/profile as a query parameter or launch argument. As shown in examples/persistent_context.py, this preserves cookies, authentication states, and localStorage across container restarts while allowing distinct profiles for each fingerprint seed.

Which automation frameworks support CloakBrowser's single-container multiplexer?

Any framework supporting CDP (Chrome DevTools Protocol) connections works with cloakserve, including Playwright (Python and Node.js), Puppeteer, and Selenium with CDP extensions. Connect via http://localhost:9222?fingerprint=YOUR_SEED rather than launching local browser binaries, and the framework will treat each connection as a standard Chromium instance.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →