Talk to Franz

Article

Interaction to Next Paint (INP): how to measure and improve it, with the whitepaper as PDF

INP is the longest delay in a visit between a click, tap or key press and the next painted frame. Below 200 ms is good, above 500 ms is poor. Our 2023 whitepaper shows how to measure and fix it.

INP Artistic Visualisation

Key takeaways

  • Every interaction has three phases: input delay, processing time and presentation delay. JavaScript causes the first two, rendering the third.
  • PageSpeed Insights and Search Console show that you have an INP issue. The web-vitals attribution build shows which interaction it is.
  • JavaScript is the first big factor: break up long tasks and yield to the main thread so the browser can respond.
  • Lighthouse warns above 800 DOM nodes and calls 1,400 excessive.
  • The paper treats the switch from First Input Delay to INP as upcoming, for March 2024.

Holger Guggi and I wrote the whitepaper: 44 pages, dated 29 November 2023. It says INP will replace First Input Delay (FID) as a Core Web Vital in March 2024. Everything below is the paper’s state of knowledge.

INP coming March 2024 Google Core Web Vitals Update

INP counts every interaction, FID only the first

MetricWhat it captures
FIDThe time from the first interaction until the browser starts processing it. Processing and rendering are not measured.
INPThe time from an interaction until the browser displays its result, for all interactions of a visit. The longest one is the INP value.

What counts as an interaction:

  • Clicks, taps and key presses count. Hovering and scrolling do not.
  • Interactions inside iframes count too.
  • INP is calculated when the user leaves the page.

Below 200 ms is good, above 500 ms is poor

INPRating
Below 200 msGood
200 ms to 500 msNeeds improvement
Above 500 msPoor

Scale: web.dev, the paper’s image source.

Three phases, two causes

JavaScript slows the first two phases of an interaction, rendering the third.

PhaseWhat it isCaused by
Input delayFrom the user’s action to the start of the event callbacks. While the main thread is busy, the interaction waits in a queue.JavaScript
Processing timeUntil the event callbacks have completed.JavaScript
Presentation delayUntil the next frame with the visual result is presented.Rendering

Field data finds the problem, the lab reproduces it

Seeing an INP issue is easy. Finding the interaction behind it takes analysis.

  1. Check whether you have an issue. Chrome UX Report data shows it in PageSpeed Insights and in Google Search Console: Core Web Vitals, Mobile, Open report, scroll to the bottom.
  2. Find the slow interaction with real users. The attribution build of the web-vitals library reports the event target and event type and integrates with Google Analytics. Guide: find slow interactions in the field.
  3. Reproduce it in the lab. The Web Vitals Chrome extension with console logging enabled is the easiest test. For detail, record a trace in the Chrome DevTools Performance panel or use Lighthouse in timespan mode, as in diagnose slow interactions in the lab.

Lab data is consistent but can miss what real users experience. Use both.

Five JavaScript fixes that free the main thread

  1. Break up long tasks. Defer work with setTimeout(), yield with async/await, prioritize with scheduler.postTask(). Yield only when the user is waiting with isInputPending().
  2. Stop overlapping interactions. An autocomplete that sends a network request per keystroke congests the main thread. Debounce it and cancel outdated requests with the AbortController. Use CSS animations, not JavaScript animations.
  3. Ship less JavaScript. Split large scripts into chunks, load ES modules with type=module and modulepreload, and use dynamic import().
  4. Move heavy work to web workers. The main thread handles the UI, the workers handle the logic. Workers have no access to the DOM. Comlink simplifies the communication.
  5. Render on the server. Send as much HTML from the server as possible and limit the DOM nodes created on the client. The advanced version is a streaming service worker that precaches the static parts with CacheStorage.

A setTimeout() of 0 sends the remaining work to the end of the task queue. scheduler.yield() sends it to the front. In November 2023 it was a proposal: behind a flag in Chrome 115, or for real users through an origin trial.

Three rendering fixes that cut the presentation delay

  1. Keep the DOM small. Lighthouse warns above 800 DOM nodes and calls 1,400 excessive. Flatten the nesting, lazy load hidden elements and use content-visibility: auto with contain-intrinsic-size for off-screen content. Guide: DOM size and interactivity.
  2. Avoid layout thrashing. Read style values first, then change styles. Reading inside a loop that also writes recalculates the layout on every iteration. Tools like FastDOM help. Guide: avoid large, complex layouts and layout thrashing.
  3. Simplify style calculations. Use single class selectors, for example with BEM, and change classes on the specific element, not high up in the DOM. Guide: reduce the scope and complexity of style calculations.

What makes INP hard, and how to keep it good

  • Root causes need know-how. The browser rendering pipeline, the main thread, event loops and task queues, DOM and CSSOM.
  • Third-party scripts can block the main thread. Know their impact.
  • Monitor continuously. Track INP in lab and field data and set alerts for significant deviations.
  • Set performance budgets. Test every release against them, for example with Lighthouse, to prevent regressions.

What the PDF adds: the code

The PDF has the code for these fixes: yielding functions, debounce with AbortController, a web worker, the service worker setup, and problematic versus optimized layout and style code. Get the PDF by email.

FeatureDetails
TitleInteraction to Next Paint (INP)
AuthorsHolger Guggi, Franz Enzenhofer
Produced byFull Stack Optimization, Vienna, 29 November 2023
Length44 pages, 6,087 words, PDF
Target audienceWeb developers, SEO experts, digital marketers with technical understanding

Holger Guggi has done web performance optimization at Full Stack Optimization since 2011, for more than 100 clients. More on the team page.

All articles