What it measures
- Core Web Vitals: LCP, CLS and the rest, taken in a real browser rather than estimated from a waterfall.
- Accessibility, via axe-core, on every surface, at desktop and mobile widths.
- Links that go nowhere, including the ones inside a component nobody has clicked since it shipped.
- Console errors, attributed to the surface that produced them.
- Dead controls: a button that is visible, enabled, and does nothing when pressed.
The dead controls are the point
The rest of that list is available elsewhere. This one is not, because it needs a browser to press the thing and watch what happens next. The canonical example, from our own fixture:
A submit button is visible and enabled, but a required field is hidden and cannot pass validation. Clicking submit does nothing, and nothing on the page says why. The browser writes “An invalid form control is not focusable” to a console no visitor will ever open.
Nothing about that page looks broken. Every static check passes. The form has been dead since the day somebody hid that field.
Running it
node cli.cjs vitals
node cli.cjs vitals --devices desktop,mobile
node cli.cjs vitals --scenarios pricing,login
--scenarios narrows to surfaces the profile already declares. It cannot add
one. See the profile.
In CI
It is deterministic, free and exits non-zero on new ship-blockers, which is the whole specification for a gate. Running it in CI.