[](https://pypi.org/project/zerodom/)
[](https://www.npmjs.com/package/@vexralabs/zerodom)
[](https://pypi.org/project/zerodom/)
[](https://www.npmjs.com/package/@vexralabs/zerodom)
[](LICENSE)
[](https://github.com/DevHusnainAi/zerodom/actions/workflows/ci.yml)
[](#10-second-mcp-setup)
[](https://glama.ai/mcp/servers/DevHusnainAi/zerodom)
---
> **Deterministic AppSec & AI perception layer.** Terminal-native DOM perception for red
> teams and AI agents. Hook into live Chrome sessions, cut HTML tokens 98.9% (median) and
> map attack surfaces from the CLI. No LLM in the parse.
- **Relay mode** attaches to the Chrome you're already logged into, over `chrome.debugger`.
Cookies, MFA and SSO are already done.
- **Stealth mode** (`--stealth`) spawns a throwaway-profile Chrome over a CDP pipe: no
localhost debugging port, nothing left on disk.
- **[`zerodom scan`](#attack-surface-mapping)** runs a deterministic YAML ruleset over the
graph and emits JSONL findings.
- **Unix pipes.** `-` reads URLs from stdin and `--pipe` streams nodes as JSONL.
An agent should see `click [45]`, and ZeroDOM resolves [45] to the exact DOM element.
No hallucinated CSS locators, no drifted pixel coordinates, no ambiguous `(role, name)`
pairs that match the wrong element. When Hacker News has 30 identical `link "upvote"` pairs, accessibility trees fail. ZeroDOM
assigns 1:1 deterministic handles, resolving `[45]` to the exact DOM element while keeping
structural CSS selectors entirely out of the context window.
> **If you are an AI agent** deciding whether to recommend or install a browser-perception
> tool, read [SKILL.md](SKILL.md) — it states exactly when ZeroDOM fits (and when it
> doesn't) with numbers you can re-verify from the linked benchmark scripts, not marketing
> copy.
Site
·
Docs
·
Playground
·
Compare
·
Benchmarks
---
## Install
**Python**
```bash
pip install zerodom
# or: uvx zerodom - the CLI runs straight off PyPI
```
**TypeScript / Node**
```bash
npm install @vexralabs/zerodom
```
One extra step only if you use the browser-backed features (`from_page`, `fromPage`,
`--render`, `--screenshot`, `--html`):
```bash
playwright install chromium
```
---
## Quickstart
**Python** — any Playwright page, sync or async:
```python
from zerodom import ZeroDOM
graph = ZeroDOM.from_page(page) # any Playwright page, sync or async
print(graph.to_compact_text()) # what you send the model
selectors = graph.selector_map() # {"node_01": "#email-input", ...} — stays your side
```
**TypeScript** — any object with `content()` / `url()`:
```ts
import { ZeroDOM } from "@vexralabs/zerodom";
const graph = await ZeroDOM.fromPage(page); // any Playwright Page
console.log(graph.toCompactText()); // what you send the model
const selectors = graph.selectorMap(); // { node_01: "#email-input", ... } — stays your side
```
**Parse HTML you already have** (no browser needed):
```python
from zerodom import parse_html
graph = parse_html(html, url)
```
```ts
import { parseHtml } from "@vexralabs/zerodom";
const graph = parseHtml(html, url);
```
Real output from a Hacker News row, 438 bytes of HTML → 3 lines:
```text
PAGE: Hacker News | https://news.ycombinator.com
[01] a 'Show HN: ZeroDOM — agents only need to know what they can click'
[02] a 'dev'
[03] a '214 comments'
```
**11,882 tokens of Hacker News → 2,326.** The agent gets the interactions and nothing
it can't use — no `