CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web-vitals

Easily measure performance metrics in JavaScript

Pending
Overview
Eval results
Files

additional-web-vitals.mddocs/

Additional Web Vitals

Measurement functions for additional Web Vitals metrics that are useful for performance monitoring and debugging: First Contentful Paint (FCP) and Time to First Byte (TTFB).

Capabilities

First Contentful Paint (FCP)

Measures the FCP value for the current page and calls the callback function once the value is ready. FCP measures loading performance by identifying when the first text or image content becomes visible to users.

/**
 * Calculates the FCP value and calls callback with paint timing data
 * @param callback - Function to receive FCP metric data
 * @param opts - Optional configuration for reporting behavior
 */
function onFCP(callback: (metric: FCPMetric) => void, opts?: ReportOpts): void;

interface FCPMetric extends Metric {
  name: 'FCP';
  entries: PerformancePaintTiming[];
}

Usage Examples:

import { onFCP } from "web-vitals";

// Track FCP timing
onFCP((metric) => {
  console.log('FCP time:', metric.value + 'ms');
  console.log('Rating:', metric.rating);
  
  const paintEntry = metric.entries[0];
  console.log('Paint entry name:', paintEntry.name); // 'first-contentful-paint'
  console.log('Start time:', paintEntry.startTime);
});

// Send FCP data to analytics
onFCP((metric) => {
  gtag('event', 'web_vitals', {
    event_category: 'Performance',
    event_label: 'FCP',
    value: Math.round(metric.value),
    custom_map: { metric_rating: metric.rating }
  });
});

Important Notes:

  • Reports once when first contentful paint occurs
  • Uses Paint Timing API with first-contentful-paint entry
  • Represents when users see first meaningful content
  • Threshold: ≤1.8s (good), 1.8-3s (needs improvement), >3s (poor)

Time to First Byte (TTFB)

Measures the TTFB value for the current page and calls the callback function once the page has loaded. TTFB measures the time from navigation start to when the first byte of the response is received.

/**
 * Calculates the TTFB value and calls callback with navigation timing data
 * @param callback - Function to receive TTFB metric data
 * @param opts - Optional configuration for reporting behavior
 */
function onTTFB(callback: (metric: TTFBMetric) => void, opts?: ReportOpts): void;

interface TTFBMetric extends Metric {
  name: 'TTFB';
  entries: PerformanceNavigationTiming[];
}

Usage Examples:

import { onTTFB } from "web-vitals";

// Track TTFB timing
onTTFB((metric) => {
  console.log('TTFB time:', metric.value + 'ms');
  console.log('Rating:', metric.rating);
  
  const navEntry = metric.entries[0];
  console.log('DNS lookup time:', navEntry.domainLookupEnd - navEntry.domainLookupStart);
  console.log('Connection time:', navEntry.connectEnd - navEntry.connectStart);
  console.log('Request time:', metric.value - navEntry.requestStart);
});

// Break down server response time components
onTTFB((metric) => {
  const navEntry = metric.entries[0];
  
  // Calculate sub-timings
  const dnsTime = navEntry.domainLookupEnd - navEntry.domainLookupStart;
  const connectionTime = navEntry.connectEnd - navEntry.connectStart;
  const requestTime = metric.value - navEntry.requestStart;
  
  console.log('Network breakdown:', {
    dns: dnsTime,
    connection: connectionTime,
    serverResponse: requestTime,
    total: metric.value
  });
});

Important Notes:

  • Waits until page load to ensure all navigation timing properties are available
  • Includes time from navigation start to first response byte
  • Encompasses DNS lookup, connection, and server processing time
  • Fallback to performance.timing for older browsers
  • Threshold: ≤800ms (good), 800-1800ms (needs improvement), >1800ms (poor)

Performance Entry Types

The Additional Web Vitals metrics use specific performance entry types:

/** Paint timing entries for FCP measurement */
interface PerformancePaintTiming extends PerformanceEntry {
  /** For FCP, this will be 'first-contentful-paint' */
  name: string;
  /** Timestamp when the paint occurred */
  startTime: DOMHighResTimeStamp;
}

/** Navigation timing entries for TTFB measurement */
interface PerformanceNavigationTiming extends PerformanceEntry {
  /** Start of DNS lookup */
  domainLookupStart: DOMHighResTimeStamp;
  /** End of DNS lookup */
  domainLookupEnd: DOMHighResTimeStamp;
  /** Start of TCP connection */
  connectStart: DOMHighResTimeStamp;
  /** End of TCP connection */
  connectEnd: DOMHighResTimeStamp;
  /** Start of request */
  requestStart: DOMHighResTimeStamp;
  /** Start of response (TTFB) */
  responseStart: DOMHighResTimeStamp;
  /** End of response */
  responseEnd: DOMHighResTimeStamp;
  /** Activation start for prerendered pages */
  activationStart?: DOMHighResTimeStamp;
}

Usage Patterns

Combining with Core Web Vitals

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

// Comprehensive performance monitoring
const performanceData = {
  fcp: null,
  lcp: null,
  cls: null,
  inp: null,
  ttfb: null
};

onFCP((metric) => performanceData.fcp = metric);
onLCP((metric) => performanceData.lcp = metric);
onCLS((metric) => performanceData.cls = metric);
onINP((metric) => performanceData.inp = metric);
onTTFB((metric) => performanceData.ttfb = metric);

// Send comprehensive report when page becomes hidden
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    sendAnalytics(performanceData);
  }
});

Loading Performance Analysis

import { onFCP, onLCP, onTTFB } from "web-vitals";

// Analyze loading performance stages
onTTFB((metric) => {
  console.log('Server response time:', metric.value + 'ms');
});

onFCP((metric) => {
  console.log('First content visible:', metric.value + 'ms');
});

onLCP((metric) => {
  console.log('Main content loaded:', metric.value + 'ms');
});

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