Self-hosted, developer-focused browser automation and extraction with block-based tasks.
10K+
Doppelganger is a self‑hosted, block-first automation control plane built for teams that want predictable, auditable browser workflows without pushing sensitive data to third‑party SaaS. It bundles a React/Vite frontend, an Express/Playwright backend, helper scripts, and optional CLI tooling so you can sketch blocks, inject JavaScript, rotate proxies, and run everything locally.

/tasks/:id/api) or npx doppelganger while passing variables and securing runs with the API key you control.Frontend
/dashboard, /tasks, /settings, /executions, and /captures.System, Data, Proxies) and houses panels for API keys, user agents, layout, storage, and version info./api/* endpoints through the Vite dev proxy (see vite.config.mts), sharing APP_VERSION via src/utils/appInfo.ts.Backend
server.js (Express) handles auth (/api/auth), task metadata, hooks into Playwright, and exposes /api/settings/* for runtime configuration.npm install.data/ for proxies and allowlists, public/captures for visuals, storage_state.json for cookies.Scripts & automation
scripts/postinstall.js runs when dependencies install (keep an eye if you customize).agent.js, headful.js, scrape.js expose specialized runners; the CLI binary bin/cli.js wires them for npx doppelganger.Code layout highlights
src/App.tsx glues together routing, alerts, and the sidebar that links dashboards, tasks, and settings.src/components houses reusable panels (API keys, storage, captures, proxies) that map directly to backend endpoints.server.js embeds all HTTP handlers in one file; use the data/ helpers for proxies, API keys, and user agent preferences if you customize behavior.The easiest way to run Doppelganger on any architecture (including M1/M2/M3 Macs) is via Docker Compose.
git clone https://github.com/mnemosynestack/doppelganger.git
cd doppelganger
docker compose up --build -d
This starts the app on http://localhost:11345 and the VNC viewer on http://localhost:54311.
docker pull mnemosyneai/doppelganger
docker run -d \
--name doppelganger \
-p 11345:11345 \
-p 54311:54311 \
-e SESSION_SECRET=replace_with_long_random_value \
-v $(pwd)/data:/app/data \
-v $(pwd)/public:/app/public \
-v $(pwd)/storage_state.json:/app/storage_state.json \
mnemosyneai/doppelganger
Visit http://localhost:11345. Stop/start with docker stop/start doppelganger.
The first visit loads the login/setup screen. After you create the admin account and sign in, the dashboard replaces the login view and stays visible for as long as the session remains valid; returning users are redirected straight to the dashboard until they explicitly log out or the session expires.
npm install
npm run server
npm run dev
Frontend calls /api via the Vite proxy defined in vite.config.mts; the backend listens on process.env.VITE_BACKEND_PORT (default 11345).
If you just want to run the packaged release (no source checkout), install the published npm package and run doppelganger directly.
npm install -g @doppelgangerdev/doppelganger
doppelganger
Or use npx:
npx @doppelgangerdev/doppelganger
If you prefer not to install globally, clone the repo, run npm install to pull dependencies, and then run npx @doppelgangerdev/doppelganger inside that folder. This ensures npx can resolve the package from the local registry/cache while still shipping the same dashboard experience.
Set SESSION_SECRET and optionally mount data/, public/, and storage_state.json (match the Docker volume layout). The CLI spins up the same Express/Playwright stack and opens the browser-based dashboard at http://localhost:11345 unless you override PORT.
Set SESSION_SECRET before any run. A quick generator:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
| Variable | Purpose | Default |
|---|---|---|
SESSION_SECRET | Signs session cookies. Required. | — |
ALLOWED_IPS | Comma list for basic IP allowlisting. | none (open) |
TRUST_PROXY | Honor X-Forwarded-* when behind a reverse proxy. | 0 |
VITE_DEV_PORT | Port for front-end dev server. | 5173 |
VITE_BACKEND_PORT | Backend port for proxying + scripts. | 11345 |
Proxy rotation also respects data/proxies.json (see below), and data/allowed_ips.json works as an alternate allowlist format.
PLAYWRIGHT_BROWSERS_PATH (or set PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH) when using a shared Playwright installation.NODE_ENV=production enables the bundled dist/ client and reduces console verbosity.HOST=0.0.0.0 allows binding beyond localhost inside Docker containers, while PORT overrides the Express listen port (defaults to 11345).LOG_LEVEL to debug if you need more Playwright or proxy diagnostics; this can also be a custom wrapper when running node server.js.54311, so open that port alongside 11345 when running headful.js or other headful flows.public/captures; delete individually or refresh.VersionPanel), and clear storage.npx doppelganger (or npm run cli) to launch the interactive CLI that shows tasks, status, and logs.bin/cli.js can invoke agent.js, headful.js, or scrape.js depending on the runtime mode (--agent, --headful, --scrape).node agent.js --help to see flags like --task, --browser, or --version. These runners share the same settings (API key, proxies, storage) as the web UI.Authorization: Bearer <key> so reverse proxies can normalize headers; the CLI also accepts a --api-key flag for scripted runs.AGENT_SPEC.md, including mode/modes (agent/block), wait times, selectors, and stealth flags.click, type, wait, press, scroll, javascript, csv, hover, merge, screenshot, if/else/end, loops, foreach, stop, set, on_error, start), so you can encode complex flows.{$var} ), structured conditions, and helper functions such as exists(), text(), and block output ensure reusable, data-driven tasks.AGENT_SPEC.md.Proxies can be defined via the UI or data/proxies.json:
[
"http://user:[email protected]:8000",
{ "server": "socks5://proxy2.example.com:1080", "label": "data center" }
]
host is always available and represents your machine’s default IP.round-robin or random) live in the Settings screen and persist through the backend endpoints./api/settings/proxies/import.POST /tasks/:id/api)
x-api-key or Authorization: Bearer <key>.{ "variables": { ... } } to override task variables or provide runtime data./api/settings/api-key — GET current, POST regen./api/settings/user-agent — toggle system vs custom list./api/settings/proxies* — GET/POST/PUT/DELETE plus rotation toggles.POST /api/clear-screenshots — removes files in public/captures.POST /api/clear-cookies — deletes storage_state.json.Authentication enforces sessions (/api/auth/login, /api/auth/logout, /api/auth/me); read server.js to see the guard/middleware logic.
return document.querySelectorAll('article').length;
#, ., and attribute hints.headful.js or agent.js depending on whether you need a visible browser for debugging.task.variables via the API to re-use generic workflows across multiple domains.goto block and a wait block to give pages time to render.javascript blocks to test for specific DOM elements; use the retry/timer controls per block.extract (JSON output) or screenshot actions before submitting so you can inspect results in the Captures tab.POST /tasks/:id/api endpoint with variables like {"variables":{"query":"books"}} to run it from automation tools.npm run build before packaging for production; the dist/ folder contains the compiled assets.server.js for debugging proxies, authentication, or Playwright failures.node_modules/.cache when using the CLI.SESSION_SECRET is consistent and cookies aren’t blocked by your browser.headful/headless modes or adding delays.data/proxies.json for valid URLs; the backend validates server as a string.public/captures; regular cleanups can be scripted via POST /api/clear-screenshots.storage_state.json. Back up this file before clearing cookies via the UI or /api/clear-cookies.data/ (look for proxies.json, allowed_ips.json, etc.) — treat this directory as your config source control.Storage controls in Settings to clear data after experimentation cycles, and keep layouts or version info tracked via localStorage as shown in src/components/SettingsScreen.tsx.data/ and storage_state.json backed up if you rely on historical cookies or proxies.mnemosyneai/doppelganger (Docker) or npm i @doppelgangerdev/doppelganger (npm). The Settings view always displays the current package version..github/ templates, respect CONTRIBUTING.md, and run available lint/test scripts if you touch critical areas./api/clear-screenshots and /api/clear-cookies./api/settings/api-key, so secure API access is ready without extra setup.storage_state.json, ensuring no cookies or local storage persist between executions for that workflow.SESSION_SECRET, API keys, or storage_state.json into shared repositories.ALLOWED_IPS/data/allowed_ips.json to gate the UI when deploying to a network-exposed host.node_modules after significant OS patches.https://github.com/mnemosynestack for releases.If you find this project helpful, please consider supporting its development. Your contributions help keep the project maintained and the lights on!
Other ways to help:
Content type
Image
Digest
sha256:e894ef82a…
Size
1.3 GB
Last updated
3 months ago
docker pull mnemosyneai/doppelganger