Skip to content
WL Tech Logo

How to Fix INP (Interaction to Next Paint) - The Plain English Guide

Christopher Welshby Christopher Welshgeneral2522 words

How to Fix INP (Interaction to Next Paint) - The Plain English Guide

I'll be honest with you. Of all the Core Web Vitals, INP catches the most business owners off guard. I've run hundreds of audits through WL Tech, and the pattern is always the same: the site was passing Google's page experience signals for years, nothing changed, and suddenly it's failing. No redesign, no new plugin, no obvious cause. Just a new metric that replaced an old one.

That metric is INP, or Interaction to Next Paint. It became a Core Web Vital in March 2024, replacing an older metric called FID. The reason so many sites that were previously fine are now failing is simple: INP is far stricter than what came before it.

If you want broader context, my Core Web Vitals overview covers all three metrics. This post is specifically about INP, why it matters, and what to do about it.

What is INP?

INP measures how quickly your web page responds when a user interacts with it. An interaction is any tap, click, or key press. The clock starts the moment the user does something and stops when the browser paints the next frame showing a visible response to that action.

So if a visitor taps a "Buy Now" button on their phone, INP measures the gap between that tap and the moment they see something change on screen. A button lighting up, a menu opening, a form submitting. Whatever the expected response is, INP is timing how long it takes to appear.

Google takes all the interactions during a page visit and uses the worst one (roughly the 98th percentile) as the INP score. They then aggregate those scores across all real visitors over a 28-day period.

The thresholds are straightforward:

  • Under 200 milliseconds is good
  • 200 to 500 milliseconds needs improvement
  • Over 500 milliseconds is poor

For context, 200 milliseconds is about a fifth of a second. It's fast enough that the response feels instant to most people. 500 milliseconds is half a second, which is long enough that users notice a lag. Anything over that and the page starts to feel broken or sluggish.

Why INP replaced FID

The metric INP replaced was called FID, or First Input Delay. FID had been a Core Web Vital since 2020, and it measured something very specific: the delay between a user's first interaction and the moment the browser started processing it.

The problem with FID is that it only measured the first interaction. If your page loaded slowly but the user's first click was handled quickly, FID would report a good score even if every subsequent interaction was painfully slow. You could have a page where the first tap works fine but the second, third, and fourth taps all take a full second to respond, and FID would say "all good here."

Google acknowledged this limitation for years. The Chrome team explained in a 2022 Chromium blog post that FID measured input delay but not processing time or presentation delay. It didn't capture the full picture of responsiveness. A site could pass FID while being genuinely frustrating to use.

INP fixes this by measuring all interactions throughout the page's entire lifetime. Every click, every tap, every keystroke gets timed. The worst interaction determines your score. This gives a much more accurate picture of how your site actually feels to real users.

That's why sites that were passing under FID are now failing under INP. The old metric was lenient. The new one isn't.

What causes a poor INP score

INP problems almost always come down to one thing: the browser's main thread is busy when the user tries to interact. Your browser has a single main thread that handles JavaScript, layout, painting, and user input. If that thread is tied up running a long JavaScript task when a user taps a button, the tap has to wait. That waiting time is your INP score going up.

Here are the specific causes I see most often in audits.

Long JavaScript tasks blocking the main thread

When a JavaScript task runs for more than 50 milliseconds without yielding control back to the browser, Google calls it a "long task." During that time, the browser can't respond to user input. If a 200-millisecond JavaScript task is running when a user clicks something, that click is going to wait at least 200 milliseconds before the browser even starts processing it.

I see this constantly with sites that load large JavaScript bundles and execute everything on page load. Analytics scripts running, frameworks hydrating, polyfills initialising. The main thread is flat out, and any interaction during that window gets queued.

Third-party scripts

This is the biggest culprit for small business sites. Third-party scripts are anything loaded from a domain you don't control: Google Analytics, Facebook Pixel, chat widgets like Intercom or Tawk.to, advertising scripts, booking widgets, social media embeds, A/B testing tools, heatmap trackers.

Each of these scripts adds JavaScript that runs on your main thread. A single chat widget can load 200KB or more of JavaScript and set up event listeners on every element on the page. When you have several of these running simultaneously, the main thread is constantly fighting for breathing room.

In audits I've run, I've seen chat widgets alone add 150 to 300 milliseconds to INP scores because their work collides with user interactions.

Heavy event handlers

An event handler is the code that runs when a user does something. Clicks a button, types in a search box, scrolls a page. If that handler does a lot of work (querying the DOM, sorting large arrays, fetching data synchronously, manipulating large lists), it will take a long time to finish, and the browser won't paint until it's done.

A common example I see on small business sites: a search or filter feature on a product listing page that re-renders all products on every keystroke. If there are 200 products and the handler re-renders the full list on each character typed, each keystroke could take 300 to 800 milliseconds. That's an INP failure.

Large JavaScript bundles

The more JavaScript you ship, the longer it takes to parse, compile, and execute. A 1MB JavaScript bundle (sadly common on modern sites) can take several seconds to fully process on a mid-range mobile device. During that processing, the main thread is blocked and interactions are delayed.

This is particularly bad on mobile. A bundle that processes in 500 milliseconds on a desktop laptop might take 2 to 3 seconds on a budget Android phone. Since Google's CrUX field data is weighted toward mobile, your INP score reflects that slower reality.

Unoptimised content loading on interaction

Sometimes the problem isn't that the handler is slow, but that it triggers a cascade of work. A user clicks a tab, and the handler fetches data, then renders it, then runs a layout calculation, then an animation library kicks in. Each step adds time before the next paint.

I audited a site recently where clicking a product image opened a modal that fetched related products, ran a carousel initialisation script, and triggered a layout shift. The whole chain took 600 milliseconds on mobile.

How to measure INP

This is where it gets nuanced, because INP is measured differently depending on the tool.

PageSpeed Insights

PageSpeed Insights is the tool most business owners know. You type in your URL and get a report with both lab data (from Lighthouse) and field data (from CrUX, the Chrome User Experience Report).

Here's the catch: Lighthouse's lab-based INP is a simulated approximation. It runs in a controlled environment on a single page load and doesn't capture real user interactions over time. It's useful as a starting point, but it's not the number Google uses for ranking. The field data section, which comes from CrUX, is the one that matters.

If your CrUX field data shows a poor INP, that's what Google is seeing. You can read more about how Lighthouse scores work in my Lighthouse scoring guide.

Google Search Console

Search Console is where you'll find the INP data that affects your search rankings. The Core Web Vitals report shows field data aggregated from real Chrome users over the previous 28 days. It groups URLs by status (good, needs improvement, poor) and tells you which pages are failing.

This is the real measure. If Search Console says your INP is poor, real users on real devices are experiencing slow responses. That's the data Google uses as a ranking signal.

Chrome DevTools

For diagnosing the actual cause, Chrome DevTools is the tool I use most. The Performance tab lets you record a session, interact with the page, and see exactly what the main thread was doing during each interaction. You can see long tasks highlighted, identify which scripts are running, and trace the delay from input to paint.

There's also a dedicated INP debugger in the Performance insights panel. It flags interactions exceeding 200 milliseconds and shows the breakdown: input delay, processing time, and presentation delay. This tells you exactly where the time is going.

How to fix INP

Now for the part you came here for. Here are the fixes I apply most often on client sites.

Break up long JavaScript tasks

If a single JavaScript task runs for 200 milliseconds, it blocks the main thread for that entire period. The fix is to break it into smaller chunks and yield to the main thread between them, so the browser can handle any pending user input.

The simplest approach is using setTimeout to break work into smaller pieces, but modern browsers also support scheduler.yield() which is purpose-built for this. If you're using a framework like React or Vue, they generally handle this for you, but custom scripts often don't. The goal is to make sure no single task runs longer than about 50 milliseconds.

Lazy-load third-party scripts

Most third-party scripts don't need to load immediately. Your analytics can wait until after the page is interactive. Your chat widget can load on a delay or when the user scrolls. Your Facebook Pixel can be deferred until the first interaction.

There are a few approaches:

  • Use the defer or async attribute on script tags so they don't block the main thread during page load
  • Load third-party scripts after a delay (for example, 3 seconds after page load)
  • Use a partytown or similar solution to move third-party scripts off the main thread entirely
  • Load chat widgets only when the user indicates intent (clicks a "chat" button or scrolls to the bottom of the page)

I've seen deferring a single chat widget drop INP from 480ms to under 200ms. That's the difference between failing and passing.

Reduce your JavaScript bundle size

Every kilobyte of JavaScript you ship has to be downloaded, parsed, compiled, and executed. The less you ship, the faster your page responds. The most effective technique is code splitting: breaking your JavaScript into smaller files that are loaded only when needed.

If you have a contact form that only appears on one page, don't load its JavaScript everywhere. If you have a complex interactive map on your contact page, load it when the user navigates there, not on the homepage.

Most modern frameworks (Next.js, Astro, SvelteKit) support automatic code splitting. But if you're on WordPress with page builders, you may be loading everything on every page regardless. That's one of the reasons WordPress sites tend to struggle with INP, and it's something I cover in my common website mistakes post.

Optimise event handlers

If an event handler does too much work, it will delay the next paint. Common approaches include debouncing or throttling input handlers so they don't run on every keystroke, caching DOM queries instead of re-querying on every interaction, using requestAnimationFrame for visual updates so they match the browser's paint cycle, and moving expensive calculations to a Web Worker so they run off the main thread.

The key principle: do the minimum work needed to show a visual response, then do the heavier work afterwards. If a user clicks a filter button, show the loading state immediately, then apply the filter. Don't make them wait for the filter to finish before they see any response.

Prioritise the worst interactions

Because INP is based on the worst interaction during a page visit, you don't need to optimise everything. You need to find the slowest interaction and fix that one. Once it's under 200ms, the next-slowest becomes your INP score. Work your way down the list.

This is where Chrome DevTools earns its keep. Record a session, interact with your page the way a real user would, and find the interaction with the longest total duration. That's your target.

INP is a real-user metric

I want to emphasise something that trips up business owners. INP is a field metric. It's measured on real users, on real devices, over real network conditions. You can't fully optimise it sitting at your desk on a fast laptop.

Google's CrUX data comes from millions of Chrome users who opted in to sharing usage data. It's weighted toward mobile. Your INP score reflects their experience, not yours. This is why a site can look fine when you test it on your computer but still show a poor INP in Search Console.

The fix often isn't a full rebuild

Here's the good news. Most INP problems I encounter in audits are fixable without rebuilding the site. The most common fixes, deferring third-party scripts and removing unnecessary JavaScript, are targeted changes that don't require a redesign.

The first step is finding out what your INP score is and which interactions are causing it. If you've seen a drop in search rankings or mobile conversions and you're not sure why, INP is one of the first things I'd check.

You can run a free audit at wltech.pro and I'll show you exactly where your site stands on INP and the other Core Web Vitals, along with what's causing any problems and what it would take to fix them.

If you're working through all three Core Web Vitals, I've written companion guides on how to fix CLS (layout shifts) and how to fix LCP (loading speed). Start with whichever one Search Console says is failing.

Frequently asked questions

What is INP in Core Web Vitals? INP measures how quickly a page responds when a user clicks, taps, or types. It replaced FID as a Core Web Vital in March 2024.

What is a good INP score? Under 200 milliseconds is good. Between 200ms and 500ms needs improvement. Over 500ms is poor.

Why did INP replace FID? FID only measured the first interaction. INP measures all interactions throughout the page's lifetime, giving a more accurate picture of responsiveness.

How do I fix a poor INP score? Break up long JavaScript tasks, defer or lazy-load third-party scripts, reduce JavaScript bundle size, and optimise event handlers so they do less work per interaction.

Want to check your own website?

Run our free 60-second audit to see how your site scores on speed, SEO, and AI visibility.

Start Free Audit →

We use only essential cookies to make this site work - no tracking, no ads. See our privacy policy.