Why INP is stricter than the metric it replaced
First Input Delay measured only the wait before your event handler started running, and only for the first interaction of the visit. Almost everything passed it, which is a decent sign a metric isn't telling you much.
INP measures the whole thing: input delay, the handler running, then the browser painting the result — for every click, tap and keypress in the visit, reporting roughly the worst. A page that opens fast and then locks up when someone taps the size chart now fails, correctly. That's three places for the delay to hide, and which one it is changes the fix entirely.
| Phase | What it is | Typical cause |
|---|---|---|
| Input delay | The tap lands while the main thread is busy doing something else. | A third-party script running a long task at exactly the wrong moment. |
| Processing time | Your event handler running. | Heavy work in the handler — DOM queries, big loops, synchronous storage reads. |
| Presentation delay | The browser recalculating layout and painting the new frame. | Enormous DOM, expensive CSS, layout thrash inside the handler. |
The scripts that actually break INP on Indian sites
In audits, the pattern repeats with depressing consistency. The site's own JavaScript is fine. Then marketing added things, one tag at a time, each of which seemed free.
Anything blocking the main thread for more than 50ms is a long task, and long tasks are where INP dies. The usual cast, in rough order of damage:
- A Tag Manager container with a dozen tags — GA4, Meta pixel, Google Ads, LinkedIn, Hotjar, Clarity, two affiliate pixels and something nobody remembers adding. Each is main-thread work.
- Live chat widgets — Tawk.to, Intercom, WhatsApp buttons. They pull in a whole app to render one bubble, early, because someone wanted it "always available".
- Exit-intent and offer popups — they bind mousemove and scroll listeners on load, then do work on every event.
- Shopify review apps — Judge.me, Loox and friends re-render star widgets per product card across a whole collection page.
- Session recording and heatmaps — Hotjar and Clarity record continuously. That's the trade you're making.
Fixing it: load order, then handler work
You rarely need to delete third-party scripts. You need to stop them competing with the user for the main thread during the first few seconds, which is when people interact.
- Audit the container first. List every tag firing on All Pages. Half usually belong to a campaign that ended. Delete those before engineering anything.
- Move the rest off the critical path. Fire non-essential tags on Window Loaded, scroll depth or a timer instead of Page View. Analytics that starts three seconds late still counts the session.
- Delay chat and popups until interaction. Load the widget on scroll, on hover, or when the page goes idle. Nobody opens live chat in the first 400 milliseconds.
- Break up your own long tasks. If a handler does real work, yield mid-way —
await scheduler.yield()where supported,setTimeoutwhere it isn't — so the tap can paint first. - Paint first, compute second. Show the accordion opening or the button state changing, then fire the tracking call. Users judge the paint, not the payload.
How to measure it honestly
Lab tools can't measure INP properly, because nobody is clicking anything. PageSpeed Insights gives you Total Blocking Time as a lab proxy — useful for direction, useless as proof.
The real measurement is field data: Search Console's Core Web Vitals report and the field section of PageSpeed Insights, both from real Chrome users at the 75th percentile. To name the guilty script, install the web-vitals library's attribution build — it reports which element was interacted with and what ran during the delay.
Throttle honestly while debugging. Set Chrome's CPU throttling to 4x or 6x, because a large share of Indian traffic arrives on mid-range Android hardware, not the MacBook the site was built on. Then check the same URLs for LCP and CLS — third-party scripts usually damage all three at once, so one clean-up pays three times.