CLI tool
lexmount/moli avatar
lexmount/moli

Moli: a Rust headless browser that skips rendering until an agent asks for pixels

Best headless browser for AI agents. Lite, Fast, High-Compatibility. Built in Rust

1,991 stars137 forksRustApache-2.0

At a glance

What is it?
Moli is an Apache-2.0 headless browser from lexmount built around on-demand layout and paint. It targets AI agents and crawlers that mostly need DOM structure, and it pays for visual work only when a request needs geometry or a screenshot.
Who is it for?
Adopt Moli if your workload is DOM-first: extraction, crawling, retrieval, browser-use agents, or evaluation harnesses where most requests never need a rendered frame. Do not adopt it if you depend on a specific Chromium rendering quirk, on browser extensions, or on a protocol or CLI flag that its documentation does not yet list.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Moli targets: agents that pay for rendering they never read

Most browser automation for agents ends in text. The agent wants the page's structure, its DOM, its network activity, or the result of a script, and it rarely wants a picture. A conventional headless browser still carries a rendering pipeline that keeps a visual state alive, and that state is maintained whether or not anyone looks at it. Moli's premise, stated in its README, is that what most automation tasks need is page structure, not a continuously rendered visual world. The project treats the native DOM and style state as the single source of truth and triggers layout or software paint only for operations that genuinely require them. The intended audience is narrow and named in the README: crawling, browser-use agents, retrieval pipelines, evaluation environments, and reinforcement-learning workloads. If you are building a screenshot service or a visual regression suite, you are not the target, and the cost model works against you.

On-demand layout and paint: what actually runs per request

The mechanism is a cost model rather than a missing feature set. Moli includes V8, CSS, layout, text shaping, hit-testing, and software paint; the README's phrasing is that the only difference is when visual work runs and how long its results are retained. The README gives a per-request table. Extracting HTML or Markdown, querying the DOM, running JavaScript, and inspecting network or storage read browser runtime state directly and do not trigger layout or paint. Reading an element's box, hit-testing coordinates, or sending coordinate input runs one layout calculation and keeps only the latest frozen layout tree. A screenshot rebuilds from the current DOM and style, replaces the frozen tree, renders a fresh frame, and discards its paint state after use. Polling a screencast compares generation metadata only; clean state emits no frame, while changed state rebuilds and emits one fresh frame. That last row is the interesting design decision, because it means screencast polling is cheap when nothing changed and expensive only when something did. The trade-off is that a screenshot is always a rebuild, so repeated captures of an unchanged page do not get cheaper the way they might in a browser that caches composited output.

One binary, three automation protocols, and a CLI that dumps trees

Moli ships as a unified automation binary. The README states that the same endpoint serves CDP, WebDriver Classic, and WebDriver BiDi, and that Playwright can connect directly over CDP. The documented Playwright example uses `chromium.connectOverCDP("http://127.0.0.1:9222")`, takes the first context and page, navigates, and reads `page.locator("body").innerText()`. That is a deliberate compatibility choice: instead of writing a Playwright driver, Moli exposes the CDP endpoint Playwright already knows how to attach to. On the extraction side, the CLI produces HTML, Markdown, JSON, semantic text trees, and frame-aware serialization, with selector, script, and response waits plus network tracing. The runtime underneath covers streaming HTML parsing, native DOM, V8 with modules, timers, microtasks and events, iframes and workers, the CSS cascade, Fetch/XHR/WebSocket, cookies, WebCrypto, and profile-scoped storage for localStorage, IndexedDB, and OPFS. The README also says Moli supports Linux, macOS, and Windows. Note that the excerpt here is truncated mid-sentence in the capabilities list, so treat the protocol and feature enumeration as the documented subset rather than a complete inventory.

Getting it running: installer, fetch flags, and serve modes

The README offers two installation paths. The agent-oriented one is a prompt: install the skills under `https://github.com/lexmount/moli/tree/main/skills`, follow their instructions to download and install the latest prebuilt binary, then use `moli-webfetch` to fetch a URL. The direct path on Linux or macOS is `curl --proto '=https' --tlsv1.2 -fsSL https://github.com/lexmount/moli/releases/latest/download/moli-installer.sh | sh`, and on Windows it is `powershell -ExecutionPolicy ByPass -c "irm https://github.com/lexmount/moli/releases/latest/download/moli-installer.ps1 | iex"`. Piping a remote script into a shell is the usual supply-chain trade; the README does not document checksum verification, so pinning a release version rather than `latest` is the only lever it gives you. For extraction, `moli fetch --dump markdown --wait-until done https://example.com` returns Markdown under the default completion strategy, and `moli fetch --dump semantic_tree_text --wait-selector body https://example.com` returns a compact semantic tree. Visual output requires an explicit flag: `moli fetch --layout --dump screenshot https://example.com > page.png`, with `screenshot_full` and `pdf` as the other documented dump values. For automation, `moli serve` starts a DOM-first server, `moli serve --layout` enables real geometry, coordinate input, and screenshot and screencast surfaces, and `moli serve --layout --resource` additionally fetches optional image, font, audio, video, media, and text-track resources. The README points to `fetch --help` for the full option list covering output formats, waits, profiles, proxy settings, resource policies, and tracing.

The rendering gap is the limitation, not a footnote

Moli's paint path is software paint. The README lists it among the included capabilities and describes screenshots as rebuilding from the current DOM and style and rendering a fresh frame. Nothing in the supplied material mentions GPU compositing, and the on-demand model means visual state is not continuously maintained. For a pipeline that captures one screenshot per page, that is fine. For a workload that needs frame-accurate capture, smooth screencast at video rates, or visual output that matches a specific Chromium build's rasterization, it is a real risk, and the README does not make a compatibility claim against Chromium rendering. The second limitation is surface area. The README says the same endpoint serves three protocols, but the capabilities list is truncated in this material, so it does not establish which CDP domains are implemented. Code that reaches for an uncommon domain may find it absent. Third, the default is DOM-first: if you forget `--layout`, geometry-dependent operations are not the mode you are in. The project is also young, with v1.1.2 through v1.1.4 released within a week in September 2026, so the API and CLI flags are still moving.

Where Moli sits next to Playwright and Puppeteer

Playwright and Puppeteer drive a full Chromium. They inherit Chromium's rendering, its extension model, and a decade of CDP surface, and they maintain a rendered visual state for the life of the page. Moli inverts the default: it keeps the DOM and style state and treats layout and paint as operations you request. That is the actual difference in approach, and it cuts both ways. If your test suite asserts against a screenshot baseline produced by Chromium, Moli is not a drop-in substitute, because the renderer is not the same and the README makes no pixel-parity claim. If your agent's job is to read pages, the inversion is the point: structure-first operations skip layout and paint entirely, and the README states that layout and pixels are generated only when needed. The compatibility bridge is CDP. Because Playwright can `connectOverCDP` to Moli's endpoint, a team can keep its Playwright client code and change what is listening on port 9222. That is the migration path the README implies, and it is worth testing early because it is also where protocol gaps would surface.

Maintenance, releases, and the Apache-2.0 terms

The repository is not archived and the last push recorded here is 2026-09-10, two days after the v1.1.4 release on 2026-09-08. Three patch releases landed in the first eight days of September 2026, which tells you the project is being actively patched and that minor-version churn is likely. For an operator, that means the upgrade cost is not zero: CLI flags and protocol behaviour are the kind of surface that moves in patch releases this early, so pinning a version and reading release notes before bumping is the practical posture. The licence is Apache-2.0, which permits commercial use, modification, and redistribution provided you keep the licence and notices and comply with its patent and attribution terms. That is a permissive licence and a common choice for infrastructure, but it is not legal advice and the terms should be read against how you distribute the binary. What the material does not support is any claim about long-term support windows, a security response process, or a compatibility matrix across the three protocols. Those are open questions you would need to answer from the repository itself.

Editorial conclusion

Adopt Moli if your workload is DOM-first: extraction, crawling, retrieval, browser-use agents, or evaluation harnesses where most requests never need a rendered frame. Do not adopt it if you depend on a specific Chromium rendering quirk, on browser extensions, or on a protocol or CLI flag that its documentation does not yet list. Before committing, verify three things against your own pages: that `moli fetch --dump markdown --wait-until done` produces the output your pipeline expects, that `moli serve --layout --resource` exposes the CDP surface your client actually calls, and that the Apache-2.0 terms and the release cadence of the v1.1.x line match how you ship.

Official sources

  1. lexmount/moli on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes