astro-webvitalsv0.4.9

CASOON Open Source

Web Vitals from real visits, for Astro.

astro-webvitals measures LCP, CLS, INP, FCP and TTFB with Google’s web-vitals library and sends them in batches to an endpoint you own. Collection can be gated on consent, Do Not Track and a sample rate; a local dashboard and a development overlay help while you build.

pnpm add @casoon/astro-webvitals
npm install @casoon/astro-webvitals
MITnpm 0.4.9Astro 4–7Node 18.17+
dashboard page checks · sample.html
pass   Title            26 characters
issue  Description      Missing
pass   Canonical        Present
pass   Language         en
pass   H1               One heading
issue  Open Graph       Title, description or image missing
pass   Skip link        Present
issue  Image alt        1 image without alt
issue  Link text        1 empty link
issue  Form labels      1 unlabelled control
info   Structured data  No invalid JSON-LD found
Web Vitals from Google’s web-vitals
5
runtime dependency
1
supported Astro major versions
4–7
gzip entry script in the demo build
4.7 kB

What it does

  1. Official metric definitions

    LCP, CLS, INP, FCP and TTFB come from the web-vitals package, with its ratings, stable metric IDs and deltas, so repeated CLS and INP reports aggregate correctly.

  2. Reports go to your endpoint

    Metrics are batched, flushed when the page is hidden and sent with sendBeacon where possible. Without an endpoint nothing is sent; every metric is also dispatched as a webvitals:metric event.

  3. Collection gates

    consent={false} and respectDnt stop the client before any observer is registered. sampleRate is decided per page load in the browser, not baked into a static build.

  4. Local dashboard

    webVitalsDashboard() adds a static, noindex route that reads this browser’s localStorage, runs a sitemap pass and shows page checks – for development and QA, not field analytics.

  5. Development overlay

    debug shows live metrics, an SEO inspection and a small accessibility heuristic. It is a development aid, not a WCAG audit.

Generated at build time

All examples →
<script>(function(){const config = {
  "debug": false,
  "consoleDock": false,
  "position": "bottom-right",
  "desktopPositions": {
    "top-right": "top: 16px; right: 16px;",
    "top-left": "top: 16px; left: 16px;",
    "bottom-right": "bottom: 16px; right: 16px;",
    "bottom-left": "bottom: 16px; left: 16px;"
  },
  "mobilePosition": "bottom: 0; left: 0; right: 0;",
  "batchReporting": true,
  "batchInterval": 5000,
  "checkAccessibility": false,
  "highlightAccessibility": false,
  "extendedMetrics": false,
  "smartDetection": false,
  "performanceBudget": {
    "LCP": 2500,
    "CLS": 0.1,
    "FCP": 1800,
    "TTFB": 800,
    "INP": 200
  },
  "headers": {},
  "sampleRate": 1,
  "trackSoftNavigations": false,
  "attribution": false,
  "trackLongTasks": false,
  "maxBatchSize": 10,
  "retryFailedMetrics": false,
  "respectDnt": false,
  "consent": true,
  "dashboard": false
};
window.__WEBVITALS_CONFIG__ = config;
})();</script>
<script type="module" src="/_astro/WebVitals.astro_astro_type_script_index_0_lang.KhS4lISl.js"></script>

What <WebVitals /> adds to a statically built page, captured from the demo build by examples/capture.mjs and formatted for reading.

examples/output/default.html

Why this site does not measure itself

This site ships no JavaScript beyond the theme’s two inline scripts. The component would add its own configuration and module script, so the examples here are captured build output of the package instead of live measurements. No metric values are shown: Web Vitals depend on each visitor’s device and connection.

Quickstart

Three steps from install to your first reports. The full walkthrough lives in the documentation.

  1. Install @casoon/astro-webvitals.
  2. Add <WebVitals /> once to your shared layout, right before </body>.
  3. Store the batches in a same-origin route, or listen for the webvitals:metric event.
src/layouts/Layout.astroLayout
---
import { WebVitals } from '@casoon/astro-webvitals';
---

<html lang="en">
  <body>
    <slot />
    <WebVitals endpoint="/api/analytics/vitals" sampleRate={0.1} />
  </body>
</html>
src/pages/api/analytics/vitals.tsEndpoint
import type { APIRoute } from 'astro';

export const POST: APIRoute = async ({ request }) => {
  const { metrics } = await request.json();
  for (const metric of metrics) {
    // Validate, rate-limit and store; sum deltas per metric.id.
  }
  return new Response(null, { status: 204 });
};