{"id":51919362,"url":"https://github.com/skyvern-ai/rustwright","last_synced_at":"2026-07-27T16:01:33.013Z","repository":{"id":371352042,"uuid":"1292544026","full_name":"Skyvern-AI/rustwright","owner":"Skyvern-AI","description":"Playwright's API on a Rust CDP engine — Chromium browser automation for Python \u0026 Node, no driver subprocess. (Alpha)","archived":false,"fork":false,"pushed_at":"2026-07-21T16:46:24.000Z","size":12932,"stargazers_count":758,"open_issues_count":20,"forks_count":42,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-07-21T18:26:14.038Z","etag":null,"topics":["browser-automation","cdp","chrome-devtools-protocol","chromium","napi-rs","nodejs","playwright","pyo3","python","rust"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Skyvern-AI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-07T16:00:40.000Z","updated_at":"2026-07-21T17:31:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Skyvern-AI/rustwright","commit_stats":null,"previous_names":["skyvern-ai/rustwright"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Skyvern-AI/rustwright","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyvern-AI%2Frustwright","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyvern-AI%2Frustwright/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyvern-AI%2Frustwright/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyvern-AI%2Frustwright/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Skyvern-AI","download_url":"https://codeload.github.com/Skyvern-AI/rustwright/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyvern-AI%2Frustwright/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35956857,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-27T02:00:06.776Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser-automation","cdp","chrome-devtools-protocol","chromium","napi-rs","nodejs","playwright","pyo3","python","rust"],"created_at":"2026-07-27T16:01:32.154Z","updated_at":"2026-07-27T16:01:32.988Z","avatar_url":"https://github.com/Skyvern-AI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"docs/assets/banner.png\" alt=\"Rustwright — a drop-in replacement for Playwright\" width=\"840\" /\u003e\n\n**A Rust rewrite of Playwright**, a popular browser automation library. Rustwright is interoperable with Playwright but runs on an in-process Rust CDP engine — **[2.55× faster](#benchmarks)** and **[70% less memory](BENCHMARK.md#client-memory-form-fill-diagnostic)** (no Node driver), with no Playwright automation fingerprint. Alpha; Chromium-only.\n\n[![status: alpha](https://img.shields.io/badge/status-alpha-orange)](#project-status)\n[![tests](https://img.shields.io/github/actions/workflow/status/Skyvern-AI/rustwright/test.yml?label=tests)](https://github.com/Skyvern-AI/rustwright/actions/workflows/test.yml)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)\n[![Python 3.8+](https://img.shields.io/badge/python-3.8%2B-3776AB?logo=python\u0026logoColor=white)](pyproject.toml)\n[![npm](https://img.shields.io/npm/v/rustwright?logo=npm\u0026label=npm)](https://www.npmjs.com/package/rustwright)\n[![Chromium only](https://img.shields.io/badge/browser-Chromium-4285F4?logo=googlechrome\u0026logoColor=white)](#limitations)\n[![Discord](https://img.shields.io/badge/Discord-join-5865F2?logo=discord\u0026logoColor=white)](https://discord.gg/fG2XXEuQX3)\n\n\u003c/div\u003e\n\n---\n\n## What is Rustwright?\n\nRustwright is a browser automation library for Python and Node.js that keeps the Playwright API you already know but drives Chromium from a **native Rust engine** speaking raw [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) — no driver subprocess in the path.\n\n```text\nplaywright-python:  your code ──pipe──► Node driver ──CDP──► Chromium\nrustwright:         your code ────────── raw CDP ──────────► Chromium\n```\n\n## Quickstart\n\nRustwright is interoperable with Playwright — install it, change one import, and your existing code runs on the Rust engine.\n\n**Python**\n\n```bash\npip install rustwright\npython -m rustwright install chromium\n```\n\n```diff\n- from playwright.sync_api import sync_playwright\n+ from rustwright.sync_api import sync_playwright\n\n  with sync_playwright() as p:\n      browser = p.chromium.launch(headless=True)\n      page = browser.new_page()\n      page.goto(\"https://example.com\")\n      print(page.title())\n      browser.close()\n```\n\n**Node.js** (experimental)\n\nInstall from npm:\n\n```bash\nnpm install rustwright\n```\n\nThe Node binding drives an existing Chromium/Chrome — point Rustwright at it with `RUSTWRIGHT_CHROMIUM`, `CHROME`, or `CHROMIUM`. Prefer to build from source? `git clone` the repo and run `npm install \u0026\u0026 npm run build` in `node/`.\n\n```diff\n- import { chromium } from 'playwright';\n+ import { chromium } from 'rustwright';\n\n  const browser = await chromium.launch();\n  const page = await browser.newPage();\n  await page.goto('https://example.com');\n  console.log(await page.title());\n  await browser.close();\n```\n\nSee the network-independent [`examples/quickstart.js`](examples/quickstart.js) example. After building the Node binding from source, run it from the repository root with `node examples/quickstart.js`.\n\nOnly a subset of the API surface is bridged — see [Limitations](#limitations).\n\n**CLI** (agent-focused)\n\nInstall the native `rustwright-cli` with one command:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Skyvern-AI/rustwright/main/install.sh | sh\n```\n\nThen drive a persistent Chromium session from your shell or an agent loop:\n\n```bash\nrustwright-cli open https://example.com\nrustwright-cli snapshot          # compact page tree with @eN refs\nrustwright-cli click @e1\nrustwright-cli close\n```\n\nSee [`cli/README.md`](cli/README.md) for the full command surface. For a Model Context Protocol\nserver, use the standalone [`rustwright-mcp`](mcp-rs/) package.\n\n## Why Rustwright?\n\n\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"docs/assets/rustwright_vs_playwright.gif\" alt=\"Rustwright vs playwright-python live demo\" width=\"360\" /\u003e\n\n\u003c/div\u003e\n\n- **No Node driver subprocess.** `playwright-python` launches and pipes to a bundled Node driver. Rustwright's engine is native — the browser-control code runs in-process.\n- **Raw CDP, in Rust.** A from-scratch async CDP client — not a wrapper around another automation library.\n- **No Playwright automation fingerprint.** The driver never loads, so its signatures never appear. See [Automation detection](#automation-detection).\n- **Trusted input by default.** Clicks and typing go through real CDP input events (`Input.dispatchMouseEvent`), not synthetic `element.click()` DOM calls. Untrusted DOM shortcuts are opt-in only.\n- **Cross-origin iframes (OOPIF).** Auto-attaches out-of-process iframe targets with flattened CDP sessions and routes `frame_locator()` across origins.\n- **One engine, two languages.** The same Rust core backs the Python and Node bindings.\n\n## How it works\n\nOne Rust core — an async CDP client built on Tokio (WebSocket, with opt-in Unix-pipe transport) — talks to Chromium directly, and thin [PyO3](https://pyo3.rs) (Python) and [napi-rs](https://napi.rs) (Node) bindings expose it in-process. The two-line diagram above is the entire architecture.\n\nAlready have a Chromium/Chrome binary? Point Rustwright at it with `RUSTWRIGHT_CHROMIUM`, `CHROME`, or `CHROMIUM`.\n\n## Browser automation for AI agents\n\nGive an agent or shell script a browser through compact accessibility snapshots with element refs (`e1`, `e2`, …), instead of raw HTML or screenshots. Refs are session-scoped, never reused, and best-effort rather than a security boundary; snapshots include page values but mask password fields.\n\n### MCP server — give your agent a browser\n\n`rustwright-mcp` is a native Rust MCP server (no Python or Node runtime in the\nserving path) that gives any MCP client `browser_*` tools over stdio, with\ncompact accessibility snapshots and inline PNG screenshots. It lives in\n[`mcp-rs/`](mcp-rs/) and is the canonical Rustwright MCP server.\n\n#### Install\n\nFrom source (needs a Rust toolchain):\n\n```bash\ncargo install --git https://github.com/Skyvern-AI/rustwright rustwright-mcp\n```\n\nThis installs the server binary as `rustwright-mcp`. An npm package (`rustwright-mcp`,\nprebuilt binaries via `npx rustwright-mcp`) is on the way.\n\nIf Chrome or Chromium is already installed, point Rustwright at it with\n`RUSTWRIGHT_CHROMIUM` (or `CHROME` / `CHROMIUM`). Otherwise download one with\n`pip install rustwright \u0026\u0026 python -m rustwright install chromium`.\n\n#### Fastest path\n\n##### Claude Code\n\n```bash\nclaude mcp add rustwright -- mcp-rs\n```\n\n##### Claude Desktop\n\nOpen `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS or `%APPDATA%\\Claude\\claude_desktop_config.json` on Windows, then use:\n\n```json\n{\n  \"mcpServers\": {\n    \"rustwright\": {\n      \"command\": \"rustwright-mcp\"\n    }\n  }\n}\n```\n\n##### Any MCP client\n\n```json\n{\n  \"mcpServers\": {\n    \"rustwright\": {\n      \"command\": \"rustwright-mcp\"\n    }\n  }\n}\n```\n\n| If... | Do this |\n|---|---|\n| You already have Chrome/Chromium | Set `RUSTWRIGHT_CHROMIUM` (or `CHROME` / `CHROMIUM`) to its executable in the server's `env`. |\n| You do not have a browser installed | `pip install rustwright \u0026\u0026 python -m rustwright install chromium` — the server finds the downloaded browser automatically. |\n| Screenshots are too large to inline | Tune `RUSTWRIGHT_MCP_SCREENSHOT_MAX_BYTES`; oversized captures fall back to a temp-file path instead of inline image content. |\n\nSee [`mcp-rs/README.md`](mcp-rs/README.md) for the full tool list and\nconfiguration. Setting up via an AI agent? Tell it to fetch\n`https://raw.githubusercontent.com/Skyvern-AI/rustwright/HEAD/mcp-rs/README.md`\nand follow it.\n\n\u003e The earlier Python MCP server is deprecated: it stays in place until the\n\u003e native server reaches full tool parity, but new capabilities land in\n\u003e `mcp-rs/` only.\n\n### CLI — drive a browser from your shell\n\nDrive one persistent Chromium session straight from the `rustwright` command, with no application code.\n\n#### Try it in 60 seconds\n\n```bash\npip install rustwright\npython -m rustwright install chromium\n\nrustwright open example.com\nrustwright snapshot\nrustwright click e1001\nrustwright close\n```\n\n- `snapshot` shows refs; act by ref, then use the fresh snapshot returned after the action.\n- Add `--json` for one JSON object per command when scripting.\n- Use `--session NAME` for named browser sessions.\n\nSee [the agent interface guide](docs/agent-interfaces.md) for every verb, flag, and security detail.\n\n## Remote browsers (Skyvern)\n\nRustwright drives browsers — but you still need somewhere to run them. Skyvern (the team behind Rustwright) offers hosted **[Browser Sessions](https://www.skyvern.com/docs/developers/features/browser-sessions)** as a paid service that funds this project.\n\n**Features:**\n\n- **Persistent cloud browsers** — logins, cookies, and tab state carry across runs\n- **Configurable timeouts** — 5 minutes to 24 hours (60 min default)\n- **Proxies in 21 countries**\n- **Live view** — watch and interact with the session in the Skyvern Cloud UI\n\nEach session returns a `browser_address` CDP endpoint that Rustwright connects to like any remote Chromium (sessions bill while open).\n\n**Get started:**\n\n1. Make an account at [app.skyvern.com](https://app.skyvern.com)\n2. Grab your API key from **Settings**\n3. `pip install skyvern`\n\n```python\nimport asyncio\nfrom rustwright.async_api import async_playwright\nfrom skyvern import Skyvern\n\nasync def main():\n    session = await Skyvern(api_key=\"\u003cSKYVERN_API_KEY\u003e\").create_browser_session()\n\n    async with async_playwright() as p:\n        browser = await p.chromium.connect_over_cdp(session.browser_address)\n        page = await browser.new_page()\n        await page.goto(\"https://example.com\")\n\nasyncio.run(main())\n```\n\n\u003e Remote sessions are Python-only for now — Rustwright's Node binding doesn't support `connect_over_cdp` yet (it's on the [Roadmap](#roadmap)).\n\n## Automation detection\n\nBecause Rustwright never loads Playwright's Node driver, it never emits the automation signatures that ship with it:\n\n- **No Playwright driver signatures** — no `__playwright__binding__` / utility-world globals, no driver bootstrap. The backend reports `playwright_driver: \"none\"`.\n- **No `Runtime.enable` on the default path** — a normal launch + navigate never enables the CDP Runtime domain, closing the `Runtime.enable` console-serialization leak behind `isAutomatedWithCDP`. (Console/page-error/binding opt-ins still enable it lazily — detectable by design.)\n- **Headless identity normalized by default** — launches with `--disable-blink-features=AutomationControlled`, rewrites `HeadlessChrome/` → `Chrome/` in the UA and client hints, and installs a `navigator.webdriver` cleanup init script.\n\nLocal fingerprint runs — default Playwright failed webdriver/headless checks that Rustwright passed; these are local diagnostics, not a guarantee:\n\n| Probe | Result |\n|---|---|\n| SannySoft | ✅ Clean |\n| BrowserScan | ✅ Clean |\n| DeviceAndBrowserInfo | ✅ Clean (after the Runtime-domain cleanup) |\n| CreepJS | ⚠️ Detects headless |\n\n\u003e [!IMPORTANT]\n\u003e **Rustwright is not \"undetectable.\"** It is not a CAPTCHA or Cloudflare bypass, and it is not fully CDP-invisible — it still uses CDP primitives (`Target.setAutoAttach`, init scripts, and lazy `Runtime.enable` for console event/pageerror event/binding opt-ins). The claim is narrow: **no Playwright-specific automation fingerprint**, plus baseline signal hygiene.\n\n## Benchmarks\n\nThe headline numbers are local diagnostics, not yet capped-CI evidence. On speed, one dev-host run (warm browser, 5 iterations) won 16 of 17 case means:\n\n| Run | Cases | Rustwright | playwright-python | Speedup |\n|---|---:|---:|---:|---:|\n| Local dev host (warm browser, 5 iterations) | 17 | 5,256 ms | 13,418 ms | **[2.55×](BENCHMARK.md#local-diagnostic-trusted-input-default)** |\n\nTreat it as a diagnostic, not a launch claim — it is not capped-Docker/CI evidence. Methodology: [`BENCHMARK.md`](BENCHMARK.md).\n\nOn memory, a [form-fill diagnostic](BENCHMARK.md#client-memory-form-fill-diagnostic) recorded the client library's footprint at **133.5 MiB for playwright-python (Python + Node driver) versus 40.6 MiB for Rustwright (no driver) — about 70% less**; a separate [async-concurrency diagnostic](docs/async-design.md#update-high-concurrency-fixes-2026-07) measured ~66% less on the same client-stack basis. Both cover the part the library controls — Chromium-dominated whole-process memory is roughly equal — and both are demo-grade diagnostics, not capped-CI evidence.\n\n## Alternatives\n\n| | Rustwright | playwright-python | Puppeteer | Patchright |\n|---|---|---|---|---|\n| **API** | Playwright-shaped (Py + Node) | Official Python Playwright | JS/TS Puppeteer | Playwright drop-in fork |\n| **Engine / transport** | Rust core, raw CDP | Python → Node driver | Node over CDP | Patched PW driver |\n| **In-process engine (no driver subprocess)** | ✅ | ❌ bundled Node driver | ✅ Node is the runtime | ❌ Playwright-style driver |\n| **Browsers** | Chromium only | Chromium, Firefox, WebKit | Chrome, Firefox | Chromium-based |\n| **Default input** | Trusted CDP events | Browser-level | Browser / CDP | Playwright + stealth |\n| **Cross-origin iframes** | OOPIF (alpha) | Mature | Frame APIs | Inherits Playwright |\n| **Playwright fingerprint** | No | Yes | n/a | Patched |\n| **Maturity** | 🟠 Alpha | 🟢 Mature | 🟢 Mature | 🟡 Focused fork |\n\nRustwright's lane: **a Rust CDP engine under the Playwright API, for Chromium.**\n\n## Limitations\n\nSee [`LIMITATIONS.md`](LIMITATIONS.md) for detail.\n\n- **Alpha** — API shape covered; full **behavioral** parity not yet proven.\n- **API coverage** — ~96% of Playwright's Python sync API (**515 of 536** methods; **411** exercised by the shared parity registry); the async API provides **488 of 536**. Full report: [`docs/PARITY.md`](docs/PARITY.md).\n- **Chromium only** — Firefox and WebKit error explicitly.\n- **Node bindings are early** — a subset of the surface is bridged (`launch`, `newPage`, `goto`, `click`, `fill`, `title`, `textContent`, `evaluate`, `screenshot`, `close`); contexts, routing, tracing, and locators are Python-only for now.\n- **Async concurrency (Python)** — the async API wraps the sync engine via threads; recommended for **≈≤25 concurrent workflows/process**, not high fan-out.\n- **OOPIF** — residual gaps in non-main-frame `JSHandle` follow-ups and drag/screenshot/bounding-box.\n- **Automation detection is partial** — 3 of 4 public fingerprint targets clean in local runs (CreepJS still detects headless). **No undetectability promise.**\n\n## Roadmap\n\n- [ ] **Kotlin binding** — idiomatic Kotlin wrapper (Kotlin/JVM can already consume the Java FFM binding)\n- [ ] Grow the new language bindings beyond the alpha subset (contexts, routing, locators)\n- [x] **Rustwright MCP server** — expose browser automation as tools for MCP-compatible AI agents ([mcp/](mcp/))\n- [ ] CI / Testbox-backed benchmark evidence\n- [ ] Broaden the Node.js surface (contexts, routing, locators)\n- [ ] Close remaining OOPIF gaps\n\nRecently shipped:\n\n- [x] **Language bindings (alpha)** — Go, Java, C#/.NET, Ruby, and PHP over a shared C ABI, plus a native Rust API ([`bindings/CONTRACT.md`](bindings/CONTRACT.md)); cross-language equivalence gated in CI\n- [x] Python package published to PyPI\n- [x] Node.js binding published to npm\n- [x] Native async engine over the Tokio CDP core\n- [x] OOPIF auto-attach with flattened CDP sessions\n- [x] 515/515 shared parity suite green against real Playwright\n- [x] `Runtime.enable` console-serialization leak closed on the default path\n\nFirefox and WebKit are **not planned** — Rustwright is deliberately Chromium-only.\n\n## Contributing\n\nRustwright is Rust + Python + Node. `cargo` builds the engine; `maturin develop --release` installs the Python package; `cd node \u0026\u0026 npm run build` builds the Node addon; the Python suite exercises the engine against real Chromium. Full Docker gate: **1,046 tests pass** (6 skipped), plus **515/515** shared parity cases run against real Playwright; CI (`test.yml`) runs a fast representative subset on every PR.\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md) for build details and the code-layout reality.\n\n## Project status\n\nRustwright is an early alpha from [Skyvern](https://github.com/Skyvern-AI), developed in the open. If the architecture resonates, [give it a ⭐](https://github.com/Skyvern-AI/rustwright).\n\nQuestions, ideas, or want to help? Join the Skyvern community on [**Discord**](https://discord.gg/fG2XXEuQX3).\n\n## License\n\n[MIT](LICENSE) © 2026 Ikonomos Inc (dba Skyvern)\n\n\u003cdiv align=\"center\"\u003e\n\u003csub\u003eBuilt with 🦀🐉 and a lot of CDP frames · \u003ca href=\"https://github.com/Skyvern-AI/rustwright\"\u003eSkyvern-AI/rustwright\u003c/a\u003e\u003c/sub\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyvern-ai%2Frustwright","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskyvern-ai%2Frustwright","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyvern-ai%2Frustwright/lists"}