Inspect layout, styles and design tokens on any page — from an extension that asks for no access to your data.
Every other inspector in this category asks to read and change all your data on all websites. That covers your staging environments, your internal dashboards, and anything you happen to be logged into. All three of the established tools are closed source, so the permission is the last thing you can verify about them.
This one asks for nothing. Chrome's own install screen will tell you the same thing.
The manifest declares activeTab and scripting, and no host_permissions key exists. activeTab is granted by your click, for one tab, and revoked by the browser the moment you navigate away.
Hover anything, or click to hold it. Arrow keys walk the tree — ↑ parent, ↓ first child, ←→ siblings — which is the only way to reach a wrapper that has no padding of its own and is therefore entirely covered by its children.
|
Styles — the box model, the spacing, and the rules that actually matched, with the declarations that lost the cascade struck through. Values are editable.
|
Layout — how the element lays out its children, how its parent places it, and the spacing scale the page genuinely follows, with outliers named. Nothing else in this category reports this.
|
|
Color — live WCAG AA/AAA grading with the nearest passing colour, a screen eyedropper that reads pixels the DOM cannot, and an audit that finds every failing text sample on the page and jumps to it.
|
Type — the font that actually rendered, measured on a canvas rather than read off the stack, because
|
Plus three more panels:
| Assets | Images with the srcset candidate the browser really chose, inline SVG lifted out as standalone markup, video, webfonts, Lottie hints |
| Markup | The element as HTML or JSX, with hydration ids, framework attributes and script-set inline styles stripped — source to paste, not a DOM recording |
| Export | CSS custom properties, SCSS, Tailwind config, JSON, W3C design tokens, and a markdown handoff written for a coding assistant |
Every claim above is checked by something that fails the build when it stops being true.
| 0 | host permissions | No host_permissions key exists in the manifest. Chrome's install screen shows no site access requested. |
| 0 | network requests | No fetch, XMLHttpRequest, WebSocket or sendBeacon — scanned across source, both generated manifests and the shipped bundles on every build by scripts/check-zero-egress.mjs. |
| 946 | tests | 908 unit tests, plus 38 end-to-end tests that drive the real packaged extension in a real Chromium. |
| AA | its own contrast | The panel grades other pages on WCAG contrast, so it is held to the same standard in both themes by a test that measures the real cascade. |
pnpm verify # typecheck, lint, unit tests, and the zero-egress guardSpacing and appearance in Styles, the metrics in Type, and the element's own colours in Color are all editable — click, type, Enter. Arrow keys step numbers (Shift by ten, Alt by a tenth).
Three properties make that safe on a page you cannot afford to break:
- Exactly revertible. Every edit records the element's prior inline value and its
!importantstate, so reverting restores what was there — including a page's own inline styles, which a blanketstyle.cssText = ''would destroy. - Rejected values are reported, not swallowed.
setPropertysilently ignores anything it cannot parse, so values are checked withCSS.supportsbefore being written. Checking afterwards cannot work: if the element already hadcolor: blueinline, a rejected write leavesbluein place, which is indistinguishable from success. - Nothing is persisted. Closing reverts every edit and removes the
styleattribute it created, down to not leaving an emptystyle=""behind.
Honest failure beats a confident wrong answer, so the panel reports what it cannot see.
- Cross-origin stylesheets cannot be read.
.cssRulesthrows when a stylesheet is served from another origin without CORS headers, and no extension permission changes that — the restriction follows the stylesheet, not the reader. Stripe serves all six of its sheets this way, so Matched Rules is empty there and says so rather than claiming nothing matched. DevTools works around this by refetching the CSS over the network; we will not, because that would break the zero-egress promise. - Canvas and WebGL surfaces have no DOM inside them. Nothing can fix this.
- Closed shadow roots are undetectable by design. An empty custom element that clearly rendered something is flagged as probably hiding one, described as the heuristic it is.
- Cross-origin iframes are unreachable from the parent frame, for every extension.
- The responsive preview cannot go below the operating system's minimum window width, roughly 570px on macOS. The panel reports the width actually achieved rather than the one requested.
color-mix(),light-dark()and relative colour syntax are refused rather than guessed at.lab(),lch(),oklch()andoklab()all parse.- No screenshots, console or network debugging. Those are separate products.
- No bulk asset download, deliberately: zipping every asset would mean fetching every asset. The Assets tab offers the URL list for
curlinstead.
pnpm install
pnpm build # production build into .output/chrome-mv3
pnpm launch # a disposable browser with the extension already installedpnpm launch starts the playground and opens a Chromium window with the extension loaded. Press Alt+Shift+I, then hover anything. Esc stops it.
Use
pnpm build, notpnpm dev, before loading it manually. WXT writes both to.output/chrome-mv3, but the dev manifest adds thetabspermission, host permissions for localhost, and a relaxed CSP so hot reload can work. Loading that would show the permission posture this project exists to avoid —pnpm launchrefuses to start on a dev build for the same reason.
All commands
| Command | What it does |
|---|---|
pnpm launch |
Disposable browser with the extension installed |
pnpm dev / pnpm dev:firefox |
WXT dev build with hot reload |
pnpm build / pnpm build:firefox |
Production build into .output/ |
pnpm zip |
Package for the store |
pnpm test |
Unit tests |
pnpm e2e |
End-to-end: the real extension in a real browser |
pnpm e2e:headed |
Same, with a visible window |
pnpm typecheck |
Project-wide typecheck |
pnpm check:egress |
The zero-egress guard |
pnpm check:size |
Bundle budgets, gzipped |
pnpm check:site |
The website's own contrast and image-ratio checks |
pnpm sweep |
Run the engine against real production sites |
pnpm verify |
Typecheck, lint, unit tests, egress guard |
pnpm gen:icons / gen:promo / gen:shots |
Regenerate icons, store promo images, screenshots |
packages/core the engine. pure TypeScript, no chrome.*, no network
packages/ui shadow-DOM overlay and the interaction loop
apps/extension WXT shell: manifest, background worker, injected script
apps/playground manual test surface, and the demo page used for screenshots
apps/site the website — static files on Cloudflare Workers
The engine deliberately knows nothing about browser extensions. It takes a DOM and returns data, which is what lets it be unit-tested without a browser and reused later in a CLI or a Playwright plugin.
How the zero-permission manifest works: the content script is declared with registration: 'runtime' and no matches patterns. WXT only promotes a runtime script's match patterns into host_permissions, so declaring none leaves the manifest free of host access. The background worker injects it via scripting.executeScript under activeTab.
pnpm build && pnpm sweepBundles the engine standalone, injects it into a dozen real production sites, and drives every module over a spread of elements on each. It reports two kinds of finding, deliberately kept apart: errors (something threw — always a bug) and suspicions (it returned, but the answer looks wrong — no rendered font on visible text, an empty palette on a colourful page).
It has already earned its keep. The first run found that Chrome serializes computed colours as lab() whenever the author used a modern colour space — so on tailwindcss.com, 2,398 colour values were being rejected as unreadable and the palette came back nearly empty. That is the most popular CSS framework there is, and no unit test would have caught it.
The reliability harness is the best place to start. A page the inspector gets wrong is a perfectly scoped issue: add it to tests/fixtures/ as a snapshot, assert the correct reading, and fix it. No product-design judgment required, and every fixture makes the next change safer.
There is a Buy me a coffee link in the panel's footer, and that is the entire business model. The extension is free, all of it, forever — there is no paid tier, no licence check and no account, and there cannot be: a licence check is a network request, which is the one thing this project promises never to make.
MIT. See LICENSE.