Abrova
☰ Docs menu · Core Web Vitals

Core Web Vitals

Measure real-world user experience for loading performance, interactivity, and visual stability with LCP, INP, CLS, TTFB and FCP metrics.

Last updated: 27 Oct 2026

Core Web Vitals are a set of metrics defined by Google that measure real-world user experience for loading performance, interactivity, and visual stability. These metrics directly impact SEO rankings and user satisfaction. AbrovaTrace uses Google's official web-vitals library for accurate measurement.

Browser Only.

Web Vitals are browser-specific metrics. Today only the Next.js SDK (@abrova-trace/nextjs-sdk) reports them. For mobile apps (iOS, Android, Flutter), use API Latency Tracking instead.

Metrics Explained#

LCP — Largest Contentful Paint

Measures loading performance. Marks when the largest content element (image, video, or text block) becomes visible.

Good
≤2.5s
Needs improvement
2.5–4s
Poor
>4s

INP — Interaction to Next Paint

Measures overall responsiveness. Observes all interactions and reports the worst latency.

Good
≤200ms
Needs improvement
200–500ms
Poor
>500ms

CLS — Cumulative Layout Shift

Measures visual stability. Sum of all unexpected layout shifts during the page's lifecycle.

Good
≤0.1
Needs improvement
0.1–0.25
Poor
>0.25

TTFB

Time to First Byte

Server response time

Good: ≤800ms

FCP

First Contentful Paint

Perceived load speed

Good: ≤1.8s

Next.js#

Basic Setup

typescript
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

AbrovaTrace.init({
  apiKey: 'ab_live_your_api_key',
  environment: 'production',
  release: '1.0.0',
});

// Enable Web Vitals tracking
// Automatically captures LCP, INP, CLS, TTFB, FCP
AbrovaTrace.getInstance()?.enableWebVitals();

App Router (Next.js 13+)

tsx
// app/providers.tsx
'use client';

import { useEffect } from 'react';
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

export function Providers({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    AbrovaTrace.init({
      apiKey: process.env.NEXT_PUBLIC_ABROVA_TRACE_KEY!,
      environment: process.env.NODE_ENV,
    });

    // Enable Web Vitals tracking
    AbrovaTrace.getInstance()?.enableWebVitals();

    // Enable HTTP performance tracking
    AbrovaTrace.getInstance()?.enablePerformanceTracking();

    return () => AbrovaTrace.getInstance()?.close();
  }, []);

  return <>{children}</>;
}

Pages Router

tsx
// pages/_app.tsx
import { useEffect } from 'react';
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';

function MyApp({ Component, pageProps }) {
  useEffect(() => {
    AbrovaTrace.init({
      apiKey: process.env.NEXT_PUBLIC_ABROVA_TRACE_KEY!,
      environment: process.env.NODE_ENV,
    });

    AbrovaTrace.getInstance()?.enableWebVitals();
    AbrovaTrace.getInstance()?.enablePerformanceTracking();

    return () => AbrovaTrace.getInstance()?.close();
  }, []);

  return <Component {...pageProps} />;
}

export default MyApp;

Advanced Options

typescript
// Report all metric changes (not just final values)
AbrovaTrace.getInstance()?.enableWebVitals({
  reportAllChanges: true,
});

// Custom batch interval (default: 5000ms): vitals are sent this long after
// the last metric arrives, and also when the page is hidden or unloaded
AbrovaTrace.getInstance()?.enableWebVitals({
  batchInterval: 10000, // 10 seconds
});

Data Structure#

Web Vitals data is reported with the following structure:

typescript
interface WebVitalsData {
  pageUrl: string;           // Full page URL
  pageRoute?: string;        // Route path (e.g., /dashboard)

  // Core Web Vitals
  lcpMs?: number;            // Largest Contentful Paint
  cls?: number;              // Cumulative Layout Shift
  inpMs?: number;            // Interaction to Next Paint
  ttfbMs?: number;           // Time to First Byte
  fcpMs?: number;            // First Contentful Paint

  // Context
  deviceType?: string;       // 'mobile' | 'tablet' | 'desktop'
  connectionType?: string;   // from Navigator API (4g, 3g, etc.)
  sessionId?: string;        // Per page-load ID from the Web Vitals tracker (not getSessionId())
  platform: 'nextjs';
  environment?: string;      // production, staging
  releaseVersion?: string;   // App version
}

Dashboard View#

In Abrova Console, Abrova Trace → Performance shows Web Vitals in a dedicated card: the 75th percentile (p75) of each metric over the selected period, rated Good / Needs improvement / Poor with the thresholds above.

Core Web Vitals Card

LCP
1.8s
Good
INP
120ms
Good
CLS
0.15
Needs improvement
FCP
1.2s
Good

Improving Your Scores#

Improve LCP

  • • Optimize and compress images
  • • Use a CDN for static assets
  • • Preload critical resources
  • • Minimize render-blocking JavaScript

Improve INP

  • • Break up long JavaScript tasks
  • • Use web workers for heavy computation
  • • Optimize event handlers
  • • Defer non-critical JavaScript

Improve CLS

  • • Always include size attributes on images
  • • Reserve space for dynamic content
  • • Avoid inserting content above existing content
  • • Use transform animations instead of layout changes

Best Practices#

Enable Early

Enable Web Vitals tracking as early as possible in your app lifecycle for accurate measurements

Use Production Data

Web Vitals are most meaningful from real production users — development data may be skewed

Monitor by Route

Track Web Vitals per route/page to identify which pages need optimization

Track Over Time

Use the dashboard trends to see how deployments affect performance

Focus on INP

INP is the Core Web Vital for interactivity — prioritize improving responsiveness

Set Realistic Goals

Aim for "Good" thresholds on 75th percentile of page loads

Was this page helpful?
Report a problem