Mastering Web Performance: Essential Metrics and How to Measure Them

This article explains the key web performance metrics such as FP, FCP, LCP, FID, CLS, and TTI, describes their meanings, when to focus on each, and details how to collect them using APIs like PerformanceObserver, Paint Timing, Largest Contentful Paint, Event Timing, Navigation Timing, and Layout Instability, with code examples.

ELab Team
ELab Team
ELab Team
Mastering Web Performance: Essential Metrics and How to Measure Them

Common Performance Metrics

Earlier we optimized a WebView for speed and stability. To quantify “fast” and “stable”, performance metrics help us understand current performance, bottlenecks, and measure improvement.

Performance metrics are familiar to developers; for example, Lighthouse provides a set of data.

This article answers:

Which performance metrics should be observed and what do they mean?

When should each metric be focused on?

How are the metrics collected?

Common Performance Metrics

First Paint (FP)

First Contentful Paint (FCP)

Largest Contentful Paint (LCP)

First Meaningful Paint (FMP)

First Input Delay (FID)

Cumulative Layout Shift (CLS)

Time to Interactive (TTI)

DOMContentLoaded (DCL)

Load

First Paint (FP)

First paint marks the time when the browser renders the first pixel, often considered the white‑screen time.

First Contentful Paint (FCP)

FCP records the time when any content (text, image, <svg>, or non‑white <canvas>) is rendered on the screen, serving as a first‑screen metric.

FP vs FCP FP: time from start to first render. FCP: time from start to first content render, which is more critical for users. FP and FCP may overlap.

Largest Contentful Paint (LCP)

LCP measures when the largest element (usually core content such as an image or text block) finishes loading; it is an SEO‑related metric.

LCP vs FCP FCP captures early loading; if a page shows a loading state, FCP may look good but does not reflect when real content appears. LCP focuses on the time the core content becomes visible, which is more relevant to users.

First Meaningful Paint (FMP)

FMP is the time when meaningful content is first painted, typically after the largest layout shift. It was deprecated in Lighthouse 6.0 due to complexity and accuracy issues.

LCP vs FMP FMP was an early recommended metric but is harder to calculate and less accurate. LCP is supported by APIs, easier to collect, though it may not always represent the most important content.

First Input Delay (FID)

FID records the delay between a user's first interaction (e.g., click, keydown) and the time the browser actually begins processing the event handler.

The delay usually occurs because the main thread is busy executing other tasks such as large JavaScript files.

Cumulative Layout Shift (CLS)

CLS accumulates layout‑shift scores throughout a page’s lifecycle; the highest‑scoring session defines the CLS value, reflecting visual stability.

Poor CLS harms user experience.

Core Web Vitals (May 2020) include LCP, FID, and CLS, which affect SEO.

Time to Interactive (TTI)

TTI is the time from page start until the page becomes fully interactive, typically after all resources are loaded and the main thread is idle.

Long Task: any task longer than 50 ms blocks the main thread, causing perceived lag when it exceeds 100 ms.

DOMContentLoaded (DCL)

DCL fires when the DOM is fully parsed, without waiting for external resources.

Load

Load fires when the page and all its dependent resources (stylesheets, images, etc.) have finished loading.

User‑Centric Metrics

Traditional metrics like Load/DCL measure fixed points in the page lifecycle but may not reflect actual user experience. User‑centric metrics such as FCP, LCP, FMP, FID, CLS, and TTI focus on perceived performance from the user’s perspective.

Data Collection Methods

Performance data can be gathered as Lab Data (synthetic monitoring) or Field Data (real‑user monitoring, RUM).

Lab Data / SYN

Collected under controlled conditions (specific device, network) to evaluate performance before release.

Field Data / RUM

Collected from real users, reflecting diverse devices and networks; requires some code instrumentation.

RAIL Model

RAIL stands for Response, Animation, Idle, Load. Google’s model defines performance goals for each phase.

Response: respond within 50 ms.

Animation: render a frame within 10 ms.

Idle: maximize idle time.

Load: deliver content and become interactive within 5 s.

How Metrics Are Collected

Performance Observer API

Provides access to various timing APIs.

Paint Timing API (FP, FCP)

Largest Contentful Paint API (LCP)

Event Timing API (FID)

Navigation Timing API (Load, DCL)

Layout Instability API (CLS)

Long Tasks API & Resource Timing API (used for TTI)

Paint Timing API

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('FCP: ', entry.startTime);
  }
}).observe({type: 'first-contentful-paint', buffered: true});

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('FP: ', entry.startTime);
  }
}).observe({type: 'first-paint', buffered: true});

Largest Contentful Paint API

new PerformanceObserver(entryList => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP: ', entry.startTime);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});

Event Timing API

new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    const FID = entry.processingStart - entry.startTime;
    console.log('FID:', FID);
  }
}).observe({type: 'first-input', buffered: true});

Navigation Timing API

new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    const Load = entry.loadEventStart - entry.fetchStart;
    console.log('Load:', Load);
  }
}).observe({type: 'navigation', buffered: true});

new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    const DCL = entry.domContentLoadedEventStart - entry.fetchStart;
    console.log('DOMContentLoaded:', DCL);
  }
}).observe({type: 'navigation', buffered: true});

Layout Instability API

let sessionEntries = [];
let sessionValue = 0;
let metric = {value: 0};

new PerformanceObserver(entryList => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      const firstSessionEntry = sessionEntries[0];
      const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
      if (sessionValue && entry.startTime - lastSessionEntry.startTime < 1000 && entry.startTime - firstSessionEntry.startTime < 5000) {
        sessionValue += entry.value;
        sessionEntries.push(entry);
      } else {
        sessionValue = entry.value;
        sessionEntries = [entry];
      }
      if (sessionValue > metric.value) {
        metric.value = sessionValue;
        metric.entries = sessionEntries;
        console.log('CLS: ', metric);
      }
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Long Tasks & Resource Timing (for TTI)

TTI calculation: start from FCP, find a quiet window of at least 5 s without long tasks and with at most two concurrent network GET requests, then locate the last long task before that window; TTI is the end time of that task, or equals FCP if none found.

Industry Tools for Collecting Metrics

In the Lab

Chrome DevTools

Lighthouse

WebPageTest

In the Field

web‑vitals library

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance metricscore web vitals
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.