Package the DICloak antidetect browser into a Docker image. Launch a fully fingerprint-spoofed browser environment with a single command — no host-level software installation required. Integrates seamlessly with Playwright and Puppeteer via the standard CDP protocol.
Image: `dicloakinc/dicloak-runtime-image`
Protocol: Chrome DevTools Protocol (CDP)
Concurrency Limit: 100 browser instances
Authentication: Email + Password
Browser Mode: Non-headless (full browser UI)
docker run -d \
--name dicloak-runtime \
-e USER_EMAIL=your@email.com \
-e USER_PASSWD=your_password \
-e PORT=52140 \
-e DOCKER=1 \
-p 52140:52140 \
-p 127.0.0.1:45000-45099:45000-45099 \
--shm-size=1g \
dicloakinc/dicloak-runtime-image:latest
Overview
DICloak Runtime Image is a preconfigured Docker image with the full DICloak antidetect browser runtime built in. It solves a core problem: vanilla headless Chromium produces highly uniform browser fingerprints that are easily flagged as automation by websites.
On startup, the image runs a Local API service (default port 52140) inside the container. Your code interacts with this API to manage browser environments, each with its own unique fingerprint profile. When an environment is opened, a CDP debug port is dynamically assigned for Playwright or Puppeteer to connect to.
The browser runs in non-headless mode with a full UI, behaving identically to a manually operated browser for stronger anti-detection capabilities.
Use Cases
- AI Agents that need persistent, logged-in browser sessions
- Automation scripts that need to bypass bot detection
- Multi-account workflows requiring isolated browser environments
- CI/CD pipelines that need stable, reproducible browser testing environments
Workflow
1. Pull and start the container — Pass account credentials and port configuration via environment variables. The Local API service starts automatically inside the container.
2. Open a browser environment via the Local API — Send a request to `http://127.0.0.1:52140/openapi/v1/env/{env_id}/open` and receive a CDP debug port (`debug_port`) for that environment.
3. Retrieve the WebSocket debug URL — Request `http://127.0.0.1:{debug_port}/json/version` to get the `webSocketDebuggerUrl`.
4. Connect and run your automation — Use `connectOverCDP(wsUrl)` to connect to the browser. Fingerprinting is handled automatically by DICloak; everything else works exactly like standard Playwright/Puppeteer.
5. Close or reuse the environment — Close the browser instance via the API to release port resources. If a volume is mounted, session data is persisted and automatically restored on next startup.
Prerequisites
System Requirements
| Resource | Minimum | Notes |
| CPU | 2 cores | Each concurrent browser instance uses approximately 0.2–0.5 additional cores |
| Memory | 4 GB | Each active browser instance uses approximately 200–400 MB |
| Disk | 10 GB | The image itself is ~3–5 GB; profile data grows on demand |
| Shared Memory | 1 GB | Chrome relies heavily on /dev/shm; insufficient allocation causes rendering crashes. Set via --shm-size=1g |
| Docker | 20.10+ | Latest stable version recommended |
DICloak Account & Plan
Before using this image, complete the following steps:
- Register an account at dicloak.com
2. Subscribe to the Plus plan or higher — Docker runtime functionality is only available to Plus-tier users and above
3. Obtain your API Key from the Settings → Open API page in the DICloak dashboard
Important Note on Account Types
> It is strongly recommended NOT to use the super admin account registered during sign-up to run Docker.
> The DICloak super admin account uses single sign-on — only one active session is allowed at a time. If you start a Docker container with the super admin account, all other sessions on other devices or browsers will be logged out.
> Best practice: Create a dedicated team member account in the DICloak dashboard for Docker use. Use that member account’s email and password as the container’s credentials. Member accounts are not subject to the single sign-on restriction and will not interfere with the super admin’s sessions.
Quick Start
Step 1: Pull the Image
docker pull dicloakinc/dicloak-runtime-image:latest
Step 2: Start the Container
Replace `your@email.com` and `your_password` with the email and password of your DICloak team member account:
docker run -d \
--name dicloak-runtime \
-e USER_EMAIL=your@email.com \
-e USER_PASSWD=your_password \
-e PORT=52140 \
-e DOCKER=1 \
-p 52140:52140 \
-p 127.0.0.1:45000-45099:45000-45099 \
--shm-size=1g \
dicloakinc/dicloak-runtime-image:latest
Step 3: Verify the Service Is Ready
curl "http://127.0.0.1:52140/openapi/v1/env/list?page_no=1&page_size=1" \
-H "X-API-KEY: YOUR_API_KEY"
A response containing {"code": 0, ...} confirms the Local API service is running.
> Note: If the container exits immediately after startup, run `docker logs dicloak-runtime` to inspect the logs. The most common causes are incorrect email/password or an account without a Plus subscription.
Environment Variables
Pass via -e KEY=VALUE (docker run) or environment: (Compose).
| Variable | Required | Default | Description |
USER_EMAIL | Yes | — | Email of the DICloak team member account |
USER_PASSWD | Yes | — | Password of the DICloak team member account |
PORT | Yes | 52140 | Local API listen port. If changed, update the -p port mapping accordingly |
DOCKER | Yes | — | Must be set to 1. Signals the application that it is running inside Docker. Do not omit |
Port Mapping
The container uses two sets of ports. Both must be mapped to the host via -p at startup; otherwise, the host cannot reach the services inside the container.
Port Overview
| Port | Direction | Purpose |
| `52140` | Host → Container | Local API port — Manages the lifecycle of browser environments (list, open, close, etc.) |
| `45000–45099` | Host → Container | Browser CDP ports — Each active environment is assigned one port for browser control |
### `-p` Parameter Format
-p [host_bind_address:]host_port:container_port
– **`host_bind_address`** (optional): Defaults to `0.0.0.0` (all interfaces) if omitted. Set to `127.0.0.1` to restrict access to localhost only.
– **`host_port`**: The port used by external clients (host machine or other services) to connect.
– **`container_port`**: The port the service listens on inside the container. Typically matches the container’s internal configuration and does not need to be changed.
Recommended Configuration
# Local API: bind to localhost (when automation scripts run on the same machine)
-p 127.0.0.1:52140:52140
# Browser CDP ports: bind to localhost
-p 127.0.0.1:45000-45099:45000-45099
Cross-Machine Access
If your automation scripts run on a different machine, change the bind address to `0.0.0.0` to expose the ports on external interfaces:
-p 0.0.0.0:52140:52140
-p 0.0.0.0:45000-45099:45000-45099
# Shorthand (omitting the address defaults to 0.0.0.0)
-p 52140:52140
-p 45000-45099:45000-45099
> Security Warning: Exposing ports to the public network is a security risk — anyone who can reach the IP can control the browsers inside the container. Only do this in trusted internal networks, or use a VPN / SSH tunnel for port forwarding.
Port Conflict Resolution
If port 52140 is already in use, change the PORT environment variable and the corresponding host port:
docker run -d \
-e PORT=52200 \
-p 127.0.0.1:52200:52200 \
... # remaining parameters unchanged
Find the process occupying the port:
lsof -i :52140 # macOS / Linux
netstat -ano | findstr :52140 # Windows
Data Persistence
By default, all data inside the container (browser profiles, cookies, LocalStorage, fingerprint configurations, etc.) is lost when the container is removed. Mount a volume to persist this data on the host, enabling automatic session restoration after container restarts.
| Container Path | Contents |
/root/.config/DICloakCache | Browser profiles, cookies, session data, fingerprint parameters |
Mount Example
docker run -d \
--name dicloak-runtime \
-e USER_EMAIL=your@email.com \
-e USER_PASSWD=your_password \
-e PORT=52140 \
-e DOCKER=1 \
-p 127.0.0.1:52140:52140 \
-p 127.0.0.1:45000-45099:45000-45099 \
-v ./data:/root/.config/DICloakCache \
--shm-size=1g \
dicloakinc/dicloak-runtime-image:latest
Data is stored in the ./data/ directory on the host. After removing the container or updating the image, remount the same directory to automatically restore all profiles and session state.
> Tip: In production, use an absolute path (e.g., `-v /data/dicloak:/root/.config/DICloakCache`) to avoid data loss caused by working directory changes.
Local API Usage
Browser control in this image relies on the DICloak Local API. After the container starts, the API service listens on the port specified by `PORT`.
Full API reference: DICloak API Developer Guide
Authentication
All requests must include the API Key in the header:
X-API-KEY: YOUR_API_KEY
Obtain the API Key from Settings → Open API in the DICloak dashboard.
Base URL
http://127.0.0.1:52140/openapi
Response Format
// Success
{ "code": 0, "msg": "success", "data": { ... } }
// Failure
{ "code": 500, "msg": "error description" }
Core Endpoints
List Environments
GET /v1/env/list?page_no=1&page_size=20
X-API-KEY: YOUR_API_KEY
Returns all created browser environments and their IDs. Use env_id in subsequent API calls.
Open a Browser Environment
PATCH /v1/env/{env_id}/open
X-API-KEY: YOUR_API_KEY
Example response:
{
"code": 0,
"msg": "success",
"data": {
"debug_port": 45001
}
}
The returned debug_port is the CDP debug port for this browser instance, in the 45000–45099 range.
Close a Browser Environment
PATCH /v1/env/{env_id}/close
X-API-KEY: YOUR_API_KEY
Get the CDP WebSocket URL
After opening an environment, request the following endpoint using the debug_port to obtain the WebSocket URL required by Playwright/Puppeteer:
GET http://127.0.0.1:{debug_port}/json/version
Example response:
{
"webSocketDebuggerUrl": "ws://127.0.0.1:45001/devtools/browser/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Connecting to the Browser
Once you have the webSocketDebuggerUrl, connect directly via Playwright or Puppeteer.
Playwright (JavaScript)
const { chromium } = require('playwright');
// 1. Open the environment and get debug_port
const openRes = await fetch(
'http://127.0.0.1:52140/openapi/v1/env/YOUR_ENV_ID/open',
{
method: 'PATCH',
headers: { 'X-API-KEY': 'YOUR_API_KEY' },
},
);
const {
data: { debug_port },
} = await openRes.json();
// 2. Get the WebSocket debug URL
const versionRes = await fetch(`http://127.0.0.1:${debug_port}/json/version`);
const { webSocketDebuggerUrl } = await versionRes.json();
// 3. Connect to the browser via CDP
const browser = await chromium.connectOverCDP(webSocketDebuggerUrl);
const page = await browser.newPage();
// 4. Use as normal — fingerprinting is handled automatically by DICloak
await page.goto('https://example.com');
// 5. Close the environment when done
await fetch('http://127.0.0.1:52140/openapi/v1/env/YOUR_ENV_ID/close', {
method: 'PATCH',
headers: { 'X-API-KEY': 'YOUR_API_KEY' },
});
Playwright (Python)
import requests
from playwright.sync_api import sync_playwright
API_BASE = "http://127.0.0.1:52140/openapi"
API_KEY = "YOUR_API_KEY"
ENV_ID = "YOUR_ENV_ID"
HEADERS = {"X-API-KEY": API_KEY}
# 1. Open the environment and get debug_port
res = requests.patch(f"{API_BASE}/v1/env/{ENV_ID}/open", headers=HEADERS)
debug_port = res.json()["data"]["debug_port"]
# 2. Get the WebSocket debug URL
version = requests.get(f"http://127.0.0.1:{debug_port}/json/version").json()
ws_url = version["webSocketDebuggerUrl"]
# 3. Connect to the browser via CDP
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(ws_url)
page = browser.new_page()
# 4. Use as normal
page.goto("https://example.com")
# 5. Close the environment when done
requests.patch(f"{API_BASE}/v1/env/{ENV_ID}/close", headers=HEADERS)
Puppeteer
const puppeteer = require('puppeteer');
// 1. Open the environment and get debug_port
const openRes = await fetch(
'http://127.0.0.1:52140/openapi/v1/env/YOUR_ENV_ID/open',
{
method: 'PATCH',
headers: { 'X-API-KEY': 'YOUR_API_KEY' },
},
);
const {
data: { debug_port },
} = await openRes.json();
// 2. Get the WebSocket debug URL
const versionRes = await fetch(`http://127.0.0.1:${debug_port}/json/version`);
const { webSocketDebuggerUrl } = await versionRes.json();
// 3. Connect to the browser via CDP
const browser = await puppeteer.connect({
browserWSEndpoint: webSocketDebuggerUrl,
});
const page = await browser.newPage();
// 4. Use as normal
await page.goto('https://example.com');
// 5. Close the environment when done
await fetch('http://127.0.0.1:52140/openapi/v1/env/YOUR_ENV_ID/close', {
method: 'PATCH',
headers: { 'X-API-KEY': 'YOUR_API_KEY' },
});
Production Deployment (Docker Compose)
For production, Docker Compose is recommended for unified configuration management, automatic restarts, data persistence, and easier service scaling.
docker-compose.yml
services:
dicloak-runtime:
image: dicloakinc/dicloak-runtime-image:latest
container_name: dicloak-runtime
restart: unless-stopped # Auto-restart on crash; no restart on manual stop
environment:
USER_EMAIL: ${DICLOAK_EMAIL} # Read from .env file to avoid plaintext secrets in yml
USER_PASSWD: ${DICLOAK_PASSWD}
PORT: 52140
DOCKER: 1
ports:
- '127.0.0.1:52140:52140'
- '127.0.0.1:45000-45099:45000-45099'
volumes:
- ./data:/root/.config/DICloakCache
shm_size: '1gb'
.env File
Store credentials in .env to keep sensitive information out of version control:
# .env
DICLOAK_EMAIL=member@yourcompany.com
DICLOAK_PASSWD=your_member_password
Make sure .env is listed in .gitignore.
Common Compose Commands
# Start in detached mode
docker compose up -d
# Follow live logs
docker compose logs -f
# Stop and remove containers (data in ./data is preserved)
docker compose down
# Update image and redeploy
docker compose pull && docker compose up -d
Container Management
Basic Operations
# Follow live logs
docker logs -f dicloak-runtime
# Stop the container
docker stop dicloak-runtime
# Start a stopped container
docker start dicloak-runtime
# Remove the container (data is preserved in ./data if a volume is mounted)
docker rm -f dicloak-runtime
Updating the Image
# 1. Pull the latest image
docker pull dicloakinc/dicloak-runtime-image:latest
# 2. Remove the old container
docker rm -f dicloak-runtime
# 3. Re-run with the same parameters (data persisted via volume is unaffected)
docker run -d \
--name dicloak-runtime \
-e USER_EMAIL=your@email.com \
-e USER_PASSWD=your_password \
-e PORT=52140 \
-e DOCKER=1 \
-p 127.0.0.1:52140:52140 \
-p 127.0.0.1:45000-45099:45000-45099 \
-v ./data:/root/.config/DICloakCache \
--shm-size=1g \
dicloakinc/dicloak-runtime-image:latest
Troubleshooting
Container Exits Immediately After Startup
Symptom: Container is not visible in `docker ps`, or STATUS shows Exited.
Diagnose:
docker logs dicloak-runtime
Common causes:
- Incorrect email or password — authentication failed
- Account does not have a Plus subscription — no access to Docker runtime
- Super admin account was used — kicked out by single sign-on (switch to a team member account)
- Missing
-e DOCKER=1parameter - Network issue preventing connection to DICloak servers
API Requests Return 401 / 403
Symptom: Local API requests return authentication errors.
Checklist:
- Verify the header name is
X-API-KEY(case-sensitive)
– Verify the API Key is from Settings → Open API in the DICloak dashboard, not the account password
- Verify the account has a Plus subscription
Port Already in Use
Symptom: Startup fails with `port is already allocated` or `bind: address already in use`.
Diagnose:
lsof -i :52140 # macOS / Linux
netstat -ano | findstr :52140 # Windows
Solution: Stop the process occupying the port, or change the `PORT` environment variable and the corresponding `-p` mapping.
Browser Instance Crashes or Freezes
Symptom: Browser becomes unresponsive after launch, pages render incorrectly, or container logs show `shared memory` errors.
Solution: Chrome relies heavily on `/dev/shm` (shared memory) for rendering. Ensure your startup command includes `–shm-size=1g`. For higher concurrency, increase the value accordingly (e.g., `–shm-size=2g`).
# Check current shared memory usage
docker exec dicloak-runtime df -h /dev/shm
Unable to Connect to the Browser via CDP
Symptom: Playwright or Puppeteer throws a connection timeout or connection refused error.
Checklist:
- Confirm you have called
/v1/env/{env_id}/openand successfully received adebug_port - Confirm the
debug_portfalls within the-pmapped range (45000–45099) - Confirm you requested
/json/versionto get the fullwebSocketDebuggerUrlrather than constructing the address manually - If connecting from another machine, confirm the bind address is
0.0.0.0, not127.0.0.1 - Check container logs for errors
Performance Issues / Slow Operation
Performance degrades when the number of concurrent instances exceeds hardware capacity. Recommendations:
- Add approximately 2 GB of memory for every 10 additional concurrent instances
- Maintain a CPU-to-instance ratio of at least 1:5
- Mount the volume on an SSD to improve profile read/write speed
Related Links
| Resource | URL |
| Docker Hub Image Page | https://hub.docker.com/r/dicloakinc/dicloak-runtime-image |
| DICloak Local API Developer Guide | https://help.dicloak.com/api-development-guide/ |
| DICloak Official Website | https://dicloak.com |