Skip to main content

How MonoSurf Works

The Engine

MonoSurf is a Rust binary that controls Chrome directly through the Chrome DevTools Protocol (CDP) via chromiumoxide — a Rust-native CDP client. No subprocess, no Node.js, no Playwright dependency.
┌─────────────────────────────────────────────────────────────────┐
│  Command: monosurf x.com search "AI terminal" --profile work     │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  1. Resolve profile → port 9222                                   │
│     └── Check CDP alive (TcpStream connect)                      │
│     └── Auto-starts Chrome if not running                        │
│                                                                   │
│  2. Connect via chromiumoxide                                     │
│     └── Browser::connect_with_config("http://127.0.0.1:9222")   │
│     └── WebSocket CDP session established                        │
│                                                                   │
│  3. Load site plugin (x.com.json)                                │
│     └── Validate domain matches base_url                         │
│     └── Integrity check (checksum)                               │
│                                                                   │
│  4. Check auth gate                                              │
│     └── Read scope: grant required                               │
│     └── Write scope: separate grant required                     │
│                                                                   │
│  5. Inject cookies from keychain                                 │
│     └── CDP Network.setCookies (supports HttpOnly)               │
│                                                                   │
│  6. Navigate via CDP                                             │
│     └── page.goto(url) with 15s timeout                          │
│     └── Fallback: window.location.href via JS evaluate           │
│                                                                   │
│  7. Dismiss cookie banners (auto JS evaluate)                    │
│                                                                   │
│  8. Wait for content selector                                    │
│     └── JS polling via page.evaluate()                           │
│     └── Falls back to timeout if selector not found              │
│                                                                   │
│  9. Execute extraction JavaScript                                │
│     └── page.evaluate(extract_js) — direct CDP Runtime.evaluate  │
│     └── Returns JSON array                                       │
│                                                                   │
│ 10. Format and output                                            │
│     └── Display template or generic key:value                    │
│     └── --json for structured output                             │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Profile Management

MonoSurf manages isolated Chrome instances per profile:
CommandPurpose
monosurf start --profile workLaunch Chrome with CDP (visible)
monosurf start --profile work --headlessLaunch headless (no window)
monosurf stop --profile workStop Chrome
monosurf profilesList all profiles + status
monosurf browsersDiscover available browser engines
Each profile uses a separate --user-data-dir and CDP port. On macOS, open -n ensures MonoSurf Chrome doesn’t conflict with the user’s regular Chrome.

Connection Flow

  1. Resolve profile name → CDP port from profiles.json
  2. TCP connect check: is port alive?
  3. If not, launch Chrome (visible or headless, system or Playwright/Puppeteer)
  4. Browser::connect_with_config() → WebSocket to Chrome CDP
  5. Get or create a page
  6. All subsequent commands go through this page
v0.4 uses CDP Network.setCookies / Network.getCookies instead of JavaScript document.cookie. This means:
  • HttpOnly cookies — accessible (JS-based approach couldn’t see these)
  • Full metadata — domain, path, expiry, secure flag
  • Cross-origin — can set cookies for any domain
Some sites (especially in headless mode) don’t complete the CDP Page.navigate event. MonoSurf uses a timeout fallback:
page.goto(url)
  → 15 second timeout
  → If timeout: fallback to window.location.href = url via JS
  → Wait 2 seconds for page load
This ensures headless mode works even when Chrome’s navigation events are unreliable.

Write Operations

For commands with intent: "write", MonoSurf executes a sequence of JS actions:
Navigate to URL
  → JS: click compose area (element.click())
  → JS: focus contenteditable + execCommand('insertText')
  → JS: find submit button + element.click()
  → Return result
All actions use js type — DOM queries and element.click(). The pw (Playwright script) action type from v0.2 is removed since there is no Playwright subprocess. Multiline text is supported — line breaks in the type action are preserved. For anti-bot sites that strip CSS selectors, JS actions use accessibility attributes:
{"js": "(() => { const btns = document.querySelectorAll('[role=button]'); for (const b of btns) { if (b.textContent.trim() === 'Reply') { b.click(); return 'clicked'; } } })()"}

Why JS element.click() Instead of CDP Mouse Events

All JS click operations use element.click() instead of CDP mouse events. This avoids scroll_into_view() which breaks modal dialogs (discovered through React source code analysis). JS clicks work on regular pages, modals, React SPAs, and any framework.

Browser Selection

MonoSurf discovers browsers at runtime from 3 sources:
SourceStealthBest For
System ChromeNoVisible mode, login
Playwright ChromiumYesHeadless automation
Puppeteer ChromeYesHeadless automation
System Chrome in headless mode may trigger bot detection (X.com, Cloudflare). Playwright/Puppeteer Chromium has navigator.webdriver spoofing and other stealth features built into the binary. Install Chromium for headless use:
npx playwright install chromium
monosurf start --profile bot --browser 2 --headless