An audit that says "your spacing is inconsistent" is a horoscope. To be worth anything it has to point: this element, this value, this target. That means drawing a marker on someone else's page — and the browser is built to stop you doing exactly that.
Iframes are a dead end
The obvious version is an iframe. Load the site, overlay markers on top, done.
Two things kill it. Most real sites send X-Frame-Options or a frame-ancestors CSP, so the frame never loads at all — the whole point of that header is refusing to be embedded by me. And on the ones that do load, the frame is cross-origin, so JavaScript can't reach inside it. I can't ask where an element is, how big it is, or what colour it computed to. No measurements, and nothing to anchor a marker to.
So the browser gives you two options: a page you can't embed, or a page you can embed and can't measure. Neither is an audit.
Don't load their page. Rebuild it.
The capture runs in a real headless Chromium — Cloudflare's Browser Run — where the site is just a page and everything is readable. While it's open, every element I care about gets stamped with a data-dl-id, and the computed styles get measured on the spot: contrast ratios, spacing, type sizes, target sizes, overflow. That part has to happen there, because that's the only place the numbers exist.
Then the already-hydrated DOM gets serialized, stamps and all, and served back from my own origin.
That one move fixes both problems at once. It's my HTML on my domain, so there's no X-Frame-Options to refuse me and no cross-origin wall — the UI can find element #42 live, read a fresh rect off it, and put the marker exactly there. Not a screenshot with coordinates baked in: a real DOM. Scroll it, resize it, switch viewport, and the overlays stay glued to their elements, because they're being positioned from the element itself every time rather than from a number I wrote down earlier.
A screenshot would have been easier and would have been wrong within one scroll.
The part that made it dangerous
I had just given a stranger's HTML my origin. That's the same trick as a stored XSS, except I built the delivery mechanism on purpose.
So the snapshot is stripped at capture time with real DOM APIs — scripts, inline handlers, javascript: URLs, CSP and refresh metas all removed — and then served with script-src 'none' and framed with sandbox="allow-same-origin". Deliberately without allow-scripts. Those two flags together let sandboxed content escape into the origin that framed it, which is the one combination that undoes everything above, and the code says so in a comment so I don't cleverly add it later.
The URL itself gets the same treatment before any of this: DNS is resolved and every returned address has to be public, so nothing can be talked into fetching 169.254.169.254 or something on a home network, and each subsequent request the browser makes is re-checked so redirects can't sneak past the first check either.
What it cost
Two things, both real.
Elements are capped at 1500 per viewport. A snapshot is a whole page of markup, and the tab you inspect it in is a real browser tab.
And the deployed version measures two viewports, not four. Free-tier Browser Run kills a session at sixty seconds and gives you ten minutes of browser time a day; four viewports don't reliably fit. It runs 1440 and 390 — the widest and the narrowest, where layout actually breaks — and the two in the middle are one config line away when the budget is.
DesignLens is at designlens.mavrickblackburn.com. Paste a URL in and it'll tell you what's wrong with it, and point at it while it does.