Core Web Vitals (core-web-vitals)
Summary
Measures LCP, CLS, FCP, TTFB, and INP using Performance Observer in a real browser session (Playwright).
Classification
- Category:
PERFORMANCE - Plugin id:
core-web-vitals - Version:
1.1.0 - Target types:
WEBSITE,WEBSHOP - Weight class:
MEDIUM - Escalation policy:
AGE_ONLY(age-based escalation only; recurrence reflects scan frequency) - Risk level: not set on plugin object
- Browser required: Yes (Playwright)
- Tier / group: Tier 2 — Browser (Playwright)
Schedule
- scheduleHints:
{ defaultInterval: '0 */3 * * *', priority: 7 } - Prerequisites: None declared on this plugin.
Configurable inputs
Public keys are derived from inputSchema: z.object({ ... }) (underscore-prefixed keys are runtime-only and omitted here).
| Field | Notes |
|---|---|
timeout |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
lcpGood |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
lcpPoor |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
clsGood |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
clsPoor |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
inpGood |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
inpPoor |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
samplePages |
Optional injected pages when Run on other pages is enabled on the target profile. |
Multi-page mode
When Run on other pages is enabled, measures vitals on up to 5 pages (homepage + 4 samples). LCP/CLS/INP findings are per-page; run score uses the worst page score.
Checks that produce findings
These checks run inside this plugin during a single test run. They are not separate tests in the database — each becomes a Finding linked to the Run for core-web-vitals.
| Check | Typical severity | Why |
|---|---|---|
Poor LCP (measured LCP > lcpPoor, default 4000 ms) |
WARNING | Slow largest paint delays perceived load and correlates with lower conversion and weaker CrUX/Search signals. |
LCP needs improvement (> lcpGood, default 2500 ms, but ≤ poor) |
WARNING | Above the “good” CrUX band — worth optimizing before it crosses into poor territory. |
Poor CLS (CLS > clsPoor, default 0.25) |
WARNING | Layout shifts cause mis-clicks on buttons and forms, directly hurting UX and ad/shop metrics. |
CLS needs improvement (> clsGood, default 0.1, but ≤ poor) |
WARNING | Visible jank during load; fix before cumulative shift crosses the poor threshold. |
Poor INP (p98 event duration > inpPoor, default 500 ms, when INP > 0) |
WARNING | Sluggish interactions after tap/click frustrate users and fail the Interaction to Next Paint “poor” band. |
INP needs improvement (> inpGood, default 200 ms, when INP > 0) |
WARNING | Main-thread blocking is noticeable; optimize before INP degrades further. |
How each check works
- Load and measure — Playwright + CDP
Performance.enable,networkidlenavigation (default 30s), then 3s settle wait. - INP sampling — Registers an Event Timing observer (
durationThreshold: 16), simulates click + Tab keypresses, waits 1s, then computes INP as p98 of collected event durations (web-vitals-style). - LCP, CLS, FCP, and TTFB — Reads Performance Timeline: LCP from largest-contentful-paint entries; CLS sums layout-shift values excluding
hadRecentInput; FCP from paint timing; TTFB from navigationresponseStart − requestStart. - Thresholds (defaults, all overridable) — LCP good 2500 ms, poor 4000 ms; CLS good 0.1, poor 0.25; INP good 200 ms, poor 500 ms. Both “needs improvement” and “poor” bands emit WARNING findings (no INFO tier).
- INP gate — INP findings are skipped when measured INP is 0 (no interaction samples).
- Artifacts and score — Saves
performance-vitals.jsonplus resource-weight metrics. Run score: 100 passed, 55 if any WARNING, 20 if CRITICAL (none emitted). Status mirrors score tiers.
Caveats and concerns
- Lab, not field data — Single cold load from the worker region differs from CrUX field medians and user devices.
- Synthetic INP — Minimal click/Tab may not reflect real user interaction patterns; INP often stays 0.
- Network idle — Heavy long-polling or analytics can delay
networkidleand skew timings. - No FCP/TTFB findings — Metrics are reported in summary/metrics only; only LCP, CLS, and INP generate findings.
- Adaptive follow-ups — Failed CWV runs may trigger
third-party-script-perfandcache-header-auditvia the adaptive orchestrator.
Source
packages/test-plugins/src/plugins/core-web-vitals.ts