{"repo":"keon/browser-control","free":true,"listed":false,"github":"https://github.com/keon/browser-control","clone":"git clone https://github.com/keon/browser-control.git","description":"A tiny, fast Rust CLI that drives a real browser over the Chrome DevTools Protocol — built for coding agents.","language":"Rust","stars":3128,"topics":["agent","browser-automation","llm","rust"],"license":"MIT","category":"dev_tool","readme_excerpt":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/keon/browser-control/main/assets/hero.png\" alt=\"browser-control\" width=\"100%\">\n</p>\n\n<h1 align=\"center\">browser-control</h1>\n\n<p align=\"center\">\n  <strong>A tiny, fast Rust CLI that drives a real browser over the Chrome DevTools Protocol — built for coding agents.</strong>\n</p>\n\n<p align=\"center\">\n  No LLM. No MCP requirement. No framework. Just compact, composable browser commands you can pipe from a shell.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://crates.io/crates/browser-control-cli\"><img src=\"https://img.shields.io/crates/v/browser-control-cli.svg?logo=rust&color=2ea44f\" alt=\"crates.io\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/crates/l/browser-control-cli.svg?color=blue\" alt=\"MIT license\"></a>\n  <img src=\"https://img.shields.io/badge/protocol-Chrome_DevTools-4285F4?logo=googlechrome&logoColor=white\" alt=\"CDP\">\n  <img src=\"https://img.shields.io/badge/cloud-Browser_Use_·_Steel_·_Hyperbrowser_·_Browserbase-6e56cf\" alt=\"cloud providers\">\n</p>\n\n---\n\n`browser-control` exposes a browser as a small, debuggable pipe: page snapshots, stable element refs, raw CDP, a background event watcher, and shell-runnable scripts. The coding agent stays the agent — `browser-control` just gives it hands and eyes.\n\n```bash\nbrowser-control launch https://example.com\nbrowser-control snapshot                 # @e1 <input#search>, @e2 <a \"Get started\">, ...\nbrowser-control click @e2\nbrowser-control eval 'document.title'\n```\n\n## Why browser-control\n\n- **Shell-native.** Every capability is a subcommand that prints compact text or JSON. No SDK, no long-running server to babysit, no language lock-in — if your agent can run a shell command, it can drive a browser.\n- **Refs built for LLMs.** `snapshot` hands back stable `@e1` / `@e2` handles you act on directly (`click @e3`), instead of brittle, hand-written selectors. CSS selectors and `x,y` coordinates still work when you want them.\n- **Raw CDP escape hatch.** Anything the helper surface can't express, `eval` and `cdp` can. You never hit a wall and have to switch tools.\n- **Self-observing.** A hidden daemon keeps in-memory event / network / console rings, and every command failure drops a compact trace under `.browser-control/traces/` so an agent can diagnose itself.\n- **Provider-agnostic cloud.** Drive a local Chrome or a remote session on Browser Use, Steel, Hyperbrowser, Browserbase — or any CDP provider — with the same commands.\n- **Reproducible.** One static Rust binary, built from a pinned toolchain and a committed `Cargo.lock`.\n\n## Installation\n\n### From crates.io\n\n```bash\ncargo install browser-control-cli      # installs the `browser-control` binary\nbrowser-control --version\n```\n\n> The crate is named `browser-control-cli` (the name `browser-control` was taken), but the installed command is **`browser-control`**.\n\n### Prebuilt binaries\n\nGrab a binary for your platform from the [latest GitHub release](https://github.com/keon/browser-control/releases/latest) — no Rust toolchain required.\n\n```bash\n# macOS / Linux, e.g. aarch64-apple-darwin:\ncurl -fsSL https://github.com/keon/browser-control/releases/latest/download/browser-control-aarch64-apple-darwin.tar.gz | tar xz\ninstall -m 0755 browser-control /usr/local/bin/\n```\n\n### From source\n\n```bash\ngit clone git@github.com:keon/browser-control.git\ncd browser-control\nrustup toolchain install      # installs the version pinned in rust-toolchain.toml\ncargo build --locked --release\n```\n\nThe release binary lands at `target/release/browser-control`. Put it on your `PATH`:\n\n```bash\ninstall -m 0755 target/release/browser-control /usr/local/bin/\nbrowser-control --version\n```\n\n### Requirements\n\n- **Rust** — the toolchain pinned in `rust-toolchain.toml` (installed automatically by `rustup toolchain install`).\n- **Chrome / Chromium** — any recent build reachable over CDP. `browser-control launch` will start one for you; `doctor` reports what it found.\n\n### Reproducible builds\n\nThe direct dependencies in `Cargo.toml` are exact-version constraints and transitive deps are frozen by `Cargo.lock`. Always build with `--locked` in CI or benchmark reproduction:\n\n```bash\ncargo build --locked\ncargo test  --locked\nscripts/verify.sh     # one-command local verification\n```\n\n## Quick start\n\n```bash\nbrowser-control init                       # create the .browser-control/ workspace\nbrowser-control launch https://example.com # start Chrome + connect\nexport BROWSER_CONTROL_CDP_URL=http://127.0.0.1:9222\n\nbrowser-control doctor                      # endpoint, browser, pid, daemon, workspace\nbrowser-control snapshot                    # numbered refs for every actionable element\nbrowser-control click @e1\nbrowser-control eval 'document.title'\nbrowser-control cdp Browser.getVersion\n```\n\nAlready have a browser listening on CDP? Skip `launch` and point at it:\n\n```bash\nexport BROWSER_CONTROL_CDP_WS='ws://127.0.0.1:9222/devtools/browser/<id>'\n# Short aliases also work:\nexport BU_CDP_WS='ws://...'\nexport BU_CDP_URL='http://127.0.0.1:9222'\n```\n\n## Selectors\n\nEvery action accepts three target styles — reach for whichever fits:\n\n| Style | Example | When |\n| --- | --- | --- |\n| **Ref** | `click @e3` | Default. Stable handles from `snapshot`/`observe`; ideal for LLM workflows. |\n| **CSS** | `click '#submit' --wait 5` | When you know the selector; `--wait` polls for it first. |\n| **Coordinates** | `click 100,200` | Canvas, maps, anything without a stable node. |\n\n`eval` IIFE-wraps a top-level `return`, so `eval 'const x = 1; return x'` works as written.\n\n## Commands\n\n### Observe\n\n```bash\nbrowser-control status\nbrowser-control doctor                         # endpoint, browser, launched pid, daemon, workspace\nbrowser-control page-info                       # url/title/readyState + viewport/scroll/page size\nbrowser-control snapshot [--json]               # `observe` is an alias\nbrowser-control text                            # visible text\nbrowser-control eval 'document.body.innerText'\nbrowser-control eval --frame iframe-url-substring 'document.title'\nbrowser-control events                          # recent DOM/lifecycle events\nbrowser-control network                         # recent requests\nbrowser-control console                         # recent console messages\nbrowser-control cdp Runtime.evaluate '{\"expression\":\"location.href\",\"returnByValue\":true}'\n```\n\n### Act\n\n```bash\nbrowser-control open https://example.com\nbrowser-control click @e3\nbrowser-control click '#submit' --wait 5        # poll up to 5s for the element first\nbrowser-control click 100,200                   # coordinates\nbrowser-control click '#row' --clicks 2         # double click; --button right|middle\nbrowser-control fill @e1 'hello@example.com'\nbrowser-control type 'hello'\nbrowser-control press Enter\nbrowser-control press ctrl+a                    # combos: alt/ctrl/meta(cmd)/shift\nbrowser-control press cmd+shift+t\nbrowser-control scroll -- -300 0                # window scroll\nbrowser-control scroll --at 640,400 -- 300 0    # wheel event at x,y (inner containers)\nbrowser-control select '#country' US\nbrowser-control drag 10,10 200,200\nbrowser-control upload '#file' ./a.pdf ./b.pdf\n```\n\n`press` maps editing combos (`ctrl/cmd` + a/c/x/v/z, `cmd+shift+z`) to renderer editing commands, so select-all and friends work headless and on macOS where the app menu would otherwise swallow them.\n\n### Wait\n\n```bash\nbrowser-control wait load 10\nbrowser-control wait networkidle 10\nbrowser-control wait-element '#ready' 10 --visible\n```\n\n### Browser & tabs\n\n```bash\nbrowser-control screenshot out.png\nbrowser-control screenshot full.png --full      # captureBeyondViewport\nbrowser-control pdf page.pdf\nbrowser-control tabs\nbrowser-control new-tab https://example.com\nbrowser-control switch-tab 1\nbrowser-control close-tab 1\nbrowser-control frames\nbrowser-control cookies\nbrowser-control viewport 1280 720\nbrowser-control download-path ./downloads\nbrowser-control dialog accept                   # daemon-backed, bounded by BROWSER_CONTROL_TIMEOUT\nbrowser-control stop                            # stop a browser launched by browser-control\nbrowser-control reload                          # minimal lifecycle reset\n```\n\n## Scripts & batch\n\n```bash\nbrowser-control run .browser-control/scripts/login.py\nprintf 'browser-control snapshot' | browser-control --from-stdin\n```\n\n`run` scripts receive `BROWSER_CONTROL_BIN` and `BROWSER_CONTROL_WORKSPACE`. Stdin execution is opt-in via `--from-stdin` — invoking `browser-control` with no subcommand and no flag is an error, so an empty or typo'd pipe can't silently `bash`-exec stdin.\n\n## Cloud browsers\n\nThe same commands drive a remote browser. Pick a provider with `BROWSER_CONTROL_CLOUD_PROVIDER` and `browser-control` speaks plain CDP to whatever session it gets back:\n\n```bash\nexport BROWSER_CONTROL_CLOUD_PROVIDER=steel\nexport STEEL_API_KEY=...\nbrowser-control cloud-start                 # provision a session, prints the CDP endpoint to export\nbrowser-control cloud-profiles              # list sessions/profiles\nbrowser-control cloud-stop <session-id>\n```\n\nBuilt-in presets, each reading its own key:\n\n| Provider | `BROWSER_CONTROL_CLOUD_PROVIDER` | API key env |\n| --- | --- | --- |\n| Browser Use *(default)* | `browser-use` | `BROWSER_USE_API_KEY` |\n| Steel | `steel` | `STEEL_API_KEY` |\n| Hyperbrowser | `hyperbrowser` | `HYPERBROWSER_API_KEY` |\n| Browserbase | `browserbase` | `BROWSERBASE_API_KEY` (+ `BROWSERBASE_PROJECT_ID`) |\n\n> **Any other provider works without a code change.** Override `BROWSER_CONTROL_CLOUD_API`, `BROWSER_CONTROL_CLOUD_API_KEY`, `BROWSER_CONTROL_CLOUD_AUTH_HEADER`, and the optional `BROWSER_CONTROL_CLOUD_{CREATE,LIST,STOP}_PATH` / `_STOP_METHOD` / `_CDP_FIELD`. `browser-control` only needs the response field that carries the CDP URL.\n\nLocal Chrome profiles can be reused or synced into a remote cloud profile:\n\n```bash\nbrowser-control local-profiles\nbrowser-control sync-profile \"Default\" --browser chrome\n``","default_branch":"main","files":167,"tree":[".github/workflows/release.yml",".gitignore","AGENTS.md","Cargo.lock","Cargo.toml","LICENSE","README.md","assets/hero.png","rust-toolchain.toml","scripts/verify.sh","skills/domain-skills/BOSS-zhipin/chat.md","skills/domain-skills/BOSS-zhipin/job-search.md","skills/domain-skills/BOSS-zhipin/navigation.md","skills/domain-skills/aa/checkout.md","skills/domain-skills/agentlist/discovery.md","skills/domain-skills/alaska/checkout.md","skills/domain-skills/allrecipes/recipe-extraction.md","skills/domain-skills/amazon/product-search.md","skills/domain-skills/amazon/retail-workflows.md","skills/domain-skills/apple/product-store-support.md","skills/domain-skills/apple/scraping.md","skills/domain-skills/archive-org/scraping.md","skills/domain-skills/articulate-rise/code-blocks.md","skills/domain-skills/arxiv-bulk/scraping.md","skills/domain-skills/arxiv/paper-search.md","skills/domain-skills/arxiv/scraping.md","skills/domain-skills/atlas/overview.md","skills/domain-skills/bbc-news/news-audio.md","skills/domain-skills/bigbang-hr/checkout.md","skills/domain-skills/bilibili/navigation.md","skills/domain-skills/booking-com/hotel-booking.md","skills/domain-skills/booking-com/scraping.md","skills/domain-skills/browser-use-cloud/cleanup-zombies.py","skills/domain-skills/browser-use-cloud/cloud.md","skills/domain-skills/cambridge-dictionary/dictionary-grammar.md","skills/domain-skills/capterra/scraping.md","skills/domain-skills/centilebrain/generate-estimates.md","skills/domain-skills/claude-ai/share-export.md","skills/domain-skills/coingecko/scraping.md","skills/domain-skills/coinmarketcap/scraping.md","skills/domain-skills/coursera/course-catalog.md","skills/domain-skills/coursera/scraping.md","skills/domain-skills/craigslist/scraping.md","skills/domain-skills/crossref/scraping.md","skills/domain-skills/ctrip/hotels.md","skills/domain-skills/dev-to/scraping.md","skills/domain-skills/duckduckgo/scraping.md","skills/domain-skills/ebay/scraping.md","skills/domain-skills/espn/sports-research.md","skills/domain-skills/etsy/scraping.md","skills/domain-skills/eventbrite/scraping.md","skills/domain-skills/expedia/automation.md","skills/domain-skills/facebook/groups.md","skills/domain-skills/facebook/pages.md","skills/domain-skills/flipkart/shopping.md","skills/domain-skills/framer/editor.md","skills/domain-skills/fred/scraping.md","skills/domain-skills/g2/scraping.md","skills/domain-skills/genius/scraping.md","skills/domain-skills/github/github-research.md","skills/domain-skills/github/repo-actions.md","skills/domain-skills/github/scraping.md","skills/domain-skills/glassdoor/scraping.md","skills/domain-skills/gmail/compose.md","skills/domain-skills/goodreads/scraping.md","skills/domain-skills/google-flights/flight-search.md","skills/domain-skills/google-flights/scraping.md","skills/domain-skills/google-maps/maps-reviews.md","skills/domain-skills/google-maps/scraping.md","skills/domain-skills/google-search/scraping.md","skills/domain-skills/google-search/source-verification.md","skills/domain-skills/gutenberg/scraping.md","skills/domain-skills/hackernews/scraping.md","skills/domain-skills/howlongtobeat/scraping.md","skills/domain-skills/hubspot/private-app-webhooks.md","skills/domain-skills/huggingface/model-hub.md","skills/domain-skills/imdb/scraping.md","skills/domain-skills/itch-io/scraping.md","skills/domain-skills/job-boards/indeed-glassdoor.md","skills/domain-skills/letterboxd/scraping.md","skills/domain-skills/linkedin/invitation-manager.md","skills/domain-skills/loom/folder-enumeration.md","skills/domain-skills/ly-com/hotels.md","skills/domain-skills/macrotrends/scraping.md","skills/domain-skills/manus/tasks.md","skills/domain-skills/medium/article-hydration.md","skills/domain-skills/medium/scraping.md","skills/domain-skills/metacritic/scraping.md","skills/domain-skills/musicbrainz/scraping.md","skills/domain-skills/nasa/scraping.md","skills/domain-skills/news-aggregation/multi-source.md","skills/domain-skills/open-library/scraping.md","skills/domain-skills/openalex/scraping.md","skills/domain-skills/openstreetmap/scraping.md","skills/domain-skills/package-registries/npm-pypi.md","skills/domain-skills/perplexity/computer.md","skills/domain-skills/polymarket/scraping.md","skills/domain-skills/producthunt/scraping.md","skills/domain-skills/pubmed/scraping.md","skills/domain-skills/qbo/report-export.md","skills/domain-skills/quora/scraping.md","skills/domain-skills/rawg/scraping.md","skills/domain-skills/reddit/scraping.md","skills/domain-skills/rest-countries/scraping.md","skills/domain-skills/salesforce/.gitkeep","skills/domain-skills/sec-edgar/scraping.md","skills/domain-skills/shopify-admin/README.md","skills/domain-skills/shopify-admin/embedded-apps.md","skills/domain-skills/shopify-admin/knowledge-base.md","skills/domain-skills/shopify-admin/polaris-inputs.md","skills/domain-skills/soundcloud/scraping.md","skills/domain-skills/spotify/scraping.md","skills/domain-skills/spreadshirt/.gitkeep","skills/domain-skills/stackoverflow/scraping.md","skills/domain-skills/steam/scraping.md","skills/domain-skills/substack/scraping.md","skills/domain-skills/tasksquad-ai/agents.md","skills/domain-skills/tasksquad-ai/auth.md","skills/domain-skills/tasksquad-ai/tasks.md","skills/domain-skills/thetechgeeks/pricing.md","skills/domain-skills/tiktok/upload.md","skills/domain-skills/tradingview/scraping.md","skills/domain-skills/trello/boards-and-lists.md","skills/domain-skills/trustpilot/scraping.md","skills/domain-skills/vercel/vercel.md","skills/domain-skills/walmart/scraping.md","skills/domain-skills/wayback-machine/scraping.md","skills/domain-skills/weather/scraping.md","skills/domain-skills/wehotel/hotels.md","skills/domain-skills/wellfound/scraping.md","skills/domain-skills/weread/read.md","skills/domain-skills/wolfram-alpha/computation-results.md","skills/domain-skills/world-bank/scraping.md","skills/domain-skills/x/posting.md","skills/domain-skills/xiaohongshu/scraping.md","skills/domain-skills/youtube/scraping.md","skills/domain-skills/zillow/scraping.md","skills/interaction-skills/connection.md","skills/interaction-skills/cookies.md","skills/interaction-skills/cross-origin-iframes.md","skills/interaction-skills/dialogs.md","skills/interaction-skills/downloads.md","skills/interaction-skills/drag-and-drop.md","skills/interaction-skills/dropdowns.md","skills/interaction-skills/evidence-page.md","skills/interaction-skills/final-answer.md","skills/interaction-skills/freshness.md","skills/interaction-skills/iframes.md","skills/interaction-skills/network-requests.md","skills/interaction-skills/print-as-pdf.md","skills/interaction-skills/profile-sync.md","skills/interaction-skills/screenshots.md","skills/interaction-skills/scrolling.md","skills/interaction-skills/shadow-dom.md","skills/interaction-skills/tabs.md","skills/interaction-skills/uploads.md","skills/interaction-skills/viewport.md","src/actions.rs","src/cdp.rs","src/cloud.rs","src/daemon.rs","src/js.rs","src/lifecycle.rs","src/main.rs","src/output.rs","src/workspace.rs","tests/run_claude_browser_control.py"],"storefront":"/r/keon","claimed":false,"request_supported":{"post":"https://gitbuyer.com/r/keon/browser-control/request-supported","requests":0},"note":"indexed from public GitHub; nothing is for sale on this page. Clone it from GitHub. Paid listings live at /search."}