Skip to main content
Engineering7 min readMarch 3, 2026

Frontend Performance: The Metrics That Matter and How to Hit Them

Frontend performance is not just about speed — it's about the specific metrics that affect user experience and search rankings. Here's how to measure, diagnose, and hit your targets.

James Ross Jr.

James Ross Jr.

Strategic Systems Architect & Enterprise Software Developer

The Metrics That Define Frontend Performance

"Make it faster" is not an actionable goal. "Get LCP under 2.5 seconds for the 75th percentile of users" is an actionable goal. Frontend performance work requires specific, measurable targets before it can be systematically pursued.

The metrics that matter in production:

Largest Contentful Paint (LCP): When does the user first see the main content? Target: under 2.5 seconds.

Interaction to Next Paint (INP): How responsive are interactions throughout the page lifetime? Target: under 200ms.

Cumulative Layout Shift (CLS): How much does content unexpectedly move while the user is looking at it? Target: under 0.1.

Time to First Byte (TTFB): How fast does the server start sending the HTML? Target: under 800ms. This is the foundation — you can't achieve good LCP without good TTFB.

Total Blocking Time (TBT): A Lighthouse-only metric that approximates main thread blockage during page load. Target: under 200ms. High TBT is the leading indicator of poor INP.

Understanding which metric is failing on your specific page is the prerequisite to fixing it. Throwing generic optimization advice at a poor INP score won't help if the root cause is a large contentful paint that's timing out.


The Performance Measurement Stack

Lighthouse: Run it in Chrome DevTools (incognito window, simulated throttling) for on-demand lab measurement. Lighthouse gives you a simulated user on a "Moto G4-equivalent" device with a slow 4G connection — which is intentionally conservative. Passing Lighthouse in lab conditions is necessary but not sufficient.

PageSpeed Insights: Combines Lighthouse lab data with Chrome User Experience Report (CrUX) field data for your URL. The field data is what Google actually uses for ranking. If lab and field diverge significantly, investigate why — sometimes the page behaves differently in lab conditions than in real-world browser diversity.

Google Search Console (Core Web Vitals tab): Shows URL-level field data directly from Google's real user measurements. This is the authoritative source for your search ranking health.

web-vitals library in production:

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

function sendMetric({ name, value, id }) {
  // Send to your analytics
  fetch('/api/vitals', {
    method: 'POST',
    body: JSON.stringify({ name, value, id, url: location.href })
  })
}

onLCP(sendMetric)
onINP(sendMetric)
onCLS(sendMetric)
onFCP(sendMetric)
onTTFB(sendMetric)

This gives you field data from your actual users, segmented by URL, page type, device type, and connection speed. It's the most honest picture of your performance.


TTFB: The Foundation

Everything starts with TTFB. If your server takes 2 seconds to start responding, LCP can't be under 2.5 seconds regardless of how well everything else is optimized.

Diagnose TTFB: In Chrome DevTools Network tab, click on the HTML document request and look at the "Timing" tab. Time to First Byte is shown explicitly.

Common TTFB causes and fixes:

Slow database queries in the server-side render path. For SSR pages, the server must query the database before it can send the first byte. A slow query = high TTFB. Fix: query optimization, caching, or streaming HTML (send the shell immediately, stream the data).

No caching on the edge. If every HTML request goes to your origin server, you're paying the origin's response time for every request. A CDN that caches HTML at the edge (or serves stale-while-revalidate) can get TTFB under 100ms for cached URLs.

No HTTP/2 or HTTP/3. Older protocols have more connection overhead. Most modern infrastructure supports HTTP/2; enable it if you haven't.


LCP Optimization Checklist

Work through these in order — each one can have a significant impact:

  1. Identify your LCP element. In Chrome DevTools, enable the "Web Vitals" checkbox in the Performance panel, run a recording, and find the LCP mark. Or use PerformanceObserver to log it: new PerformanceObserver((list) => console.log(list.getEntries())).observe({ type: 'largest-contentful-paint', buffered: true }).
  2. Preload the LCP image. If LCP is an image, add <link rel="preload" as="image" href="..." fetchpriority="high"> to the <head>.
  3. Ensure the LCP element is in the initial HTML. If LCP is rendered client-side (React/Vue hydration), the HTML document won't contain the element, and LCP is delayed until JavaScript executes. Use SSR or SSG.
  4. Check image format and size. LCP images should be WebP or AVIF, properly sized for the display size (not 4000px wide for a 1200px container), and served from a CDN.
  5. Eliminate render-blocking scripts. Any <script> without async or defer in the <head> blocks rendering. Audit your script tags.

INP Optimization Checklist

INP problems are almost always long tasks on the main thread. The diagnostic process:

  1. Open Chrome DevTools → Performance tab → enable INP recording.
  2. Click around the page normally for 30 seconds while recording.
  3. Find high INP interactions in the recording. Click on each to see the main thread activity during that interaction.
  4. Identify the long task. What JavaScript is running for more than 50ms during the interaction? Is it in your code, a third-party script, or a framework operation?
  5. Break up long tasks. Use setTimeout(0) or scheduler.yield() to yield to the browser between expensive operations.
  6. Move work off the main thread. For computationally intensive work (data processing, complex calculations), use a Web Worker.
  7. Audit third-party scripts. Google Tag Manager, chat widgets, ad scripts — these run on your main thread and can cause poor INP. Test the page with all third-party scripts disabled to see the baseline.

CLS Optimization Checklist

  1. Set explicit dimensions on all images: width and height HTML attributes, or aspect-ratio in CSS.
  2. Reserve space for dynamic content: Cookie banners, notification bars, embedded ads — add a container with explicit height before they load.
  3. Match fallback font metrics to web fonts: Use size-adjust, ascent-override, descent-override to prevent layout shift from font swaps.
  4. Avoid inserting content above existing content in response to user interactions (unless the user explicitly requests it).
  5. Transition animations: If you're showing/hiding content, use CSS animations that transform opacity and transform (GPU-accelerated) rather than height and margin (which trigger layout).

The Performance Budget

A performance budget is a constraint on your performance metrics that you enforce in CI. Common budgets:

  • Total JavaScript: under 150KB (gzipped)
  • LCP: under 2.5 seconds on simulated slow 4G
  • Lighthouse performance score: over 90
  • No new long tasks over 300ms

Tools like Lighthouse CI, Bundlesize, and webpack's built-in size limits can enforce these budgets in your CI pipeline, failing builds that introduce regressions.


Frontend performance is an ongoing discipline, not a project. The optimizations you make today may be reversed by a new dependency or an unoptimized image six months from now. Build the measurement infrastructure, set the budgets, enforce them in CI, and treat regressions as bugs.

If you're working on a site with poor Web Vitals and want a systematic audit and prioritized fix plan, book a call at calendly.com/jamesrossjr.


Keep Reading