Easily measure performance metrics in JavaScript
—
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).
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:
first-contentful-paint entryMeasures 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:
performance.timing for older browsersThe 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;
}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);
}
});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