A small, Chromium-first automation library for Rust workloads that need a real browser and explicit control over its resources.
Lightwright is built for scrapers, agents, CI jobs, internal automation, and long-lived workers. It speaks Chrome DevTools Protocol directly, keeps the core Rust-native, and makes browser memory, resource loading, and lifecycle decisions visible in your code.
Playwright-style, not Playwright-compatible. Lightwright is an alpha with a deliberately smaller API surface - not a drop-in replacement for Playwright.
- Lean Rust controller. Drive a real Chromium browser without a Node runtime in your automation path; the measured controller footprint is 28 MiB.
- Smaller controller footprint. In the current local runs, Lightwright used 3.5x to 4.1x less controller memory than Playwright.
- Fast simple navigation average. On the aligned cold-page run, Lightwright averaged 170 ms versus Playwright's 197 ms. Read the p95 before treating that as a general win.
- Measured multi-context progress. Lazy CDP initialization cut Lightwright's own two-context/four-page average from 934 ms to 672 ms in repeated local runs.
- Isolated contexts. Cookies and web storage stay scoped to their
BrowserContext. - Explicit resource control. Choose memory modes, block resource classes, and enforce browser-tree memory budgets.
- Small operational surface. Launch, pages, contexts, locators, screenshots, storage, and a practical CLI.
- Measured, reproducible benchmarks. Timing and memory runs are separate, use the same browser executable, and report variability.
| KPI | Lightwright | Reference | What it shows |
|---|---|---|---|
| Controller memory, simple page | 28 MiB | Playwright: 116 MiB | 4.1x smaller controller footprint in this local pass |
| Controller memory, 2 contexts / 4 pages | 28 MiB | Playwright: 98 MiB | 3.5x smaller controller footprint in this local pass |
| Simple cold navigation average | 170 ms | Playwright: 197 ms | 14% lower average; p95 remains less stable |
| Multi-context navigation, before/after | 934 -> 672 ms | Lightwright baseline | 28% lower after lazy CDP initialization |
These are controlled local measurements with Chrome for Testing 149.0.7827.55, not universal performance guarantees. Lightwright does not currently win on Chromium-tree memory, multi-context absolute latency, or reused-browser latency.
cargo fmt --all -- --check
cargo test
cargo run -p lightwright-cli -- open `
"data:text/html,<title>Lightwright</title><h1>Hello</h1>" `
--memory ultra-lowuse lightwright_core::{Browser, LaunchOptions, MemoryMode};
#[tokio::main]
async fn main() -> lightwright_core::Result<()> {
let browser = Browser::launch(
LaunchOptions::new()
.memory_mode(MemoryMode::UltraLow)
.max_memory_mb(350),
)
.await?;
let page = browser.new_page().await?;
page.goto("data:text/html,<title>LW</title><h1>Hello</h1>")
.await?;
println!("{}", page.title().await?);
browser.close().await
}| Area | Included in v0.1.0-alpha.1 |
|---|---|
| Browser lifecycle | Chrome, Edge, and Chromium detection on Windows; executable override; headless launch; temporary profiles |
| Automation | Browser, isolated BrowserContext, Page, locators, navigation, evaluation, actions, screenshots, cookies, and storage |
| CDP | Sessions, request IDs, events, response correlation, timeouts, and safe concurrent commands |
| Resource control | Memory modes, resource profiles, explicit URL/resource blocking, headers, viewport, and user-agent overrides |
| Operations | Browser-process-tree memory measurement, budget actions, local fixtures, benchmark harness, and CLI |
Still out of scope: Firefox, WebKit, Playwright compatibility, a test runner, video/tracing, and native Node bindings. The Node package is a private type-shape preview only.
The following local measurements use Chrome for Testing 149.0.7827.55 (Playwright Chromium 1228), headless mode, a 1280x720 viewport, and the same data: page. Timing runs have no memory sampler. Lower is better.
xychart-beta
title "Average navigation time (ms) - lower is better"
x-axis ["Simple cold", "2 contexts / 4 pages", "Simple reuse"]
y-axis "Milliseconds" 0 --> 1000
bar "Lightwright" [170, 672, 151]
bar "Playwright" [197, 380, 108]
| Scenario | Lightwright | Playwright | Notes |
|---|---|---|---|
| Simple page, cold browser | 170 ms navigation | 197 ms navigation | 20 measured runs each; Lightwright had a wider p95 in this pass |
| Two contexts, four pages, cold browser | 672 ms navigation | 380 ms navigation | 20 measured runs each; isolated-context creation remains the main gap |
| Simple page, reused browser | 151 ms navigation | 108 ms navigation | 100 measured runs each |
Lightwright now initializes Network only when a page needs headers, user-agent overrides, cookies, cache actions, or resource blocking. In the multi-context workload this reduced average navigation from 934 ms to 672 ms in a repeated 20-run local comparison. Results are machine-specific measurements, not performance guarantees.
Memory is measured in a separate five-run pass after navigation. It includes the launched Chromium root process and all of its descendants; controller memory is deliberately reported separately.
xychart-beta
title "Chromium browser-tree memory after navigation (MiB)"
x-axis ["Simple page", "2 contexts / 4 pages"]
y-axis "MiB" 0 --> 750
bar "Lightwright" [455, 675]
bar "Playwright" [349, 525]
| Scenario | Lightwright controller | Lightwright Chromium tree | Playwright controller | Playwright Chromium tree |
|---|---|---|---|---|
| Simple page | 28 MiB | 455 MiB | 116 MiB | 349 MiB |
| Two contexts, four pages | 28 MiB | 675 MiB | 98 MiB | 525 MiB |
The controller is materially smaller, while Chromium itself is still larger than Playwright's in these workloads. See the viability report for protocol details, history, and limitations.
Choose a memory mode for the browser process:
| Mode | Intended use |
|---|---|
default |
Safe Chromium defaults |
low |
Reduce background work while retaining normal browser behavior |
ultra-low |
Prefer minimal browser footprint; disables GPU and image loading |
agent |
Agent-oriented defaults that preserve screenshots and accessibility work |
scraper |
Extraction-oriented defaults |
test |
Closer to ordinary Chromium behavior |
Add a resource profile when the workload does not need every asset:
cargo run -p lightwright-cli -- inspect "data:text/html,<title>LW</title><h1>Hello</h1>" `
--memory ultra-low `
--profile text-only `
--max-memory-mb 350 `
--on-memory-pressure close-idle-pagesAvailable profiles: default, low, ultra-low, scraper, agent, form, visual, and text-only.
Useful CLI options:
--memory default|low|ultra-low|agent|scraper|test
--profile default|low|ultra-low|scraper|agent|form|visual|text-only
--headless true|false
--browser-path <path>
--viewport 1280x720
--user-agent "..."
--header "Name: Value"
--block image,font,media,stylesheet
--max-memory-mb <mb>
--on-memory-pressure warn|clear-cache|close-idle-pages|fail-fast
Browser::new_context(...).await maps to Chromium's isolated browser contexts. Cookies and web storage do not cross context boundaries; closing a context closes its pages and disposes its Chromium context.
Browser::memory_usage() reports resident memory for the Chromium root process and its descendants. For a remote browser, it returns None because Lightwright does not own that process tree. When a configured budget is exceeded, enforce_memory_budget() can warn, clear the browser cache, close idle pages, or fail fast.
Use the same local fixture, browser executable, headless mode, viewport, workload, warmups, and run count for both tools. Run timing and memory separately.
# Terminal 1: local fixture server
cargo run -p lightwright-cli -- fixture-server --port 0
# Terminal 2: Lightwright timing pass
cargo run -p lightwright-bench -- `
--url "http://127.0.0.1:PORT/simple" `
--browser-path "C:\\path\\to\\chrome.exe" `
--runs 20 --warmup-runs 3 `
--pages 2 --contexts 2 --concurrency 4 `
--viewport 1280x720 `
--measure-memory false --json
# Separate memory pass
cargo run -p lightwright-bench -- `
--url "http://127.0.0.1:PORT/simple" `
--browser-path "C:\\path\\to\\chrome.exe" `
--runs 5 --warmup-runs 1 `
--pages 2 --contexts 2 --concurrency 4 `
--viewport 1280x720 `
--measure-memory true --jsonFor the matching Playwright harness and the full comparison rules, see Benchmark comparison and Benchmarks.