Metadata-Version: 2.4
Name: eyebrowse
Version: 0.1.6
Summary: EyeBrowse — a stealthy, LLM-drivable browser-control engine (Camoufox), consumed as a library and over MCP.
Project-URL: Homepage, https://github.com/Evil-Bane/eyebrowse
Project-URL: Repository, https://github.com/Evil-Bane/eyebrowse
Project-URL: Issues, https://github.com/Evil-Bane/eyebrowse/issues
Author-email: Evil-Bane <72240505+Evil-Bane@users.noreply.github.com>
License: MIT
License-File: LICENSE
Keywords: agent,anti-detection,browser-automation,camoufox,firefox,llm,mcp,model-context-protocol,playwright,stealth,web-scraping
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Testing
Requires-Python: <3.13,>=3.12
Requires-Dist: camoufox[geoip]==0.4.11
Requires-Dist: httpx>=0.27
Requires-Dist: imageio-ffmpeg>=0.5
Requires-Dist: mcp>=1.2.0
Requires-Dist: pillow>=10.0
Requires-Dist: playwright<2,>=1.40
Requires-Dist: pydantic-settings>=2.2
Requires-Dist: pydantic>=2.6
Requires-Dist: pyotp>=2.9
Provides-Extra: extract
Requires-Dist: crawl4ai>=0.4.0; extra == 'extract'
Description-Content-Type: text/markdown

<div align="center">

# 🦊 EyeBrowse

### A stealthy, LLM-drivable browser engine — one codebase, two faces.

A **Python library** *and* an **MCP server** for driving a real, hard-to-detect browser
— Camoufox, a Firefox fork with C++-level fingerprint spoofing — so legitimate automation
isn't false-flagged or IP-banned by Cloudflare, DataDome, Akamai, or PerimeterX.

[![PyPI](https://img.shields.io/pypi/v/eyebrowse?color=3775A9&logo=pypi&logoColor=white)](https://pypi.org/project/eyebrowse/)
[![Python 3.12](https://img.shields.io/badge/python-3.12-3776AB?logo=python&logoColor=white)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-22c55e.svg)](LICENSE)
[![MCP tools](https://img.shields.io/badge/MCP-78_tools-7c3aed.svg)](docs/TOOLS.md)
[![Engine: Camoufox](https://img.shields.io/badge/engine-Camoufox%20(Firefox)-FF6611.svg)](https://github.com/daijro/camoufox)

![EyeBrowse driving a real browser](https://raw.githubusercontent.com/Evil-Bane/eyebrowse/master/docs/demo.gif)

<sub>▶ Higher-quality MP4: <a href="https://github.com/Evil-Bane/eyebrowse/blob/master/docs/demo.mp4">docs/demo.mp4</a> — real EyeBrowse captures, composed into an ad by <code>examples/make_demo.py</code></sub>

</div>

---

## Why EyeBrowse?

- 🥷 **Stealth by default** — engine-level fingerprint spoofing (`geoip` + `humanize` + `block_webrtc` on out of the box); `navigator.webdriver` masked; viewport auto-sized to the spoofed screen. No `puppeteer-extra` band-aids — the anti-detection is *in the browser*.
- 🤖 **Built for LLMs** — pages are read as an **ARIA tree with `[ref=…]` handles**; the model acts by ref (`click`/`type`/`hover`), not by brittle CSS or raw pixels. Cross-origin iframes, shadow DOM, popups — handled.
- 🧰 **Library *and* MCP from one codebase** — a clean Python API (`EyeBrowse` + `Session`), mirrored 1:1 by a thin **MCP server** (**78 `browser_*` tools**) for Claude Code and any MCP client.
- 🪟 **Never boxed in** — the curated high-level API doesn't hide Playwright: reach `session.page` / `.context` / `.browser` for anything it doesn't wrap.
- 🔋 **Batteries included** — multi-session, proxy + identity rotation, API-mode captcha solvers, full HAR capture, screen recording (MP4/GIF), and clean-markdown extraction.

> **Scope.** EyeBrowse is a low-level browser *engine* — it holds **no workflow logic**.
> Consumers decide *what* to do; the engine provides *what's possible*.

## Contents

[Quickstart](#quickstart) · [Install](#install) · [Features](#features) · [Library](#use-as-a-library) · [MCP](#use-over-mcp) · [Proxy & identity](#proxy--identity-optional) · [Extraction](#extraction) · [Recording](#recording) · [How it works](#how-it-works) · [Caveats](#camoufox-caveats) · [Tools](docs/TOOLS.md) · [License](#license)

## Quickstart

```bash
pip install eyebrowse
python -m camoufox fetch          # one-time: download the stealth Firefox + GeoIP db
```

```python
import asyncio
from eyebrowse import EyeBrowse

async def main():
    eb = EyeBrowse()                          # stealth defaults: geoip · humanize · block_webrtc
    async with eb.session() as s:
        await s.navigate("https://example.com")
        print(await s.snapshot())             # ARIA tree with [ref=...] handles
        await s.click("e6")                   # act on a ref from the snapshot
    await eb.aclose()

asyncio.run(main())
```

…or wire it into **Claude Code** (or any MCP client) — see [Use over MCP](#use-over-mcp).

## Install

**From PyPI**

```bash
pip install eyebrowse                 # or: uv pip install eyebrowse
python -m camoufox fetch             # one-time browser fetch (like Playwright's `playwright install`)
pip install "eyebrowse[extract]"     # optional: + Crawl4AI markdown extraction (heavier)
```

**From source (development)**

```bash
git clone https://github.com/Evil-Bane/eyebrowse && cd eyebrowse
uv sync                              # core engine  (add --extra extract for Crawl4AI)
uv run python -m camoufox fetch
cp .env.example .env                 # only if you use a proxy / captcha keys
```

Python 3.12 (pinned `<3.13`). Pinned engine: `camoufox==0.4.11` (Firefox v135), `playwright 1.60`, `mcp 1.27`.

## Features

| | |
|---|---|
| 🥷 **Stealth** | Camoufox engine-level fingerprint spoofing; `geoip` + `humanize` + `block_webrtc` by default; `webdriver` masked; viewport matched to the spoofed screen. |
| 🤖 **LLM interaction** | `aria_snapshot(mode="ai")` → ARIA tree + `[ref]` handles; click / type / hover / select / drag / file-upload / dialogs / keyboard; coordinate mouse too. |
| 🪟 **Frames & DOM** | cross-origin iframe routing by ref, shadow-DOM piercing, popup/new-tab switching, `evaluate` inside any frame. |
| 🗂 **Multi-session** | independent stealth sessions, each with its own context / identity / proxy. |
| 🌐 **Network** | inspect requests/responses (incl. XHR/fetch bodies & WebSocket frames), block URLs, mock responses, go offline, full **HAR** export. |
| 💾 **State** | cookies, localStorage & sessionStorage (CRUD), `storage_state` save/reload. |
| 🪪 **Identity rotation** | fresh fingerprint (OS/screen) + isolated profile + paired proxy; pluggable residential `ProxyProvider`. |
| 🧩 **Captcha** | pluggable **API-mode** solvers (CapSolver / 2Captcha / CapMonster / NextCaptcha) + TOTP — no browser extension. |
| 📄 **Extraction** | Crawl4AI `raw:` feed → clean, token-efficient **markdown** (no LLM, no API keys). |
| 🎥 **Capture** | screenshots, Playwright tracing, and **screen recording → MP4 / WebM / GIF** (ffmpeg). |
| ✅ **Verify & debug** | assertions, element highlighting, locator generation, geolocation/header emulation. |

Full per-tool reference: **[docs/TOOLS.md](docs/TOOLS.md)** (78 tools across 17 groups).

## Use as a library

```python
import asyncio
from eyebrowse import EyeBrowse

async def main():
    eb = EyeBrowse()                           # stealth defaults
    try:
        async with eb.session() as s:          # a stealth session (auto-closed)
            await s.navigate("https://example.com")
            print(await s.snapshot())          # ARIA tree with [ref=...] handles
            await s.click("e6")                # act on a ref
            await s.type("e8", "hello", submit=True)
            png = await s.screenshot(full_page=True)
            title = await s.page.title()        # full Playwright power when you need it
    finally:
        await eb.aclose()

asyncio.run(main())
```

Run the included proof: `uv run python examples/direct_usage.py`.

## Use over MCP

EyeBrowse ships an MCP server (`eyebrowse-mcp`, FastMCP over stdio). Add it to any MCP client.

**Claude Code (CLI):**

```bash
claude mcp add eyebrowse -- eyebrowse-mcp
```

**Any MCP client (JSON config):**

```json
{
  "mcpServers": {
    "eyebrowse": {
      "command": "eyebrowse-mcp"
    }
  }
}
```

Then drive the loop: `browser_navigate(url)` → read the snapshot → act by ref
(`browser_click` / `browser_type` / …). A default session is auto-created, so most tools just
work. Full list: **[docs/TOOLS.md](docs/TOOLS.md)**.

## Proxy & identity (optional)

Runs **proxyless by default** (`geoip` still aligns locale/timezone to your real IP). Add a proxy
only when you want one:

```python
await eb.new_session(proxy="http://user:pass@residential.example:8080")
await eb.rotate_identity(proxy="socks5://host:1080")   # fresh fingerprint + paired IP
await eb.new_session(no_proxy=True)                     # force proxyless
```

Set a default once via `EYEBROWSE_PROXY_*` in `.env`, `eb.set_static_proxy(...)`, or a custom
`ProxyProvider` for rotation. Over MCP: `browser_new_session(proxy_url=…)` /
`browser_new_identity(proxy_url=…)` / `browser_set_proxy(…)`.

## Extraction

`eb.extract()` (or `browser_extract`) hands the rendered HTML to Crawl4AI's `raw:` feed and
returns clean, pruned **markdown** — **no LLM is called and no LLM keys are ever read**; the
consuming agent does any structuring.

```python
md  = await eb.extract()                            # markdown string
res = await eb.extract(output_path="data/page.md")  # → {"path": ..., "chars": ...}
```

## Recording

Camoufox can't write native browser video, so EyeBrowse rolls its own recorder: it captures
viewport frames and encodes them with **ffmpeg** into a smooth, real-time **MP4/WebM** (and a
palette-optimized **GIF** that autoplays inline on GitHub). ffmpeg ships bundled
(`imageio-ffmpeg`), so it works out of the box.

```python
await s.start_recording(fps=30)
# ... drive the browser ...
await s.stop_recording("demo.mp4", extra_paths=["demo.gif"])
```

The demo at the top was produced this way — see **`examples/make_demo.py`**.

## How it works

```
CONSUMERS                         ENGINE (library: eyebrowse/)
 Claude Code  ──MCP──▶  mcp/  ──▶  EyeBrowse façade (public API)
 your code   ─ import ──────────▶   ├─ Camoufox engine (stealth context, HAR)
 any MCP client                     ├─ proxy / identity rotation (pluggable)
                                    ├─ captcha solvers (pluggable, API-mode)
                                    └─ Crawl4AI (raw: feed) → clean markdown
```

The façade (`EyeBrowse` + `Session`) is the product; the MCP adapter is a thin 1:1 wrapper over
it. The high-level API is curated and LLM-friendly — *not* a reimplementation of all of Playwright
— and the raw `page` / `context` / `browser` objects are always one attribute away.

## Camoufox caveats

These shape the API — worth knowing:

- **`evaluate` runs in an isolated world** — it sees the DOM but **not** page-script `window.*`
  globals. Read app state via DOM / network / HAR.
- **reload / back / forward** aren't reported by Firefox's Juggler, so they're driven via `goto` +
  an internal navigate() history (they traverse navigate()-driven history, not click-driven).
- **Not available on Firefox/Camoufox** (intentionally omitted, not broken): `page.pdf()`, media
  emulation, and native Playwright video — use the **ffmpeg recorder** instead.

## Project layout

```
eyebrowse/
  api.py            EyeBrowse façade — the single public entry point
  config.py         settings / secrets (pydantic-settings)
  snapshot.py       aria_snapshot(mode="ai") + aria-ref= resolution
  proxy.py          ProxyConfig + pluggable ProxyProvider
  identity.py       Identity + random_identity()
  extract.py        Crawl4AI raw: feed → markdown (lazy, optional dep)
  engine/           camoufox_engine.py (launch) + session.py (verbs + registry)
  captcha/          solver ABC + 4 providers + DOM detect/inject
  mcp/              FastMCP server + state + tools/ (17 groups, 78 tools)
examples/direct_usage.py   library proof (no MCP)
examples/make_demo.py      the screen-recording demo above
docs/TOOLS.md              full tool reference
```

Build notes, version-pin rationale, and verified Camoufox behavior live in **[CLAUDE.md](CLAUDE.md)**.

## Use responsibly

EyeBrowse drives a real browser with anti-detection features. Use it only against sites you
own or are explicitly authorized to automate, and within their terms and applicable law.

## License

[MIT](LICENSE) © Evil-Bane
