Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save carefree-ladka/c94e3779ec4afc6bbd07ecf824709eaf to your computer and use it in GitHub Desktop.

Select an option

Save carefree-ladka/c94e3779ec4afc6bbd07ecf824709eaf to your computer and use it in GitHub Desktop.

Web Vitals: A Practical Guide for Modern Web Applications

What Are Web Vitals?

Web Vitals are performance metrics defined by Google to measure real user experience—not just raw speed, but how smooth, responsive, and stable your UI feels to actual users.

image

They quantify:

  • Loading performance — How fast content appears
  • Interactivity — How responsive the UI is to user actions
  • Visual stability — Whether elements jump around unexpectedly
  • Responsiveness — How quickly the UI reacts to interactions
  • Smoothness — Animation and rendering quality

Core Web Vitals (2024–2025)

These metrics directly impact Google's search rankings and user experience scores.

1. LCP — Largest Contentful Paint

"How fast does the main content appear?"

  • Good: ≤ 2.5 seconds
  • What triggers it: The largest visible element—hero image, video thumbnail, main heading, or text block
  • Why it matters: Users form first impressions within seconds. Slow LCP = high bounce rates

Common causes of poor LCP:

  • Large, unoptimized images
  • Slow server response times
  • Render-blocking JavaScript and CSS
  • Client-side rendering delays

2. INP — Interaction to Next Paint

"How fast does the UI respond after a user interacts?"

  • Good: ≤ 200 milliseconds
  • Replaced: FID (First Input Delay) in 2024
  • Measures: Time from user interaction to visual feedback
  • Critical for: Apps with buttons, form inputs, drag-and-drop, media controls

What affects INP:

  • Long-running JavaScript tasks
  • Heavy event handlers
  • Slow React renders
  • Main thread blocking

3. CLS — Cumulative Layout Shift

"Does the layout jump around unexpectedly?"

  • Good: ≤ 0.1
  • Measures: Unexpected layout shifts during page load
  • Causes: Images without dimensions, dynamically injected content, web fonts, ads

How to fix:

  • Set explicit width/height on images and videos
  • Reserve space for dynamic content
  • Use font-display: swap carefully
  • Avoid inserting content above existing content

Supplemental Web Vitals

While not part of Core Web Vitals, these metrics provide deeper insights:

4. FCP — First Contentful Paint

When the first text or image renders on screen.

5. TTFB — Time To First Byte

Measures server responsiveness and network latency.

6. TTI — Time to Interactive

How long before the page becomes fully interactive.

7. Animation Performance

Measured via:

  • FPS: Target 60fps for smooth animations
  • RequestAnimationFrame timing
  • JavaScript long tasks (>50ms blocks main thread)

Real-World Application: Video Player (YouTube)

Critical Web Vitals for Video Players

1. LCP — High Priority ⭐⭐⭐

Users expect immediate visual feedback when landing on a video page.

What affects LCP:

  • Video thumbnail load time
  • Hero image optimization
  • Player container initialization
  • Player JavaScript bundle size
  • Video title and metadata rendering

Optimization strategies:

// Preload critical resources
<link rel="preload" href="video-thumbnail.jpg" as="image">
<link rel="preload" href="player.js" as="script">

// Use responsive images
<img 
  src="thumb-800.jpg" 
  srcset="thumb-400.jpg 400w, thumb-800.jpg 800w"
  sizes="(max-width: 600px) 400px, 800px"
  width="800" 
  height="450"
/>

2. INP — Very High Priority ⭐⭐⭐

Every control interaction must feel instant.

Key interactions:

  • Play/Pause button
  • Seek bar scrubbing
  • Volume adjustment
  • Quality switching
  • Fullscreen toggle
  • Speed controls

Common pitfalls:

// ❌ Bad: Heavy computation blocks main thread
playButton.addEventListener('click', () => {
  processAnalytics(); // Blocks for 150ms
  video.play();
});

// ✅ Good: Defer non-critical work
playButton.addEventListener('click', () => {
  video.play();
  requestIdleCallback(() => processAnalytics());
});

3. CLS — Medium Priority ⭐⭐

Video pages often suffer from layout shifts.

Common shift causes:

  • Ad injection
  • Recommended videos loading
  • Comments section appearing
  • Font loading
  • Dynamic UI elements

Prevention:

/* Reserve space for video player */
.video-container {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #000;
}

/* Reserve space for ads */
.ad-slot {
  min-height: 250px;
  background: #f0f0f0;
}

4. Smoothness — Very High Priority ⭐⭐⭐

Essential for premium viewing experience.

Critical animations:

  • Progress bar rendering (60fps)
  • Control panel fade in/out
  • Fullscreen transitions
  • Quality switch transitions
  • Buffer loading indicators

Performance monitoring:

// Track frame drops
let lastTime = performance.now();
function checkFrameRate() {
  const currentTime = performance.now();
  const delta = currentTime - lastTime;
  
  if (delta > 16.67 * 2) { // Missed frames
    console.warn('Frame drop detected:', delta);
  }
  
  lastTime = currentTime;
  requestAnimationFrame(checkFrameRate);
}

YouTube Example Breakdown

Scenario: User clicks a video from search results

Timeline expectations:

Metric Target What Users See
LCP < 2.5s Thumbnail and title visible
INP (Play) < 100ms Video starts immediately after click
CLS < 0.1 No jumping when ads/recommendations load
Smoothness 60fps Smooth progress bar, no stuttering

Additional metrics:

  • Time to First Frame: < 1 second
  • Buffering Frequency: Minimal
  • Seek Latency: < 300ms

Real-World Application: Video Call (Teams/Zoom)

Video conferencing apps have different priorities due to real-time requirements.

Critical Web Vitals for Video Calls

1. INP — Critical Priority ⭐⭐⭐⭐

This is the most important metric for call applications.

Essential interactions:

  • Mute/unmute toggle
  • Camera on/off
  • Screen sharing start/stop
  • Participant switching
  • Chat panel opening
  • Reactions/emoji
  • Background blur toggle

Why it's critical:

  • Users interact constantly during calls
  • Any lag > 200ms feels broken
  • Affects perceived call quality
  • Impacts professional credibility

Optimization example:

// ✅ Optimized mute handler
function handleMute() {
  // Immediate visual feedback
  updateMuteButtonUI();
  
  // Async audio processing
  audioStream.getAudioTracks()[0].enabled = false;
  
  // Defer analytics
  queueMicrotask(() => {
    logMuteEvent();
    updateParticipantState();
  });
}

2. Smoothness + Long Tasks — Critical Priority ⭐⭐⭐⭐

Real-time video/audio rendering demands consistent frame rates.

What requires smoothness:

  • Video tile rendering (30-60fps)
  • Audio processing (real-time)
  • WebRTC negotiation
  • Canvas/WebGL rendering for effects
  • Screen share streaming
  • Background blur/replacement

Impact of long tasks (>100ms):

  • Video freezes
  • Audio glitches/crackling
  • Delayed speaker switching
  • Dropped frames
  • Choppy animations

Monitoring approach:

// Detect blocking tasks
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.duration > 50) {
      console.error('Long task detected:', {
        duration: entry.duration,
        startTime: entry.startTime,
        name: entry.name
      });
    }
  }
});

observer.observe({ entryTypes: ['longtask'] });

3. CLS — Medium Priority ⭐⭐

Less critical than video players, but still important.

Potential shift sources:

  • Participant tiles appearing/disappearing
  • Chat panel sliding in
  • Notification banners
  • Screen share mode changes
  • Toolbar repositioning

Best practices:

/* Fixed participant grid */
.participant-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px;
  min-height: 400px; /* Prevent collapse */
}

/* Reserved chat panel space */
.chat-panel {
  position: fixed;
  right: 0;
  width: 300px;
  transform: translateX(100%);
  transition: transform 0.3s;
}

.chat-panel.open {
  transform: translateX(0);
}

4. Network Metrics — Essential

Not standard Web Vitals, but crucial:

  • WebRTC connection time: < 2 seconds
  • STUN/TURN negotiation: < 1 second
  • Packet loss: < 1%
  • Jitter: < 30ms
  • Round-trip time (RTT): < 150ms

Monitoring:

// Track WebRTC stats
peerConnection.getStats().then(stats => {
  stats.forEach(report => {
    if (report.type === 'inbound-rtp' && report.kind === 'video') {
      console.log({
        packetsLost: report.packetsLost,
        jitter: report.jitter,
        framesPerSecond: report.framesPerSecond
      });
    }
  });
});

5. LCP — Medium Priority ⭐⭐

While not the top priority, fast initial load matters.

What to optimize:

  • Call UI loads < 2.5s
  • Video tiles appear quickly
  • Control panel renders immediately
  • Participant list shows fast

Teams/Zoom Example Breakdown

Scenario: Joining a team meeting

Timeline expectations:

Metric Target What Users Experience
LCP < 2.5s Call UI fully visible
INP (Mute) < 100ms Instant mute feedback
INP (Camera) < 200ms Camera toggle responds immediately
Smoothness 30-60fps No video stuttering
Long Tasks < 50ms No audio/video glitches
WebRTC Setup < 2s Connected and streaming

Quick Reference Table

Feature/App Type LCP INP CLS Smoothness Critical Extras
Video Player ⭐⭐⭐ High ⭐⭐⭐ Very High ⭐⭐ Medium ⭐⭐⭐ Very High Buffering time, Seek latency
Video Calls ⭐⭐ Medium ⭐⭐⭐⭐ Critical ⭐⭐ Medium ⭐⭐⭐⭐ Critical WebRTC metrics, Jitter, Long tasks, Packet loss

Measuring Web Vitals

In Development

Chrome DevTools:

// Performance tab → Experience section
// Shows LCP, CLS, INP markers

Web Vitals JavaScript Library:

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

onCLS(console.log);
onINP(console.log);
onLCP(console.log);

In Production

Google Search Console: Shows real user data

Chrome User Experience Report (CrUX): Public dataset of real-world metrics

RUM (Real User Monitoring): Tools like Datadog, New Relic, Sentry


Key Takeaways

  1. Different apps need different priorities: Video players focus on LCP and smooth playback; video calls prioritize INP and real-time responsiveness

  2. INP is often underestimated: It's now more important than FID and directly impacts how "fast" your app feels

  3. Long tasks are the enemy: Any JavaScript execution >50ms blocks the main thread and hurts both INP and smoothness

  4. Measure real users, not just lab data: Synthetic tests don't capture network variability, device diversity, or user behavior patterns

  5. Web Vitals are interconnected: Optimizing one can help or hurt others—balance is key


Interview Tips

When discussing Web Vitals:

  • Always connect metrics to user experience, not just numbers
  • Give specific examples from real products
  • Explain trade-offs (e.g., prefetching improves LCP but increases bandwidth)
  • Mention measurement tools you've used
  • Discuss optimization strategies you've implemented

Sample answer structure:

"In my video player project, we had poor INP scores (~350ms) because our play button handler was doing analytics synchronously. We fixed it by deferring non-critical work with requestIdleCallback, which brought INP down to 80ms. This made the player feel much more responsive, especially on lower-end devices."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment