Reaction

A browser that skips layout should not be checking your UI by default

Moli, a fast headless browser for agents, skips real layout unless asked. We measured what that does to Playwright's visibility and hit-testing answers.

Published Updated 5 min read

Moli, a headless browser built for agents, topped Product Hunt today on a speed pitch, and the speed comes from a choice worth understanding: by default it does no real layout. For scraping, that is a sensible trade. For verifying a UI, it is the wrong default. In our run, default-mode Moli told Playwright that a zero-size button was visible, put an off-screen button on screen, and said the element under a full-screen modal was the button. If an agent uses it to check its own work, turn on --layout first.

What Moli does differently

Moli is not a Chromium wrapper. It is its own engine, with a DOM, V8, CSS, networking and storage in one binary, and one endpoint that speaks CDP, WebDriver Classic and WebDriver BiDi. Playwright, Puppeteer and Selenium connect to it as if it were Chrome.

The README is explicit about the trade. The default geometry is "LayoutPolicy::Mock", described as "deterministic geometry in a compatible format, with no real layout or paint". DOM queries and JavaScript do "not trigger layout or paint". Real layout, hit-testing and screenshots come with the --layout flag.

The speed is real. Marcus Schuler at Implicator ran v1.1.16 on a page of JavaScript-rendered quotes: "Moli returned all ten in 0.62 seconds with peak resident memory of about 56 MiB" (Repo Radar #20). His write-up also covers "why clicks time out without the layout flag".

That is a reasonable design for an agent that reads pages. The question is what it does to the answers a test asks for.

What we measured

One HTML page with four elements:

  • a Pay button covered by a full-screen modal
  • a 0×0 button
  • a button positioned at left: -9999px

We ran the same Playwright 1.56.1 script against three browsers: stock Chromium launched by Playwright, Moli v1.1.19 in its default mode, and Moli with --layout, both Moli runs connected over CDP. Everything ran on macOS arm64 with Node 22.

CheckChromiumMoli (default)Moli --layout
isVisible on the 0×0 buttonfalsetruefalse
Bounding box of the 0×0 button0×0100×200×0
Bounding box of the off-screen buttonx = -9999x = 0, on screenx = -9999
elementFromPoint at the Pay button's centrethe modalthe Pay buttonthe modal
click on the covered Pay buttontimed outtimed outtimed out

With --layout, Moli matched Chromium on every row. Without it, every geometry answer came back plausible and wrong. The mock policy hands out tidy boxes in document order, 100 pixels wide, stacked 24 pixels apart, whatever the CSS says.

The click row is the good news. Playwright refused to click the covered button in every mode, so the most direct false pass did not happen here.

Why this matters for verification

Playwright counts an element as visible when it "has non-empty bounding box and does not have visibility:hidden computed style" (actionability docs). An agent that checks "the error message is visible" or "the confirm button is on screen" is asking a geometry question. On a mock-geometry browser, the answer is computed from the mock, so a broken layout passes the check.

The elementFromPoint result is the sharper one. "What is under this point?" is how you detect that a modal, a cookie banner or a stuck overlay is covering the thing a user needs. In default mode Moli answered with the button underneath. A check built on that call would report the button as reachable while a real user could not reach it.

None of this is a bug in Moli. It does what its README says, and the speed is real because it skips the work. The risk is in the pairing. Agent tooling increasingly swaps the browser underneath a harness through a CDP URL, and nothing in Playwright's API tells the test that the geometry is synthetic. The test still asks its questions, and they still get answers.

What to do

  • Reading pages, extracting text, filling forms by role or label: the default mode is fine, and fast.
  • Anything that asserts on visibility, position, overlap, scroll or screenshots: start Moli with moli serve --layout, or keep a real browser for that stage.
  • Agent harnesses: record which browser and which layout mode produced a verdict, next to the verdict. A pass from a mock-geometry run is not the same claim as a pass from a laid-out page.

Fast browsers for agents are a good thing. A check is only as honest as the geometry underneath it, and here the geometry is opt-in.

Sources

  1. 01GitHub: lexmount/moli (README: layout policy)github.com
  2. 02GitHub: lexmount/moli release v1.1.19github.com
  3. 03Product Hunt: Moli by Lexmount launchwww.producthunt.com
  4. 04Playwright docs: actionability checks and what visible meansplaywright.dev
  5. 05MDN: Document.elementFromPoint()developer.mozilla.org
  6. 06Implicator.ai: Repo Radar #20, Moli (Marcus Schuler, 12 October 2026)www.implicator.ai
Reticleverdict

// The agent clicked "Pay". Did the right things actually happen?

{verified: "no"failureReason: "POST /api/order returned 500, expected 200"source: "src/checkout/PayButton.tsx:42"}

Example from the README

Your agent says it works. Reticle checks the network, state and console inside your running app, and names the line to fix.

85 of 88 seeded bugs caught in the public benchmark