dots is an open-source AI web agent that ships with its own anti-detect Firefox browser, aimed at developers and automation engineers who need an agent to browse, log in and click through real websites without being blocked.
What it is
dots is a Python project, MIT licensed, that pairs a language model with a browser built for automation. The model is any model available on OpenRouter, selected with the --model flag, while the browser is a real Firefox engine patched in C++. The project's premise is that every AI agent is a model plus a browser, and that while the model can be swapped with one flag, the browser is what the website actually sees. The interface runs as a local web page where the conversation sits on the left and the live browser on the right.
The concrete problem it addresses is web-agent failure caused by the browser rather than the model: a page that never loads, a challenge that appears, a login that expires, or a click that does not land. Dots is built around making that layer reliable. Its fingerprint is decided inside the engine rather than painted over with JavaScript a page can inspect, and no WebDriver flag, DevTools protocol or automation globals are exposed to the page. Pointer movements travel to the element that is clicked and keys are pressed one at a time, so every event the page receives is a trusted one.
Key capabilities
- A real Firefox engine patched in C++, so the fingerprint is set inside the engine rather than emulated by page-inspectable JavaScript.
- One identity per seed: screen, fonts, GPU, timezone and language agree with each other, and
--seed returns the same identity on every run.
--profile-dir persists logins and cookies from one run to the next.
--proxy makes the timezone and language follow the exit node the connection is made from.
--model swaps the underlying language model, which can be any model on OpenRouter, with --openrouter-key supplying the credential.
- Natural-language multi-step browsing tasks, such as checking flight fares across a range of dates and reading the cheapest fare for each day without guessing unavailable numbers.
- The same browser is exposed as a server through the companion project
invisible_playwright_mcp for MCP clients.
Who uses it and how
- Developers running a local agent session at
http://127.0.0.1:8765, keeping the conversation and the live browser side by side while working through a task.
- Users of Claude Code, Codex, Gemini CLI or any MCP client who attach
invisible_playwright_mcp to give their existing assistant this browser as a server.
- Automation engineers who need repeatable identities across runs, using
--seed so the same person is presented every time.
- Operators who combine
--proxy with a persistent --profile-dir to keep a login alive across sessions while the traffic exits from a chosen location.
- Command-line users on Windows (PowerShell) or Linux who install via
uv and launch with uvx.
Getting started
Install uv, then run uvx --from git+https://github.com/feder-cr/dots dots --openrouter-key sk-or-... and open http://127.0.0.1:8765; dots --help lists every option.
How it compares
Among the tools named in its own documentation, dots is the browser layer that Claude Code, Codex and Gemini CLI do not provide themselves; it hands those assistants the browser through invisible_playwright_mcp as a server, with dots serving as its interface. It therefore complements those assistants rather than competing with them, supplying the anti-detect Firefox engine they would otherwise borrow from a generic Playwright installation.
When to use it — and when not
A self-hoster runs a local server on port 8765 and must supply an OpenRouter API key, so the model side is tied to that provider even though the model itself is swappable. It is not a good fit for teams that want a hosted service, a non-Firefox engine, or a model outside OpenRouter. The README is terse, and the anti-detect and patched-engine claims are the kind best verified against a target site before relying on them.
project readme (upstream, from github) — read inline
dots
Every AI agent is a model and a browser.
You can swap the model with one flag. The browser is what the website sees.
Windows, in PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
uvx --from git+https://github.com/feder-cr/dots dots --openrouter-key sk-or-...
Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uvx --from git+https://github.com/feder-cr/dots dots --openrouter-key sk-or-...
Then open http://127.0.0.1:8765. The conversation on the left, the browser on the right, live.
It all comes down to the browser
When a web agent fails, the model is rarely why. The page never loaded, a
challenge appeared, the login expired, the click did not land. All of that
happens in the browser, before the model gets to think.
So dots is built around one:
- A real Firefox engine, patched in C++. The fingerprint is decided inside
the engine, not painted over with JavaScript that a page can inspect.
- One identity per seed. Screen, fonts, GPU, timezone and language agree
with each other, and
--seed gives back the same person on every run.
- Nothing for a page to find. No WebDriver flag, no DevTools protocol, no
automation globals in the page.
- A person's hands. The pointer travels to what it clicks and keys are
pressed one at a time, so every event the page receives is a trusted one.
- A browser that remembers.
--profile-dir keeps logins and cookies from
one run to the next.
- Where it connects from is who it is. With
--proxy, the timezone and the
language follow the exit.
The model is any model on OpenRouter, and --model changes it.
What to ask it
Go to ``. One way, Milan to Lisbon, economy, one adult. Check
every date from the 12th to the 16th of next month and read the cheapest fare
for each day. If a date has no availability, say so. Do not guess a number.
The same browser, in your own assistant
Claude Code, Codex, Gemini CLI or any MCP client:
invisible_playwright_mcp
gives them this browser as a server. dots is its interface, and dots --help
lists every option.
Not affiliated with OpenAI. MIT licensed.