GrowthHasten

Interaction to Next Paint: How to Diagnose and Fix INP

Interaction to Next Paint replaced First Input Delay in March 2024, and unlike its predecessor it measures every interaction, not just the first. This covers the three phases a slow interaction hides in, how to find which one is yours, and why the modern API for fixing it does nothing in Safari.

Anshuman Sinha

Written by Anshuman Sinha

Published August 31, 2026
Updated August 31, 2026
13 min read
Close-up of a hand clicking a computer mouse beside a keyboard

Interaction to Next Paint measures the time between a user clicking, tapping or pressing a key and the browser painting the next frame, and it reports the slowest of those interactions across the whole visit. It became a Core Web Vital on March 12, 2024, when it replaced First Input Delay. Two readers should find it useful: the front-end engineer whose Search Console report gives a failing number and no cause, and the person who has to turn that report into a ticket somebody can work on. It covers the three phases an interaction can stall in, how to get from a field score to a named element, what to change for each phase, and why the modern API for fixing it does nothing at all for your Safari traffic.

The short version

  • Scrolling does not count. Only mouse clicks, touchscreen taps and key presses are measured, so the sluggish scroll your team keeps reporting will never show up in your INP.
  • INP splits into three phases: input delay, processing duration and presentation delay. Which one is slow decides the fix, and a presentation-delay problem is immune to shipping less JavaScript.
  • Good is 200 milliseconds or less, needs improvement runs from there to 500, and anything above 500 is poor. All three bands are read at the 75th percentile.
  • scheduler.yield(), the API Google's own long-tasks guide recommends, is not Baseline and has no Safari support as of August 2026. Neither does the Long Animation Frames API that the field attribution tooling depends on.
  • Safari only gained the ability to report INP at all in December 2025, which is three months after both of Google's canonical INP articles were last updated.

What is a good INP score?

200 milliseconds or less. Google's Interaction to Next Paint reference on web.dev publishes three bands, measured at the 75th percentile of page loads and reported separately for mobile and desktop.

INP at the 75th percentileVerdictWhat it feels like
200 ms or lessGoodThe interface answers before the user notices waiting for it.
Above 200 ms, up to 500 msNeeds improvementA perceptible lag on menus, filters and form controls, worse on mid-range phones.
Above 500 msPoorUsers tap twice because the first tap looked like it did nothing.

Two things about that number surprise people. It is not an average: INP reports the single longest qualifying interaction in the visit, so one slow control can set the score for a page that is otherwise fine. And it is not raw either, because outliers get trimmed before the worst one is chosen.

The three-metric system and the field-versus-lab split belong to the parent piece, our guide to Core Web Vitals. Visual stability has a node of its own, on finding and fixing the element that moves. Everything below is INP only.

Which interactions actually count toward INP?

Three, and only three: a click with a mouse, a tap on a touchscreen, and a press of a key on a physical or onscreen keyboard.

The exclusion list is where teams misread their own data. Hovering, zooming and scrolling are not observed, which means the janky scroll that generates the most internal complaints contributes nothing to the metric. Gestures that happen to contain a qualifying click or tap still count, so a carousel advanced by a tapped arrow does register.

Four details in the specification change how you read a report:

  • An interaction is a group of events, not one: a key press fires keydown, keypress and keyup; a tap fires pointerdown and pointerup. The longest single event duration inside that group is what contributes to the interaction's latency.
  • Outliers are discarded on busy pages: for every 50 interactions on a page, the single highest is ignored. On a text editor or a heavily filtered table, a one-off stall will not set your score. A control that is consistently slow will.
  • Interactions inside iframes count, but the API does not report them: a click on an embedded video player is part of the page experience, yet JavaScript in the parent frame cannot see it. That is a real reason your own monitoring and the Chrome User Experience Report can disagree.
  • Some visits produce no INP at all: a session with no click, tap or key press returns nothing, which is also why crawlers and headless browsers contribute no data.

What are the three phases of an interaction?

Input delay, processing duration and presentation delay, and their sum is the total interaction latency you see in the field. Google's INP optimization guide defines the split, and it is the only frame that turns a number into a decision.

PhaseStarts and endsUsually to blame
Input delayFrom the moment the user acts until the first event callback begins to runA task already holding the main thread: script evaluation during load, a third-party tag, a timer firing on schedule
Processing durationFrom the first callback starting to the last one finishingHandler code doing work the next frame does not need: validation, analytics, state fan-out, synchronous storage writes
Presentation delayFrom the last callback finishing to the next frame appearing on screenRendering cost: a very large DOM, layout thrashing, expensive style recalculation, HTML assembled in JavaScript

The reason this matters is that a fix only ever acts on the phase it targets. Deferring non-critical JavaScript and reducing main-thread work both act on input delay and processing duration. If your problem is presentation delay, neither one moves the number, because by then the callbacks have already finished and the browser is doing layout and paint.

Two definitions worth pinning down while you are here. A long task is any main-thread task that runs longer than 50 milliseconds, and everything above 50 milliseconds counts as that task's blocking period. And field tools do not agree on labels: web.dev calls the middle phase processing duration, while DebugBear's documentation calls the same span processing time. Same measurement, different word, and it is enough to make two reports look like they disagree.

How do you find which interaction is slow?

Four steps, in order, and the first three happen before you open an editor. Skipping to step four is how teams spend a sprint optimizing a phase that was never the problem.

Step 1. Confirm it in the field: enter the URL in PageSpeed Insights to read the Chrome User Experience Report data for that page or origin, and toggle between mobile and desktop. Search Console groups the same data by page type, which is more useful when the failure belongs to a template rather than one URL.

Step 2. Attach attribution to your own monitoring: the attribution build of the web-vitals library, version 4 or later, returns far more than the score. It gives you interactionTarget as a CSS selector pointing at the element that produced the value, such as button#save, plus interactionType, the three phase timings, and Long Animation Frames entries naming the scripts that ran.

Step 3. Read the phase split before writing any code: this is the step that decides everything downstream. A 480 ms interaction that is 380 ms of input delay is a loading and third-party problem. The same 480 ms sitting in presentation delay is a rendering problem in one component.

Step 4. Reproduce it in the Performance panel: with a named selector and a phase, open Chrome DevTools and perform that exact interaction. Do it while the page is still loading as well as after, because the main thread is busiest during load and that is where slow interactions hide.

In our implementation work the phase split is the first thing we read, because it decides whether the next hour goes into the bundle, the event handlers or the component tree. Lab tools cannot hand you that split reliably, and the reasoning behind that lives in the parent guide linked at the top rather than getting repeated here.

What do you change for each phase?

Different work for each, and the mapping is stable enough to treat as a lookup table.

PhaseWhat to changeWhere the fix lives
Input delayBreak up whatever is already running. Split long tasks, cut or delay third-party tags, and reduce the script that has to be parsed and compiled during load.Build configuration and the tag manager
Processing durationLeave only the visual update inside the callback and defer the rest to a later task. Move heavy computation to a web worker where the result is not needed for the frame.Application code, in the event handlers themselves
Presentation delayReduce what the browser must render for that one frame. Shrink the DOM, stop reading styles you just wrote, and use content-visibility to skip off-screen work.Component markup and the CSS layer

The processing-duration fix has a concrete shape that is worth copying. Update the interface first, then push everything else into a later task, which Google's optimization guide does by nesting setTimeout() inside a requestAnimationFrame() callback. Google describes its own pattern as "admittedly a bit esoteric" and recommends it anyway, on the grounds that it works in every browser.

Two of these fixes belong to work we already cover elsewhere. Bundle size and hydration cost sit inside how JavaScript execution affects crawling and rendering, and if you are on React, code splitting and the other performance defaults in Next.js handles a good share of the input-delay side before you tune anything by hand.

One caution on ownership. Input delay is usually fixed by whoever controls the build and the tag list, and that is often not the same person who owns the component with the slow handler. A phase split is therefore also a routing decision, and naming the owner in the ticket saves more time than the code change does.

Does scheduler.yield work everywhere?

No, and the gap is in the browser you can least afford it. scheduler.yield() is the purpose-built API for handing the main thread back mid-task, and its real advantage over setTimeout() is that the continuation of your function is prioritized, so it resumes ahead of unrelated tasks that were queued behind it. Google documents it on its guide to optimizing long tasks, last updated December 2024.

Support, checked on 2026-08-31: Chrome and Edge from version 129, Firefox from 142, and no Safari at all. MDN lists the method as limited availability and explicitly not Baseline, for exactly that reason. Read the current status before you rely on this paragraph, because it is the one fact here designed to expire.

There is a second thing worth knowing about where the documentation sits. Neither of Google's two canonical INP articles mentions scheduler.yield() once: not the metric reference, and not the optimization guide, both last updated on 2025-09-02. The API is documented one page over, on long tasks, and that page has not itself been updated since December 2024. DebugBear, a performance tool vendor whose INP documentation was updated on 2026-08-27 and is more current than Google's on this metric, does name the API in its input-delay section, and does not mention Safari.

Assembled in one place, the support picture across the three APIs an INP workflow touches looks like this:

APIWhat it does for INPStatus as of August 2026
Event Timing, via interactionIdReports INP and the three phase timings in your own monitoringBaseline newly available since December 2025. Every major engine, with Safari 26.2 the last to ship it.
Long Animation FramesAttributes a slow interaction to the specific scripts that ranChromium only, from Chrome and Edge 123. Not Baseline.
scheduler.yield()Yields the main thread with a prioritized continuationChrome and Edge 129, Firefox 142, no Safari. Not Baseline.

Put the three rows together and the shape of the problem is clear. The Chrome User Experience Report is built from Chrome telemetry, so the INP in Search Console never contained a Safari visit in the first place. Since Safari 26.2, your own monitoring can finally measure those visits, which is genuinely new and postdates both of Google's canonical INP articles. You still cannot attribute them to a script, and you cannot fix them with the recommended API.

From my experience the right call, when a meaningful share of traffic is on iOS, is to write the fallback as the default path rather than as a graceful degradation. Feature-detect with globalThis.scheduler?.yield and fall back to a setTimeout() wrapped in a promise, and design your yield points so that correctness never depends on the continuation being prioritized. Browsers without the API still yield; they just yield without the queue-jumping benefit. If your work genuinely cannot tolerate an unprioritized resume, treat the whole thing as an enhancement and do not yield at all in those browsers.

What replaced First Input Delay, and does it change what you fix?

INP replaced First Input Delay on March 12, 2024, and yes, it changes the work substantially.

First Input Delay only timed the gap before the browser started processing the first interaction on a page. In the vocabulary above, it measured one phase of one interaction. Everything after the callback began, all the processing and all the rendering, was invisible to it, and so was every interaction after the first.

The practical consequence is that the old playbook is now one third of the answer. Deferring scripts so the page can respond to the first tap was a complete FID strategy and it is an input-delay-only INP strategy. Two thirds of what INP measures, the handler work and the frame that follows it, were never on the FID checklist at all. If your performance backlog was written before 2024, that is where the stale items are.

When should you stop optimizing INP?

Sooner than most performance backlogs assume. Four honest stopping points:

  • When your 75th percentile is comfortably under 200 ms on mobile: moving 130 ms to 95 ms buys you nothing a user can feel and nothing the metric rewards.
  • When the interaction setting your score is a control almost nobody uses: the value comes from the worst qualifying interaction, so an admin-only toggle can set the score for the entire page. Fix what sits on the path to a signup first, then decide whether the outlier is worth a deploy.
  • When the only remaining fix is replacing your rendering model: rewriting a hydration strategy is a quarter of engineering time. Weigh it against how little page experience contributes on its own. It can separate two comparable pages. It will not rescue one.
  • When you have no field data: stop optimizing and start measuring. Total Blocking Time is a reasonable proxy in a lab tool, and it is not a substitute, because a lab run only reports the interactions your script happened to perform. Some lab tools report no INP at all.

The habit worth building takes less time than any of the fixes: read the phase split before you write a line of code. Without it the natural guess is processing duration, because that is the phase whose fixes are easiest to picture, and a wrong guess costs a sprint on work that was never going to move the number.

This week, run your three highest-traffic templates through PageSpeed Insights and note the mobile INP for each. If any of them sits above 200 ms, deploy the attribution build of web-vitals on that template, so that the next reading arrives with a selector attached instead of a number. If the fix turns out to be architectural rather than a patch, our performance engineering work and our guide to building a search-ready site both start from the same place: the field data, then the phase, then the code.

Need an SEO-Friendly Website?

We design and develop high-performance websites built for users, search engines, and conversions. If a failing INP is a symptom of how the site is built, we can help you judge what to fix and what to rebuild.

Start Your Website Project
FAQ

Frequently Asked Questions

What is a good INP score?

Google documents three bands: 200 milliseconds or less is good, above 200 and up to 500 needs improvement, and above 500 is poor. The score is the longest qualifying interaction in a visit rather than an average, and on pages with many interactions the single highest is discarded for every 50 recorded. Search Console reports it at the 75th percentile, split between mobile and desktop, and the two are worth reading separately because device capability varies far more on mobile.

How do you optimize INP?

Start by finding out which of the three phases is slow, because the fix is different for each. Input delay is fixed in the build and the third-party tag list, processing duration in the event handlers themselves, and presentation delay in the component markup and CSS. Get the phase timings from the attribution build of the web-vitals library, which also names the element that produced the score. Guessing the phase is how INP work gets wasted.

Does the switch from First Input Delay to INP change what you should fix?

Yes, and it widens the work by roughly three times. First Input Delay timed only the gap before the browser began processing the first interaction on a page, so deferring scripts at load was a complete strategy. INP measures every qualifying interaction across the visit and includes the handler execution and the frame that follows it. Any performance backlog written before March 2024 covers one phase of three.

Why can't INP be measured in a lab?

Because the metric needs a real interaction, and a lab run only reports the interactions the test happened to perform. Some lab tools return no INP value at all, since they load the page without touching it. Total Blocking Time is a reasonable proxy for diagnosis but not a substitute for the metric. Use field data to find the problem and the lab to reproduce and explain it.

Does scrolling count toward INP?

No. Only mouse clicks, touchscreen taps and key presses are observed. Scrolling, hovering and zooming are excluded, so a page that scrolls badly can still record a good INP. The one wrinkle is that a gesture containing a qualifying tap, such as advancing a carousel by tapping an arrow, does count. If scroll performance is your complaint, INP is the wrong metric to chase it with.

Can I use scheduler.yield in production?

Only behind a feature check. As of August 2026 it works in Chrome and Edge from version 129 and Firefox from 142, with no Safari support, and MDN lists it as limited availability rather than Baseline. Detect it and fall back to a setTimeout wrapped in a promise, so browsers without it still yield to the main thread. Verify the current support status before shipping, because this is changing.

Share This Article

Anshuman Sinha
Written by

Anshuman Sinha

AI SEO Specialist, GrowthHasten

Anshuman Sinha is an AI SEO Specialist and Computer Science Engineer with over three years of experience in SEO and five years in web development. He specializes in Technical SEO, AI Search Optimization (AEO and GEO), SaaS SEO, and building high-performance websites with modern technologies.

View profile

Stay Ahead Of The Curve

Get the latest SEO insights and growth strategies delivered to your inbox. No spam, just actionable advice.