The Browser That Only Renders When You Ask

A Rust headless browser whose bet is that agents need page structure, not a maintained visual world — so layout and paint are computed on demand, frozen, and thrown away.
The market for browsers nobody looks at is having a moment. Lightpanda just shipped a 1.0 with 1.7 million passing WPT subtests and a cloud offer attached. Obscura sits at 28.4k stars, sponsored by three proxy companies, with a waitlist for its own cloud. Cloudflare and Browserbase sell managed browsers by the thousand to agents that shop, scrape, file claims, and run KYC checks. Into this crowd walks Moli — a Rust headless browser from Lexmount, dual-licensed Apache-2.0/MIT, running on Linux, macOS, and Windows — with a pitch that is less about being small and more about being lazy.

A naming note, because it will matter to anyone searching: Moli is also a Greenwich restaurant with elaborate murals and silk furnishings, a Spotify artist, and a verified Facebook musician with a song about the struggles of casual dating. The browser is several pages down the results. Obscure name, serious architecture.
The standing army nobody watches
Start with the boring fact at the center of the project, because that is where the value is. A conventional browser spends most of its life maintaining a visual world that, in headless agent workloads, has no audience. Every DOM mutation ripples outward through style recalculation, invalidation, damage tracking, layout patching, display-list updates, and compositing — machinery built so a human watching at sixty frames per second sees smooth motion. Headless Chrome inherits all of it and pays for it continuously. In Moli’s crawl benchmark, Chrome Headless ran at a median of 773 MiB of resident memory per page. That is the tax for keeping pixels honest for nobody.
Moli’s answer is an inversion of browser architecture rather than a diet. The native DOM and its computed style — via Stylo, the CSS engine out of Servo — are the single source of truth, and almost nothing else persists. There is no incrementally maintained layout tree, no damage graph, no retained display list, no GPU compositor, no persistent window. When a request genuinely needs geometry, Moli builds a working layout tree from scratch — Taffy for boxes, Parley for text — freezes the canonical geometry into an immutable, DOM-independent structure the README calls a FrozenLayoutTree, keeps only that, and discards the working tree, the style borrows, the layout caches, and the paint state.
Requests then sort into three tiers. Structure work — extracting HTML or Markdown, querying the DOM, running JavaScript, inspecting network and storage — reads browser runtime state directly and never triggers layout or paint. Geometry work — reading an element’s box, hit-testing a coordinate, sending coordinate input — runs one layout pass and retains the frozen tree. Visual work — a screenshot, a screencast frame — rebuilds from the current DOM and style, replaces the frozen tree, renders one fresh frame, and throws the frame away after use.
Where Chrome keeps a standing army of rendering infrastructure on permanent duty, Moli keeps a reserve, calls it up per request, and sends it home. The README’s framing is blunt and correct: what most browser automation tasks actually need is page structure, not a continuously rendered visual world.
Nor is Moli everything-from-scratch in the Lightpanda-in-Zig sense. It assembles the Rust browser-components ecosystem — libcurl for transport, html5ever for parsing, V8 for JavaScript, Stylo for CSS, Taffy and Parley for layout, Vello’s CPU renderer and usvg for paint — with the original work sitting in the ownership and lifecycle rules that decide when any of the visual machinery runs at all. The parts are shared; the policy is the product. One binary speaks CDP, WebDriver Classic, and WebDriver BiDi on the same endpoint, with no separate ChromeDriver or browser install, and the CLI emits Markdown, JSON, and semantic text trees directly, with selector, script, and response waits built in.
Mock geometry, frozen trees
The most aggressive cost control is also the one most likely to surprise anyone porting an existing suite: by default, Moli runs under a policy the README calls LayoutPolicy::Mock, which returns deterministic geometry in a compatible format with no real layout and no paint. Ask where an element sits and you get deterministic, plausible-shaped answers without a single layout pass having run. Real geometry — Taffy layout, hit-testing, coordinate input, screenshots, screencast — lives behind an explicit opt-in, and optional resource families such as images, fonts, audio, and video each sit behind their own. Persistence is selective too: profiles, HTTP cache, and cookie files exist only if a workload turns them on. Expensive behavior is never on by default.
Then there is the staleness rule, documented and worth reading twice: ordinary geometry reads may reuse the frozen tree even if the page has changed since it was built. Screenshots and screencasts never reuse anything — they always rebuild from current state. Geometry can be stale; pixels cannot. That is a real consistency trade-off, stated in writing rather than discovered in production, which is the honest way to ship one. What the README does not spell out is how a CDP or WebDriver client is supposed to tell mock geometry from real — whether anything in the protocol surface flags the difference. That is unclear, and it is the kind of unclear that matters if you point a visual-regression tool at the default configuration and believe what comes back.
One design choice deserves particular credit: unsupported protocol paths return explicit errors. The README states it as a principle — Moli never pretends that a browser action, event, network observation, or visual result occurred. For agent workloads this matters more than it sounds. A browser that silently no-ops an unsupported call hands the agent a fabricated success, and agents are remarkably good at building confident narratives on top of fabricated successes. Loud failure is an agent-safety feature.
The numbers, self-reported
The README carries two measured data sets. Both are the project’s own, and nothing in the available material independently corroborates them — worth saying up front. The first is a crawl over 192 public URLs from major Chinese and international sites, with a success definition better than most: a page counts only if it produces meaningful content after JavaScript runs. An HTTP 200, a challenge page, a login wall, an empty response, or a shell-only application does not count. That measures extraction value, not network luck.
On that set, Moli delivered 103 useful pages — 53.6 percent — at a 1.43-second median and 73 MiB of median RSS. Chrome Headless delivered 101 at the same median time and 773 MiB. Lightpanda delivered 85 at 0.97 seconds and 40 MiB. Obscura delivered 57 at 1.30 seconds and 39 MiB.
Read as a trade-off table, it is genuinely interesting. Moli matched Chrome’s extraction quality at roughly a tenth of the memory, at identical median time. Lightpanda was faster and lighter and lost sixteen pages that Chrome got — the price of a no-rendering engine on a web that keeps finding new ways to need one. Obscura, lightest of all, lost nearly half the useful pages. The implied pattern: the more you strip from a browser, the more pages slip through. Moli’s bet is that lazy rendering keeps the full runtime available without paying rent on it.
The caveats deserve equal billing: 192 URLs is a small sample, the mix skews toward major sites, the definition of meaningful is the project’s own, and the exercise is unaudited. It is a capability envelope, not a certification.
The second data set is an agent workload, and its vocabulary is telling — episode active p50 is reinforcement-learning language. Moli reports CDP readiness at 34.85 milliseconds against Chromium’s 169.37; episode-active p50 of 33.40 against 57.13; peak PSS of 102.46 MiB against 348.82; and one process with 24 threads against Chromium’s 11 processes and 123 threads. For evaluation farms and RL environments running thousands of parallel browser episodes, that last row is the story — one process per instance changes what a fleet of browsers looks like, and a sub-35-millisecond cold start makes spawn-a-browser-per-task a reasonable architecture rather than a luxury.
Moli also reports 1.612 million passing tests in one complete run of its WPT selection; Lightpanda claims 1.7 million passing subtests at its 1.0. The selections differ, so the numbers are not comparable — but the fact that both engines lead with WPT counts says something about this cohort: they measure themselves against the web platform, which is the correct opponent.
Three bets on the same problem
The field has sorted into roughly three positions, and Moli’s is the newest. Lightpanda’s bet is subtraction: no rendering, ever — JavaScript execution, no graphical rendering, as its own site puts it. Fastest, lightest, and visibly lossy on hard pages, per Moli’s table.
Obscura’s bet is camouflage. Its README leads with built-in anti-detection, claims Cloudflare’s Kitesurf prototype began as a port of Obscura, and carries sponsor blurbs from three proxy providers complete with discount codes. Obscura has since added native rendering — screenshots, screencast, PDFs — so it straddles the structure/pixels line too, but its center of gravity is looking human.
Moli’s bet is metering. Rendering exists, completely — V8, CSS, layout, text shaping, hit-testing, software paint — but it is lazy, opt-in, and discarded after use. Notably, the README says nothing about stealth or anti-detection at all. In a market where Obscura sells evasion and Cloudflare advertises a well-behaved bot mode that identifies itself with cryptographic signatures, Moli is conspicuously silent on the arms race. It competes on the cost model, not the camouflage.
There is also a commercial convergence worth noticing, because everyone lands on the same shape. Lightpanda has a cloud. Obscura has a cloud waitlist. Cloudflare and Browserbase are the cloud. Lexmount Browser is Moli’s managed runtime and control plane, and the README states in writing that the open-source browser is fully usable without it — the standard open-core promise, at least explicitly made.
One small detail dates the project precisely: Moli ships a skills directory, and the README’s opening instruction is a prompt you hand to your AI agent, which then installs the skills, downloads the binary, and fetches a page. The primary reader of this browser’s documentation is expected to be a machine. Meanwhile, out in the operational world, scraping teams were already building escalation ladders — one operator on Hacker News described starting with the cheapest extraction, no JavaScript and no browser, and escalating to a real browser only when a site demands it. Moli internalizes that ladder inside a single binary: the cheap tier and the expensive tier become per-request policies rather than separate infrastructure.
What it refuses to do
The scope section is unusually candid. No GUI, no persistent window, no GPU compositor, no retained multi-frame paint. No pixel-for-pixel parity with Chrome, no high-fidelity Canvas or WebGL, no serious media playback. Not every Chrome screenshot or print mode is implemented. Within the agent-browser scenarios its documentation defines, the project claims production readiness; outside them, it fails loudly rather than approximating quietly.
That last clause is the whole philosophy in one line, and it is the right one for the audience. Agents do not need a browser that can do everything. They need one that never lies about what it did.
The open questions
At least three. Whether the extraction-quality edge holds beyond 192 curated URLs — the web is long-tailed, and the long tail is where engines break. Whether mock-by-default geometry survives contact with the Playwright and Puppeteer ecosystem, whose assumptions were formed on Chrome; the README does not say how a client distinguishes mock from real. And whether any of it holds up under third-party measurement, since every number here is the project’s own.
The deeper question is whether the idea spreads. Never render and always render are both special cases of render on demand — Lightpanda’s policy and Chrome’s policy sit at the two ends of a spectrum Moli claims the middle of, per request. If the cost model is right, and the memory numbers suggest it is at least right for crawl-and-extract workloads, the incumbents can copy it without giving anything up. On-demand rendering is not a moat; it is an argument. Moli’s contribution is making the argument in working code, with a frozen tree where everyone else keeps a standing army.
Sources
- Home | Moli in Greenwich, CT
- h4ckf0r0day/obscura: The headless browser for AI agents ...
- Is browser-based web scraping the next major unlock for AI ...
- Moli
- Lightpanda | The headless browser
- How I Built a Web Scraping AI Agent
- Moli (@whoismoli)
- Headless browser agents are a dead end. The future is ...
- We're using AI agents for the orchestration of our fully ...
- MOLI (@whoismoli) • Instagram photos and videos
- Headless, programmable web browsers built for AI Agents
- Browserbase Use Cases: Web Scraping & AI Agent ...