Opens in a new tab

New pricing is live: save 50% on Warp Performance

How to Optimize INP in 2026: The Complete Guide to Interaction to Next Paint

How to Optimize INP in 2026 featured - clean responsive guide WARP Performance

Interaction to Next Paint, or INP, is how fast your page actually feels. Not just the first click. Every tap, click, and keypress after that counts too. Since Google swapped First Input Delay for INP in March 2024, this is the number that decides whether your site feels snappy or sluggish.

I wrote this for people who run WordPress sites and need INP to drop without rebuilding everything. You will get the thresholds that matter in 2026, what INP is really measuring under the hood, how to catch it with real user data, and five fixes you can ship this week. Most of them live in your JavaScript and templates, not your hosting.

TL;DR: Key Takeaways

Good INP in 2026 is 200 ms or less at the 75th percentile, measured in the field. Above that, start here:

  • Ship less JavaScript. Split by route, defer what is not critical, delete what you never use.
  • Keep tasks under 50 ms. Break work with scheduler.yield() or chunked setTimeout(0). Push heavy work to Web Workers.
  • Load third parties late. Chat, GTM, Clarity. Fire them on first interaction, not on page load.
  • Stop layout thrashing. Read, then write. Never both in a loop. Keep DOM under 1,500 nodes.
  • Measure where it matters. CrUX and RUM (onINP()) tell the truth. Lab TBT just helps you reproduce it.

On most WordPress sites I audit, one template drives the bulk of poor INP URLs. Fix that template and the whole site shifts. The pattern is near the end of this guide.

What Is INP? (And Why It Replaced FID)

Interaction to Next Paint (INP), as defined by web.dev, is a Core Web Vital for responsiveness. It tracks every click, tap, and keypress during a visit, then reports the 75th percentile. That is the near-worst experience, not an average that hides the bad ones.

Google retired First Input Delay in March 2024 for a simple reason. FID only timed the first interaction, and only the wait before the browser started handling it. A page could pass FID and still feel janky five seconds later. INP looks at the full lifecycle, every time.

INP thresholds in 2026

From web.dev: What is a good INP score: good is 200 ms or less, needs improvement is 200 to 500 ms, poor is over 500 ms.

  • Good: 200 ms or less
  • Needs improvement: 200 to 500 ms
  • Poor: over 500 ms

Those numbers come from real-user field data in the Chrome User Experience Report, at the 75th percentile, split by mobile and desktop. If mobile is 260 ms, you are in needs improvement even if desktop is green.

One nuance people miss in 2026: INP is a field metric. Lighthouse cannot give you a true INP score. Lab tools can only guess at risk, usually with Total Blocking Time. Real users decide your score.

The Three Parts of INP

Every interaction breaks into three chunks. If you know which one is slow, you know what to fix.

  1. Input delay. The gap between what the user did and when the main thread is free to handle it. If a 180 ms task is already running, that click just waits. This is the most common culprit.
  2. Processing time. The work inside your event handlers. The JS that decides what happens next. Handlers that read and write the DOM, fire analytics, and force re-renders in the same tick get expensive fast.
  3. Presentation delay. The time from handler end to the next paint. Style recalcs, layout, and paint, especially with a huge DOM or gnarly CSS, drag this out.
Most WordPress sites I have checked fail INP in the same way: a blocked main thread plus an overgrown handler. That is Phases 1 and 2. Phase 3 only takes over when the DOM gets absurd, roughly past 2,800 nodes. Fix the thread first.
Diagram showing the three phases of INP latency: Input Delay, Processing Time, Presentation Delay
Where time goes. Input delay is usually the biggest win.

The #1 Cause of Poor INP: Long Tasks

A long task is any main-thread task over 50 ms. While it runs, the browser cannot process your click. INP spikes, and there is nothing the user can do about it except wait.

What I see most often, in order:

  • Monolithic bundles. 400 to 900 KB of JS parsed on load, often from page builders and leftover modules you stopped using months ago.
  • Third-party scripts. Analytics, tag managers, chat widgets, ads, A/B tools. Each adds listeners and timers you did not ask for.
  • Layout thrashing. Reading offsetHeight then writing style.height in a loop. That forces a reflow every iteration.
  • Heavy CSS and huge DOM. 2,500 nodes or more with complex selectors makes every interaction pay a style and layout tax.
  • Chatty timers and listeners. setInterval polling, scroll and resize handlers that do real work on every fire.

How to find it: open DevTools, Performance tab, hit record, click around. Look for the gray bars labeled Long task with a red triangle. Click one. The bottom-up stack tells you the function and file to fix.

How to Measure INP Correctly (Field First)

Field data first. Lab second, just to iterate faster.

  • Search Console, Core Web Vitals. Free CrUX data by origin and URL group, split mobile and desktop. This is your source of truth.
  • PageSpeed Insights. Same CrUX INP plus lab diagnostics for a single URL.
  • CrUX Dashboard or BigQuery. For history and origin versus URL comparisons.
  • Real User Monitoring. The web-vitals library’s onINP(), or Cloudflare Web Analytics, Vercel, Sentry, Datadog. You get INP by interaction type, by template, by device. That segmentation is the whole point.
  • Lab proxy: Total Blocking Time. Lighthouse keeps TBT under 200 ms as a rule of thumb. It is not INP. But if TBT is 600 ms, field INP will almost certainly be poor.

The 30-second RUM snippet

import {onINP} from 'web-vitals';
onINP(({value, entries}) => {
  // value is INP in ms at 75th percentile for this page load's interactions
  console.log('INP', value, entries.at(-1));
  // send to analytics: gtag, plausible, etc.
  gtag('event', 'web_vital_inp', { value: Math.round(value), metric_id: 'INP' });
});

Segment by template. Homepage, blog post, product page. On most sites one template owns the majority of poor INP. Fix that template and you fix the site.

5 Steps to Fix INP (With Code You Can Ship)

1. Ship less JavaScript

  • Split by route. Only load what a template needs. In WordPress, dequeue builder widgets and scripts per template.
  • Defer what is not critical. defer keeps execution in order and out of the way of the first paint.
  • Delete unused code. DevTools, Cmd+Shift+P, Coverage. Record a session. Remove what never runs.
  • Load third parties late. Chat and tag managers on scroll or first click, not on load. That single change often moves the needle more than anything else.
// Lazy-load a chat widget only after first user interaction
let chatLoaded = false;
['scroll','mousemove','touchstart','click'].forEach(evt =>
  window.addEventListener(evt, () => {
    if(chatLoaded) return; chatLoaded = true;
    const s = document.createElement('script');
    s.src = 'https://cdn.example.com/chat.js'; s.defer = true;
    document.head.appendChild(s);
  }, {once:true, passive:true})
);

2. Break up long tasks

  • Use scheduler.yield() when you can. Chromium has had it since 2024. It yields mid-task so input gets through.
  • Chunk with requestIdleCallback or batched setTimeout(0) if yield is not available.
  • Push heavy non-DOM work to Web Workers, like CSV parsing or image work.
// Before: one 260 ms task
function processBigArray(arr){ for(let i=0;i<arr.length;i++) heavy(arr[i]); }

// After: chunked with yield, never blocks more than about 40ms
async function processBigArrayYielding(arr){
  const CHUNK = 80;
  for(let i=0; i<arr.length; i+=CHUNK){
    for(let j=i; j<Math.min(i+CHUNK, arr.length); j++) heavy(arr[j]);
    if(navigator.scheduling?.isInputPending?.()) await scheduler.yield();
    else await new Promise(r => setTimeout(r, 0));
  }
}

3. Keep handlers tiny

  • Do the visual update right away. Defer the rest to requestAnimationFrame or setTimeout.
  • Use event delegation. One listener on the parent beats 200 on individual items.
  • Debounce or throttle rapid events, input, scroll, resize. Do not recompute on every keystroke.
// Delegation
document.querySelector('#product-grid').addEventListener('click', e => {
  const btn = e.target.closest('[data-add-to-cart]');
  if(!btn) return;
  // minimal work now, rest next frame
  btn.classList.add('loading');
  requestAnimationFrame(() => addToCart(btn.dataset.addToCart));
});

4. Stop layout thrashing

  • Batch reads, then batch writes. Never mix them in a loop.
  • Use content-visibility: auto and contain: layout on long feeds or cards to limit render scope.
  • Keep the DOM lean. Under 1,500 nodes is ideal, under 2,000 is fine. Page builders love to double that with empty wrappers.
// Thrashing
items.forEach(el => { el.style.height = el.offsetHeight + 10 + 'px'; }); // read and write each loop, reflow x N

// Fixed: read then write
const heights = items.map(el => el.offsetHeight);
items.forEach((el,i) => el.style.height = heights[i] + 10 + 'px');

5. Make the browser do less

  • Animate only transform and opacity. Those stay on the compositor and avoid layout.
  • Avoid expensive selectors like .a .b .c *:not(...) and large @import chains.
  • Preconnect to origins you must use: <link rel="preconnect" href="https://cdn.example.com">. One line, often a free 100 ms.

WordPress and Bricks: Where INP Actually Breaks

On WordPress, INP is almost always JavaScript plus third parties plus builder wrappers. For Bricks and WARP sites, and our WordPress performance guide (2026) covers the full stack, the fixes are specific:

  • Audit per template. Use Query Monitor and Coverage to find what each template actually needs. Dequeue swiper or lightbox where you do not use them.
  • Delay third parties in WARP. In WARP Performance, turn on Delay JS and Defer Third-Party on Interaction under WARP → Performance → JavaScript. Check the docs if you have not used it before.
  • Dequeue by template. In your child theme, wp_dequeue_script for sliders or maps on templates that never render them.
  • Fonts and icons. Two families max, font-display: swap, subset what you ship. Icon fonts that pull 200 KB of JS are an easy delete.
  • Bricks DOM hygiene. Use sections and containers, not divs inside divs inside divs. Remove empty wrappers. Keep post listings under 24 items with pagination.
Quick win in WARP: set chat and GTM to Load on User Interaction under Advanced, Script Manager. On the sites I have tested, that one toggle often drops INP by 90 to 140 ms.

Illustrative Pattern: How One Template Often Drives Site-Wide INP

Illustrative pattern, not a controlled benchmark. On WordPress and Bricks builds, poor INP tends to cluster in a single template, usually the post template. The same three things show up together:

  • A large shared bundle loaded everywhere
  • Third-party scripts firing on load, GTM, chat, analytics
  • A scroll or input handler doing layout work on every event

What tends to help when that is the case:

  1. Split the bundle so each template loads only what it needs
  2. Defer non-critical third parties until first interaction. If you use WARP Delay JS, test every interactive element after you turn it on.
  3. Break long tasks with scheduler.yield() or chunked setTimeout, and delegate your handlers
  4. Batch DOM reads then writes and keep the DOM lean

Prove it with field data. Check CrUX or your RUM, split by template, before and after. Lab numbers like TBT are just for reproducing locally.

Why INP Matters: Page Experience, Not Just a Score

INP sits inside Google’s page experience system. It will not save a page with weak relevance. But when two pages are close on relevance, the one that feels instant has an edge. Google says as much without publishing a neat tiebreaker formula, and that is fine. You should not chase the number. Fix the feel.

  • Close calls tilt on experience. Core Web Vitals, INP included, are part of page experience. Good vitals will not outrank great content, but they can decide a close race. No public tiebreaker rule, just cumulative signal.
  • Responsiveness keeps people. Laggy pages lose people. People who stay read more, scroll further, and bounce less. That behavior shows up in the data over time.
  • Mobile is where it breaks. Google indexes mobile. Mobile CPUs are slower and the main thread has less room. If INP is bad, it is almost always a mobile problem first.
  • Rendering has a budget. If the main thread is blocked for seconds, content and internal links appear late. Crawlers on a timeout may see a thinner version of the page.

Does the same work help AI Search and answer engines?

There is no published rule that says better INP equals more citations in AI Overviews or assistants. The overlap is practical, not causal. Pages that are faster and cleaner tend to be easier for crawlers and extractors to handle:

  1. Render budget is finite. Google’s renderer and many crawlers will wait only so long. If your answer needs seconds of JavaScript before it appears in the DOM, it risks being summarized incompletely.
  2. Good content plus good experience travels. Original, well-structured answers hold up everywhere, classic search and AI search alike. Speed alone does not earn a citation.
  3. Extractability overlaps. A direct answer in the first 100 words, clear H2 and H3, a tight TL;DR, FAQ with FAQPage schema, and no render-blocking bloat helps both humans and machines. Same techniques, no guarantee.

Checklist: Ship These, Then Measure in the Field

  • INP at or under 200 ms at p75 on mobile and desktop, in field data
  • No main-thread tasks over 50 ms. TBT under 200 ms in the lab
  • JavaScript split by route, deferred, actually tree-shaken
  • Third parties gated behind first interaction
  • Heavy work in workers or yielded chunks
  • Handlers delegated, debounced, tiny
  • DOM reads and writes batched, DOM under 1,500 nodes, content-visibility where it makes sense
  • Animations on transform and opacity only
  • RUM running with onINP(), split by template

Frequently Asked Questions

What is a good INP score in 2026?

Good is 200 ms or less at the 75th percentile of real interactions, measured in the field. 200 to 500 ms needs work. Over 500 ms is poor.

How is INP different from FID?

FID timed only the first interaction and only the wait before the browser reacted. INP measures all interactions, wait plus work plus paint, at the 75th percentile. It reflects the whole session, not just the entry.

Can I measure INP in Lighthouse?

Not directly. INP needs field data. Use TBT under 200 ms in Lighthouse as a rough proxy while you fix things, then confirm in CrUX or RUM.

Does INP affect SEO?

Yes, as part of page experience and Core Web Vitals. It will not outrank relevance, but in a close comparison a page with good vitals can have an edge.

What causes a high INP?

Long tasks over 50 ms that block input, plus heavy handlers and layout thrashing. On WordPress, third-party scripts are usually the trigger.

How do I improve INP quickly?

Reduce and defer JS, gate third parties behind interaction, break long tasks with scheduler.yield(), and batch DOM reads and writes. One template fix often helps the whole site.

Does INP matter for AI Overviews?

Fast, clean pages render more completely and are easier to extract answers from. That helps everywhere, but there is no documented rule that INP alone earns AI citations.

Sources & Further Reading

Thresholds and techniques checked against web.dev and MDN as of September 2026.

Optimizing INP is not about chasing a metric. It is about making the page feel instant when someone tries to use it.

The work is consistent: less blocking JavaScript, smaller bundles, handlers that do almost nothing, a lean DOM. I would start with one bad template. Most sites only need one.

This week, do three things:
  1. Search Console, Core Web Vitals, filter mobile. Find your worst template.
  2. Record one interaction in Performance. Find the longest task and break it with scheduler.yield().
  3. In WARP, set GTM and chat to Load on User Interaction. That is often the biggest single win.

Measure in the field, fix the main thread, keep RUM running. The part users feel is the part that matters. Try WARP Performance if you want that toggle without hand-rolling it: 14-day free trial.

Last updated: September 5, 2026 • Reviewed by WARP Performance engineering. Tested on Bricks, WordPress 7.1, Chromium 128.

Saurabh Guttedar

linkedin blueinstagram blue

Founder & Lead Developer

Saurabh Guttedar is the founder of Warp Performance, a technology entrepreneur, software engineer, and systems architect with extensive experience building and optimizing high-traffic digital platforms. His work spans WordPress, cloud infrastructure, caching, performance engineering, and scalable web systems. At Warp Performance, he is focused on making advanced website optimization faster, more intelligent, and accessible to businesses and developers.

View profile
[fluent_comments]