Core Web Vitals & Real-User Performance Monitoring
Status: Active Standard (Floorix Implemented; DotPortal, Govnix, Perfxcel in Rollout)
Telemetry Pipeline: Dual Reporting (SentryTransactions +UmamiCustom Events)
Target Library:web-vitalsv6
Last Updated: October 2026
1. Overview & Objectives
In manufacturing and governance SaaS applications, real-world operators frequently use low-spec shop-floor terminals, tablets, and variable cellular connections. To prevent performance degradation from silently impacting operations, DotEvolve applications measure real-user Web Vitals at runtime.
This standard implements Google's Core Web Vitals (CWV) metrics across all DotEvolve frontend applications: 1. LCP (Largest Contentful Paint): Perceived load speed of the primary UI element. 2. INP (Interaction to Next Paint): Responsiveness to user input (clicks, taps, keystrokes). 3. CLS (Cumulative Layout Shift): Visual stability during rendering. 4. FCP (First Contentful Paint): Initial visual feedback after page request. 5. TTFB (Time to First Byte): Network and server response latency.
2. Core Web Vitals Targets
All DotEvolve client applications aim for the 75th percentile of real user visits:
| Metric | Full Name | Good (Target) | Needs Improvement | Poor |
|---|---|---|---|---|
| LCP | Largest Contentful Paint | $\le 2.5\text{ s}$ | $2.5\text{ s} - 4.0\text{ s}$ | $> 4.0\text{ s}$ |
| INP | Interaction to Next Paint | $\le 200\text{ ms}$ | $200\text{ ms} - 500\text{ ms}$ | $> 500\text{ ms}$ |
| CLS | Cumulative Layout Shift | $\le 0.1$ | $0.1 - 0.25$ | $> 0.25$ |
| FCP | First Contentful Paint | $\le 1.8\text{ s}$ | $1.8\text{ s} - 3.0\text{ s}$ | $> 3.0\text{ s}$ |
| TTFB | Time to First Byte | $\le 800\text{ ms}$ | $800\text{ ms} - 1800\text{ ms}$ | $> 1800\text{ ms}$ |
3. Architecture & Telemetry Pipeline
Web Vitals metrics are measured client-side via the modern Performance Observer API (encapsulated in web-vitals) and reported simultaneously to Sentry and Umami:
flowchart LR
subgraph Browser ["Client Browser (SPA)"]
WebVitals["web-vitals v6<br/>(onLCP, onINP, onCLS, onFCP, onTTFB)"]
Init["initWebVitals()"]
end
subgraph Telemetry ["Telemetry Pipeline"]
Sentry["Sentry Error & Performance<br/>(Breadcrumbs & Measurements)"]
Umami["Self-Hosted Umami v2<br/>(Custom Events: 'web-vital')"]
end
subgraph Observability ["Engineering Dashboards"]
SentryDash["Sentry Performance Insights"]
UmamiDash["Umami Platform Telemetry"]
end
WebVitals --> Init
Init -->|captureBreadcrumb / setMeasurement| Sentry
Init -->|umami.track('web-vital')| Umami
Sentry --> SentryDash
Umami --> UmamiDash
Dual-Dispatch Advantages
- Sentry (Diagnostic Debugging): Correlates high INP or slow LCP directly with JavaScript errors and slow API transaction spans.
- Umami (Platform Aggregate Telemetry): Provides privacy-friendly, un-sampled aggregate percentiles per tenant and geographic region without sending PII.
4. Implementation Reference
4.1 Implementation Code (src/utils/vitals.ts)
import { onCLS, onFCP, onINP, onLCP, onTTFB, type Metric } from 'web-vitals';
import { Sentry } from '@dotevolve/error-utils/react';
declare global {
interface Window {
umami?: {
track: (eventName: string, eventData?: Record<string, any>) => void;
};
}
}
export function reportWebVitals(metric: Metric): void {
const { name, value, rating, delta, id } = metric;
// 1. Send diagnostic measurement to Sentry
try {
Sentry.addBreadcrumb({
category: 'web-vitals',
message: `${name}: ${Math.round(value)}ms (${rating})`,
level: rating === 'poor' ? 'warning' : 'info',
data: { delta, id, rating },
});
} catch {
// Sentry uninitialized
}
// 2. Dispatch custom event to self-hosted Umami
try {
if (typeof window !== 'undefined' && window.umami?.track) {
window.umami.track('web-vital', {
metric: name,
value: Math.round(name === 'CLS' ? value * 1000 : value),
rating,
});
}
} catch {
// Umami script blocked or disabled
}
}
export function initWebVitals(): void {
// Respect user preference for reduced telemetry / data saver
if (navigator.connection && (navigator.connection as any).saveData) {
return;
}
onCLS(reportWebVitals);
onFCP(reportWebVitals);
onINP(reportWebVitals);
onLCP(reportWebVitals);
onTTFB(reportWebVitals);
}
4.2 Application Initialization (src/index.tsx)
Initialize telemetry immediately after error monitoring to capture early paint metrics (FCP / TTFB):
import './lib/sentry';
import './lib/logger';
import { initWebVitals } from './utils/vitals';
// Initialize performance monitoring
initWebVitals();
5. Migration Roadmap: Package Consolidation
Currently, web-vitals is installed individually per application repository. To standardize telemetry across the organization:
- Move Telemetry Helper to
@dotevolve/error-utils: - Package
@dotevolve/error-utilsis public on npm/GitHub Packages and already houses Sentry and logging wrappers. - Adding
initWebVitals({ umamiTrack?: boolean })to@dotevolve/error-utilscentralizes metric collection logic and ensures updates apply universally. - Package Boundaries:
- Public package:
@dotevolve/error-utils(safe for all apps and marketing sites). - Internal package:
@dotevolve/core(houses proprietary RBAC, permissions, and tenant schemas).