Understanding INP: The Complete Guide to Interaction to Next Paint

Understanding INP: The Complete Guide to Interaction to Next Paint

Master Interaction to Next Paint (INP), the Core Web Vital that replaced FID. Learn about INP's history, how it measures responsiveness, why FID was retired, and how to optimize your INP score.

Understanding INP: The Complete Guide to Interaction to Next Paint

What is Interaction to Next Paint (INP)?

Interaction to Next Paint (INP) is a Core Web Vital that measures page responsiveness. Specifically, it tracks the latency between when a user interacts with your page (clicking, tapping, or pressing a key) and when the browser displays the visual feedback of that interaction.

Think of it this way: when you click a button on a website, you expect something to happen immediately. INP measures how long it takes from your click until you see the response. If there’s a noticeable delay, the site feels sluggish and unresponsive.

Unlike its predecessor FID (First Input Delay), which only measured the first interaction, INP measures all interactions throughout the user’s session and reports a value that represents the overall responsiveness of the page.

What Counts as an Interaction?

INP considers these types of user interactions:

  • Clicks (mouse or trackpad)
  • Taps (touchscreen devices)
  • Key presses (physical or on-screen keyboards)

Not included:

  • Scrolling
  • Hovering
  • Pinch-to-zoom
  • Mouse movement

These excluded interactions are typically handled differently by browsers and don’t have discrete “start” and “end” points that can be measured reliably.

The Three Phases of an Interaction

Every interaction INP measures consists of three phases:

  1. Input Delay - Time from when the user interacts until event handlers start running
  2. Processing Time - Time spent running event handlers
  3. Presentation Delay - Time from when handlers complete until the browser paints the result

Total INP = Input Delay + Processing Time + Presentation Delay

INP Thresholds

RatingLatency
Good≤ 200 milliseconds
Needs Improvement200 - 500 milliseconds
Poor> 500 milliseconds

To provide a good experience, Google recommends that the 75th percentile of page visits have an INP of 200 milliseconds or less.

The History of Responsiveness Metrics

The Early Days: No Standard Metric

In the early web, there was no standard way to measure how responsive a page felt. Developers relied on subjective testing or crude measurements like “time to interactive,” which had various definitions.

First Input Delay (FID): 2018-2024

Introduction (2018)

Google introduced First Input Delay in 2018 as part of their early web vitals work. FID measured the delay between a user’s first interaction and when the browser could begin processing that interaction.

The Promise of FID

FID was innovative because it:

  • Focused on real user experience, not synthetic benchmarks
  • Could be measured with minimal performance overhead
  • Correlated with user frustration from unresponsive pages

FID Becomes a Core Web Vital (2020)

When Google announced Core Web Vitals in May 2020, FID was chosen as the responsiveness metric alongside LCP and CLS.

FID Thresholds:

  • Good: ≤ 100ms
  • Needs Improvement: 100-300ms
  • Poor: > 300ms

The Limitations of FID

As websites evolved and the Chrome team gathered more data, FID’s limitations became apparent:

Problem 1: Only Measures First Interaction

FID only captured the very first interaction. If a user’s first click was responsive but subsequent interactions were slow, FID wouldn’t reflect that. Users might have a great FID but a terrible overall experience.

Problem 2: Ignored Processing Time

FID measured only the delay before handlers ran, not how long the handlers themselves took. A page could have a great FID but still feel sluggish if the event handlers were slow.

Problem 3: Ignored Presentation Delay

FID didn’t account for time between when handlers finished and when the visual update appeared. Complex DOM changes or forced layout recalculations weren’t captured.

Problem 4: Many Sites Had “Perfect” FID

By 2023, over 90% of sites had good FID scores. This sounds positive, but it meant FID was no longer differentiating between truly responsive and merely adequate sites.

Total Blocking Time (TBT): A Lab Alternative

While FID was the field metric, developers used Total Blocking Time (TBT) in lab environments. TBT measures the total time the main thread was blocked during page load. While useful, TBT didn’t measure actual user interactions.

INP Development (2022-2024)

May 2022: INP Introduced as Experimental

Google announced INP as an experimental metric, available in Chrome UX Report and web-vitals library. They encouraged developers to start measuring and optimizing for it.

Design Goals for INP:

  1. Measure ALL interactions, not just the first
  2. Include the full interaction latency (delay + processing + presentation)
  3. Report a single value representing overall responsiveness
  4. Be measurable in the field with low overhead

February 2024: INP Promoted to Pending

Google announced INP would replace FID as a Core Web Vital in March 2024, giving developers a month to prepare.

March 12, 2024: INP Becomes Core Web Vital

INP officially replaced FID. All Core Web Vitals tools, reports, and ranking signals now use INP instead of FID.

Why the 200ms Threshold?

Research shows that delays under 100ms feel instantaneous to users. Between 100-300ms, users notice the delay but don’t lose their sense of cause and effect. Beyond 300ms, the delay becomes frustrating.

Google chose 200ms as the “good” threshold because:

  • It provides buffer for the full interaction lifecycle
  • It’s achievable for well-optimized sites
  • It correlates with positive user experience metrics

Why INP Matters

Real-World Responsiveness

INP captures what users actually experience. A site might look fast on paper but feel sluggish in practice. INP reveals these hidden responsiveness problems.

Business Impact

Poor responsiveness directly affects business metrics:

Bing Study: A 100ms increase in page latency resulted in a 0.6% decline in revenue.

Amazon: Found that every 100ms of latency cost them 1% in sales.

Google Research: Pages with better INP scores have lower bounce rates and longer session durations.

Competitive Advantage

Many sites that passed FID will fail INP. This reset creates opportunities for sites that optimize proactively.

SEO Ranking Signal

INP is now part of Core Web Vitals, which influences Google rankings. While not the most important factor, it can be a tiebreaker between otherwise equal pages.

How INP is Calculated

The Measurement Process

  1. Every interaction is measured - Each click, tap, or keypress is tracked
  2. Full latency is captured - Input delay + processing + presentation
  3. Worst interaction is identified - Usually the slowest interaction
  4. Statistical adjustment - For pages with many interactions, an “almost worst” value is used

The 75th Percentile

INP reports the 75th percentile of interaction latencies. This means:

  • 75% of users experience this latency or better
  • It accounts for outliers and slow networks
  • It represents what most users actually experience

High Interaction Pages

For pages with many interactions (like complex web apps), INP uses a slight adjustment to avoid being overly influenced by single outliers. Specifically, for every 50 interactions, one additional slow interaction is ignored.

Common Causes of Poor INP

1. Long JavaScript Tasks

The browser’s main thread can only do one thing at a time. Long JavaScript tasks block the thread and delay interaction handling.

Symptoms:

  • Long tasks (>50ms) visible in DevTools Performance panel
  • High Total Blocking Time
  • Visible delay after clicking

Solutions:

  • Break long tasks into smaller chunks using setTimeout or requestIdleCallback
  • Move work off the main thread with Web Workers
  • Defer non-critical JavaScript

2. Heavy Event Handlers

Event handlers that do too much work cause high processing time.

Symptoms:

  • Event listeners with expensive operations
  • DOM manipulations in handlers
  • Synchronous API calls

Solutions:

  • Optimize event handler code
  • Use virtualization for large lists
  • Debounce or throttle frequent events
  • Move expensive operations to Web Workers

3. Excessive DOM Size

Large DOM trees make updates expensive and increase presentation delay.

Symptoms:

  • 1500 DOM elements

  • Deep nesting (>32 levels)
  • Slow layout calculations

Solutions:

  • Reduce DOM size
  • Use virtualization for long lists
  • Simplify nested structures
  • Avoid inline styles that trigger layout

4. Forced Synchronous Layouts

Reading layout properties after making style changes forces the browser to recalculate layout immediately.

Symptoms:

Solutions:

  • Batch DOM reads and writes
  • Use CSS transforms instead of layout properties
  • Avoid offsetWidth, offsetHeight in loops

5. Third-Party Scripts

External scripts can block the main thread unexpectedly.

Symptoms:

  • Third-party scripts in flame charts during interactions
  • Analytics or ad scripts running during user actions

Solutions:

  • Audit third-party scripts
  • Load non-critical scripts asynchronously
  • Use Partytown or similar for off-main-thread execution

Optimizing INP: Proven Strategies

Break Up Long Tasks

// Before: One long task
function processAllItems(items) {
  items.forEach(item => processItem(item)); // Blocks for entire duration
}

// After: Yield to the browser periodically
async function processAllItems(items) {
  for (const item of items) {
    processItem(item);

    // Yield every 5ms to allow interactions
    if (performance.now() - startTime > 5) {
      await scheduler.yield(); // Chrome 129+
      // Or: await new Promise(resolve => setTimeout(resolve, 0));
      startTime = performance.now();
    }
  }
}

Use scheduler.yield() (Modern Browsers)

async function handleClick() {
  // Do critical work first
  updateButtonState();

  // Yield to let the browser paint
  await scheduler.yield();

  // Continue with less critical work
  sendAnalytics();
  updateRelatedContent();
}

Optimize Event Handlers

// Before: Heavy handler
button.addEventListener('click', async () => {
  const data = await fetchData();           // Network delay
  processAllData(data);                      // Heavy processing
  renderResults(data);                       // Heavy DOM updates
});

// After: Optimized handler
button.addEventListener('click', async () => {
  // Immediate visual feedback
  button.classList.add('loading');

  // Move heavy work off main thread
  const worker = new Worker('/process-worker.js');
  const data = await fetchData();
  worker.postMessage(data);

  worker.onmessage = (e) => {
    // Efficient rendering
    requestAnimationFrame(() => {
      renderResults(e.data);
      button.classList.remove('loading');
    });
  };
});

Virtualize Long Lists

// Before: Render all items
function renderList(items) {
  items.forEach(item => {
    const el = createItemElement(item);
    container.appendChild(el);
  });
}

// After: Only render visible items
// Use libraries like react-window, vue-virtual-scroller, or lit-virtualizer
import { FixedSizeList } from 'react-window';

<FixedSizeList
  height={500}
  itemCount={items.length}
  itemSize={50}
>
  {({ index, style }) => (
    <div style={style}>{items[index].name}</div>
  )}
</FixedSizeList>

Debounce Frequent Interactions

// Debounce search input
const debouncedSearch = debounce(performSearch, 300);
searchInput.addEventListener('input', debouncedSearch);

function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

Use CSS for Animations

/* Avoid: JavaScript-driven animations that block main thread */

/* Use: CSS animations with GPU-accelerated properties */
.animated {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.animated:hover {
  transform: scale(1.1);
  opacity: 0.8;
}

Measuring and Debugging INP

Tools for INP Analysis

Chrome DevTools

  1. Performance panel: Record user interactions
  2. Look for long tasks during interactions
  3. Identify slow event handlers

PageSpeed Insights

  • Shows INP in field data (if available)
  • Identifies slow interactions
  • Provides optimization suggestions

Web Vitals Extension

  • Real-time INP measurement
  • Shows INP for each interaction
  • Highlights the slowest interaction

Using the web-vitals Library

import {onINP} from 'web-vitals';

onINP(metric => {
  console.log('INP:', metric.value, 'ms');
  console.log('Interaction type:', metric.entries[0]?.name);

  // Send to analytics
  sendToAnalytics({
    name: 'INP',
    value: metric.value,
    rating: metric.rating, // 'good', 'needs-improvement', 'poor'
    interaction: metric.entries[0]?.name,
  });
});

The Interaction Timeline

When debugging a slow interaction, look for:

  1. Input delay - Is the main thread blocked when user clicks?
  2. Event handler - Is the handler code itself slow?
  3. Style/Layout - Is the browser recalculating styles?
  4. Paint - Is painting taking too long?

INP Debugging Checklist

  • Use the web-vitals library to measure INP in production
  • Identify your slowest interactions using DevTools
  • Check for long tasks (>50ms) during interactions
  • Review event handler code for heavy operations
  • Look for forced synchronous layouts
  • Audit third-party scripts blocking the main thread
  • Check DOM size and complexity
  • Test on real mobile devices, not just desktop
  • Use Chrome’s Performance panel Interactions track

Migrating from FID to INP

Key Differences

AspectFIDINP
Interactions measuredFirst onlyAll
What’s measuredInput delay onlyFull latency
”Good” threshold≤100ms≤200ms
Typical site scoreUsually goodOften needs work

If You Had Good FID

Don’t assume you’ll have good INP. Many sites that passed FID fail INP because:

  • Subsequent interactions are slower than the first
  • Processing and presentation time weren’t captured by FID
  • Complex interactions reveal responsiveness issues

Prioritization Strategy

  1. Find your worst interactions - Use field data and DevTools
  2. Focus on common interactions first - Buttons, links, form inputs
  3. Address the biggest delays - Long tasks, heavy handlers
  4. Test on representative devices - Mobile phones are often worse

Common INP Mistakes to Avoid

1. Only Testing the First Interaction

Unlike FID, INP considers all interactions. Test scrolling, clicking multiple buttons, filling forms, not just the first action.

2. Ignoring Mobile Performance

Mobile devices have slower processors. An interaction that feels instant on desktop might be sluggish on mobile.

3. Blocking on Analytics

Sending analytics synchronously during interactions adds delay. Always send analytics asynchronously or defer it.

4. Not Using Browser Scheduler APIs

Modern browsers offer scheduler.yield() and scheduler.postTask() to help manage main thread work. Use them.

5. Over-Relying on Virtualization

Virtualization helps with long lists but adds complexity. Sometimes simplifying the DOM is better than adding virtualization overhead.

Conclusion

Interaction to Next Paint represents a significant evolution in how we measure web responsiveness. By capturing the full lifecycle of all interactions, not just the first, INP provides a much more accurate picture of how users experience your site.

The transition from FID to INP is an opportunity. Sites that invest in responsiveness optimization now will gain advantages as competitors struggle to meet the new standard.

Remember: responsiveness isn’t just about metrics. Every millisecond of delay is friction between your users and their goals. Fast interactions build trust, encourage engagement, and create the kind of smooth experiences that keep users coming back.

FAQs

1. What’s a good INP score? 200 milliseconds or less is “good.” Between 200-500ms needs improvement, and over 500ms is poor.

2. Why did my INP get worse when FID was replaced? INP measures more interactions and more of each interaction’s lifecycle. Sites that passed FID often reveal hidden responsiveness problems under INP.

3. How is INP different from TBT (Total Blocking Time)? TBT measures main thread blocking during page load in lab conditions. INP measures actual interaction latency from real users throughout their session.

4. Can I still measure FID? Yes, for historical comparison, but FID is no longer a Core Web Vital and isn’t used in rankings.

5. Why does my INP vary between visits? INP depends on which interactions users perform, device capability, and network conditions. Field data shows the 75th percentile to account for this variation.

6. Should I optimize for the worst interaction or average? Focus on your worst common interactions first. The 75th percentile means most users encounter your slowest interactions, so improving them has the biggest impact.

// SYS.FOOTER