How to Fix INP and Core Web Vitals Without a Rebuild
When a site fails Core Web Vitals, the first suggestion is often a redesign or a new platform. Sometimes that’s justified. More often, the problems come from a handful of scripts, heavy event handlers and bloated pages that can be fixed on the site you already have. This guide focuses on Interaction to Next Paint (INP), the responsiveness metric that is usually the hardest to diagnose, and ends with quick wins for loading speed and layout stability.
Core Web Vitals in brief
Core Web Vitals are three metrics Google uses to describe how real visitors experience a page:
| Metric | What it measures | Good | Poor |
|---|---|---|---|
| Largest Contentful Paint (LCP) | Loading: when the largest visible image or text block renders | 2.5 s or less | Over 4 s |
| Interaction to Next Paint (INP) | Responsiveness: delay from a click, tap or key press to the next visual update | 200 ms or less | Over 500 ms |
| Cumulative Layout Shift (CLS) | Visual stability: how much visible content moves unexpectedly | 0.1 or less | Over 0.25 |
A page meets the “good” threshold when the 75th percentile of visits falls within it, measured separately for mobile and desktop. Anything between “good” and “poor” is rated “needs improvement.”
INP replaced First Input Delay (FID) as a Core Web Vital in March 2024. FID only measured the wait before the browser began handling the first interaction. INP looks at clicks, taps and key presses (not scrolling or hovering) throughout the visit and reports a value close to the slowest, so a page that turns sluggish after loading can’t hide behind a quick first click.
What makes an interaction slow
Every interaction has three parts, and each one needs a different kind of fix:
- Input delay: the time before your event handlers can start, usually because the main thread is busy with other work.
- Processing time: the time your event handlers take to run.
- Presentation delay: the time the browser needs to recalculate styles, lay out the page and paint the result.
Step 1: Confirm the problem with field data
Core Web Vitals are assessed on data from real visitors (field data), so start there rather than with a lab score.
- Search Console has a Core Web Vitals report that groups similar URLs and shows which groups fail, and on which metric.
- PageSpeed Insights shows field data from the Chrome User Experience Report (CrUX) for a URL or for the whole site when enough data exists, above the Lighthouse lab results.
- Your own real-user monitoring. Lower-traffic sites often have no CrUX data. Google’s open-source
web-vitalslibrary can send LCP, INP and CLS values from real visits to your analytics, and its attribution build shows which element and which phase caused a slow interaction.
A standard Lighthouse run doesn’t measure INP, because it doesn’t interact with the page. Its Total Blocking Time (TBT) is a useful lab signal for a busy main thread, not a substitute.
Step 2: Reproduce the slow interactions
Open the Performance panel in Chrome DevTools. Its live metrics view shows INP as you click around the page and logs each interaction. Throttle the CPU to approximate a mid-range phone, then record a trace of the slow interaction and see what runs on the main thread: your own code, third-party scripts, or large amounts of style and layout work.
Typical suspects include menu toggles, filters, accordions and tabs, add-to-cart buttons, form fields that validate on every keystroke, and cookie banners.
Step 3: Fix the causes without a rebuild
Trim and delay third-party scripts
Tag managers, chat widgets, heatmaps, A/B testing tools, social embeds and ad scripts all compete for the main thread. For each one, ask whether it’s still used, whether it needs to be on every page and whether it needs to load right away. Remove what nobody uses, limit tools to the pages that need them, and load the rest later or on demand, such as loading a chat widget only when someone clicks it.
Break up long tasks
Any task that occupies the main thread for more than 50 milliseconds is a long task, and while it runs the browser can’t respond to input. Split heavy work into smaller pieces and yield to the browser between them, so it can respond to input in the gaps:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function processItems(items) {
let lastYield = performance.now();
for (const item of items) {
handleItem(item);
if (performance.now() - lastYield > 40) {
await yieldToMain();
lastYield = performance.now();
}
}
}
scheduler.yield() isn’t available in every browser yet, which is why the example falls back to setTimeout.
Make event handlers do less
- Update the interface first. If a click opens a panel and also sends an analytics event, show the panel and defer the analytics call.
- Debounce input handlers on search boxes and filters so expensive work doesn’t run on every keystroke.
- Move heavy calculations on large data sets into a web worker.
- Avoid forced layouts. Reading a value like
offsetHeightright after changing styles makes the browser calculate layout immediately, and in a loop the cost multiplies.
Reduce rendering work
Presentation delay grows with the size and complexity of the page, so very large DOMs and deeply nested page-builder markup make every interaction more expensive.
- Remove unused sections and markup left behind by old plugins.
- Apply
content-visibility: autoto long sections below the fold, paired withcontain-intrinsic-size, so the browser can skip rendering them until they’re needed. - Animate
transformandopacityrather than properties that trigger layout, such as width or top.
Watch your CMS and plugins
On WordPress and similar platforms, plugins often load scripts and styles on every page, even when only one page uses them. Unloading those assets where they aren’t needed, and replacing heavy plugins with lighter ones, removes main-thread work without changing the design. Our WordPress development services include this kind of cleanup.
Quick wins for LCP and CLS
These common loading and stability fixes don’t require a rebuild either.
- Don’t lazy-load the main image. The hero image is often the LCP element. Load it normally, add
fetchpriority="high", and make sure it’s in the HTML rather than injected by JavaScript. - Serve images at the right size and in modern formats such as WebP or AVIF, using
srcsetso phones don’t download desktop-sized files. - Improve server response time with page caching and a CDN.
- Set width and height on images and videos, or use CSS
aspect-ratio, so the browser reserves space before they load. - Reserve space for late-loading content such as ads, embeds and banners.
- Soften font swaps by preloading only your most important font files and choosing a fallback font with similar proportions.
When a rebuild does make sense
A rebuild is worth considering when the theme or platform can’t be changed without breaking it, when nearly every page depends on a heavy builder you can’t trim, or when the site also has deeper security, accessibility or structural problems. Even then, measure first, so you know which problems the new build has to avoid.
Keep it from coming back
Performance slips quietly as new tags, plugins and features are added. Keep real-user monitoring running and review the three metrics monthly by page type and device. Agree on a performance budget, such as a maximum amount of JavaScript per page, and review every new third-party script before it goes live.
Google uses Core Web Vitals as part of its page experience signals, but it has also been clear that relevant, helpful content matters more. The better reason to fix INP is simpler: visitors notice when buttons and menus lag, and a responsive site is easier to use. If you’d like help finding and fixing what slows your site down, our web development services cover performance audits and optimization.


