Improving INP: finding the long tasks that make a page feel slow
INP is the metric that exposes how much JavaScript you shipped. A page can load in a second and still feel broken when tapped.
Third-party scripts commonly account for the majority of main-thread blocking on a marketing site. Audit what is loaded, remove anything without a named owner and a purpose, load what remains with defer or after interaction, and move measurement server-side where the vendor supports it.
| Script type | Typical transfer | Main-thread impact |
|---|---|---|
| Analytics | 20–50 KB | Low to moderate |
| Tag manager (plus tags) | 50–300 KB | Depends entirely on contents |
| Chat widget | 100–500 KB | High, often loads on page load |
| Session recording | 50–150 KB | High — instruments every event |
| A/B testing (synchronous) | 30–100 KB | Blocks rendering by design |
| Ad stack | 300 KB – 1 MB+ | Very high, plus layout shift |
The pattern in our audits is consistent: the site's own JavaScript is well optimised, and third-party tags account for most of the blocking time. Nobody notices because the tags were added by different people over two years.
| Strategy | When | Use for |
|---|---|---|
| Inline / blocking | Immediately, blocks parsing | Almost never |
| async | Downloads in parallel, runs on arrival | Independent analytics |
| defer | Downloads in parallel, runs after parsing | Most third-party scripts |
| On idle | After the page settles | Non-critical measurement |
| On interaction | When the user acts | Chat, video, maps, social embeds |
// Next.js: load after the page becomes interactive
<Script src="https://example.com/analytics.js" strategy="afterInteractive" />
// Load only when the browser is idle
<Script src="https://example.com/heatmap.js" strategy="lazyOnload" />A facade is a lightweight placeholder that looks like the widget and loads the real thing only when the user interacts. A chat bubble image that loads the chat SDK on click costs a few kilobytes instead of several hundred, and the vast majority of visitors never trigger it.
No. It stops the download blocking HTML parsing, but the script still executes on the main thread and competes with your code. Cost is deferred, not removed.
It removes a connection but breaks vendor updates and can violate terms of service. Generally not worth it except for stable, versioned libraries.
Measure it. Show the blocking time attributable to the script and the conversion impact of the page being slower. A number is far more persuasive than a principle.
ROVQIX Growth
SEO & growth team, ROVQIX
The ROVQIX growth team handles technical SEO, Core Web Vitals and AI-search visibility for the sites we build. Recommendations here are the ones we apply to client projects and to rovqix.in itself.
ROVQIXdesigns and builds production web platforms — Next.js front ends, Node.js APIs and the infrastructure behind them. Tell us what you're building and we'll scope it with you.
INP is the metric that exposes how much JavaScript you shipped. A page can load in a second and still feel broken when tapped.
Performance work that happens once decays within two quarters. A budget makes it a constraint every pull request has to respect.
CLS is the most fixable Core Web Vital. Almost every point of it comes from an element that did not tell the browser how big it would be.
No spam. Just the occasional case study and craft breakdown.