CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web-vitals

Easily measure performance metrics in JavaScript

Pending
Overview
Eval results
Files

thresholds.mddocs/

Thresholds

Pre-defined threshold constants for determining metric ratings according to Web Vitals standards. These thresholds classify metric values as "good", "needs improvement", or "poor" based on real-world performance data and user experience research.

Capabilities

Threshold Constants

Each Web Vitals metric has associated threshold constants that define the boundaries between performance ratings.

/**
 * CLS thresholds: [0.1, 0.25]
 * - ≤ 0.1: good
 * - 0.1 - 0.25: needs improvement  
 * - > 0.25: poor
 */
const CLSThresholds: MetricRatingThresholds;

/**
 * FCP thresholds: [1800, 3000] (milliseconds)
 * - ≤ 1800ms: good
 * - 1800ms - 3000ms: needs improvement
 * - > 3000ms: poor
 */
const FCPThresholds: MetricRatingThresholds;

/**
 * INP thresholds: [200, 500] (milliseconds)
 * - ≤ 200ms: good
 * - 200ms - 500ms: needs improvement
 * - > 500ms: poor
 */
const INPThresholds: MetricRatingThresholds;

/**
 * LCP thresholds: [2500, 4000] (milliseconds)
 * - ≤ 2500ms: good
 * - 2500ms - 4000ms: needs improvement
 * - > 4000ms: poor
 */
const LCPThresholds: MetricRatingThresholds;

/**
 * TTFB thresholds: [800, 1800] (milliseconds)
 * - ≤ 800ms: good
 * - 800ms - 1800ms: needs improvement
 * - > 1800ms: poor
 */
const TTFBThresholds: MetricRatingThresholds;

type MetricRatingThresholds = [number, number];

Usage Examples

Import and Use Thresholds

import { 
  CLSThresholds, 
  FCPThresholds, 
  INPThresholds, 
  LCPThresholds, 
  TTFBThresholds 
} from "web-vitals";

// Check threshold values
console.log('CLS thresholds:', CLSThresholds);        // [0.1, 0.25]
console.log('FCP thresholds:', FCPThresholds);        // [1800, 3000]
console.log('INP thresholds:', INPThresholds);        // [200, 500]
console.log('LCP thresholds:', LCPThresholds);        // [2500, 4000]
console.log('TTFB thresholds:', TTFBThresholds);      // [800, 1800]

Manual Rating Calculation

Although the Metric.rating property automatically provides ratings, you can manually calculate ratings using the thresholds:

import { LCPThresholds } from "web-vitals";

function calculateRating(value: number, thresholds: MetricRatingThresholds): string {
  if (value <= thresholds[0]) {
    return 'good';
  } else if (value <= thresholds[1]) {
    return 'needs-improvement';
  } else {
    return 'poor';
  }
}

// Example usage
const lcpValue = 3200; // 3.2 seconds
const rating = calculateRating(lcpValue, LCPThresholds);
console.log('LCP rating:', rating); // 'needs-improvement'

Custom Threshold Analysis

import { onLCP, LCPThresholds } from "web-vitals";

onLCP((metric) => {
  const [goodThreshold, poorThreshold] = LCPThresholds;
  
  console.log(`LCP: ${metric.value}ms (${metric.rating})`);
  
  if (metric.rating === 'poor') {
    const improvement = metric.value - poorThreshold;
    console.log(`Need to improve by ${improvement}ms to reach 'needs-improvement'`);
  } else if (metric.rating === 'needs-improvement') {
    const improvement = metric.value - goodThreshold;
    console.log(`Need to improve by ${improvement}ms to reach 'good'`);
  }
});

Threshold-Based Monitoring

import { 
  onCLS, onFCP, onINP, onLCP, onTTFB,
  CLSThresholds, FCPThresholds, INPThresholds, LCPThresholds, TTFBThresholds 
} from "web-vitals";

// Monitor metrics and alert on poor performance
const thresholds = {
  CLS: CLSThresholds,
  FCP: FCPThresholds,
  INP: INPThresholds,
  LCP: LCPThresholds,
  TTFB: TTFBThresholds
};

function monitorMetric(metricName: string, metric: any) {
  const threshold = thresholds[metricName as keyof typeof thresholds];
  
  if (metric.rating === 'poor') {
    console.warn(`⚠️ Poor ${metricName}: ${metric.value} (threshold: >${threshold[1]})`);
    
    // Send alert to monitoring system
    sendAlert({
      metric: metricName,
      value: metric.value,
      rating: metric.rating,
      threshold: threshold[1]
    });
  }
}

// Set up monitoring
onCLS(metric => monitorMetric('CLS', metric));
onFCP(metric => monitorMetric('FCP', metric));
onINP(metric => monitorMetric('INP', metric));
onLCP(metric => monitorMetric('LCP', metric));
onTTFB(metric => monitorMetric('TTFB', metric));

Rating System Details

Rating Categories

Each metric value falls into one of three categories:

  • Good: Represents a great user experience
  • Needs Improvement: Indicates room for optimization
  • Poor: Suggests significant performance issues

Threshold Methodology

The threshold values are based on:

  1. Real-world data from Chrome User Experience Report (CrUX)
  2. User experience research correlating performance with user satisfaction
  3. 75th percentile targets for good performance
  4. Statistical analysis of millions of web pages

Metric-Specific Considerations

CLS (Cumulative Layout Shift)

  • Unit: Unitless score (0 = no shifts, higher = more shifts)
  • Good: ≤ 0.1 (minimal unexpected layout shifts)
  • Poor: > 0.25 (significant visual instability)

FCP (First Contentful Paint)

  • Unit: Milliseconds from navigation start
  • Good: ≤ 1.8s (fast content appearance)
  • Poor: > 3s (slow content appearance)

INP (Interaction to Next Paint)

  • Unit: Milliseconds of interaction latency
  • Good: ≤ 200ms (imperceptible delay)
  • Poor: > 500ms (noticeable delay)

LCP (Largest Contentful Paint)

  • Unit: Milliseconds from navigation start
  • Good: ≤ 2.5s (fast loading of main content)
  • Poor: > 4s (slow loading of main content)

TTFB (Time to First Byte)

  • Unit: Milliseconds from navigation start
  • Good: ≤ 800ms (fast server response)
  • Poor: > 1.8s (slow server response)

Important Notes

Automatic Rating

The Web Vitals library automatically calculates and provides the rating in the metric.rating property, so manual threshold checking is typically unnecessary:

import { onLCP } from "web-vitals";

onLCP((metric) => {
  // Rating is automatically calculated
  console.log('LCP rating:', metric.rating); // 'good', 'needs-improvement', or 'poor'
  
  // No need to manually check thresholds
  // const rating = metric.value <= LCPThresholds[0] ? 'good' : 
  //                metric.value <= LCPThresholds[1] ? 'needs-improvement' : 'poor';
});

Threshold Updates

Threshold values may be updated in future versions of the library to reflect evolving web performance standards and user expectations. Always use the exported constants rather than hardcoding values.

Cross-Metric Analysis

import { onLCP, onCLS, onINP } from "web-vitals";

const metrics = {
  lcp: null as any,
  cls: null as any,
  inp: null as any
};

onLCP(metric => metrics.lcp = metric);
onCLS(metric => metrics.cls = metric);
onINP(metric => metrics.inp = metric);

// Analyze overall page performance
setTimeout(() => {
  const goodMetrics = Object.values(metrics)
    .filter(metric => metric && metric.rating === 'good').length;
    
  const totalMetrics = Object.values(metrics)
    .filter(metric => metric !== null).length;
    
  console.log(`Overall performance: ${goodMetrics}/${totalMetrics} metrics are good`);
}, 5000);

Install with Tessl CLI

npx tessl i tessl/npm-web-vitals

docs

additional-web-vitals.md

attribution.md

core-web-vitals.md

index.md

thresholds.md

tile.json