INP went from 150ms to 400ms the week a marketing tag was added. Marketing says the script is async and cannot be the cause. How do you prove it either way and fix it?
Async controls when a script downloads, not what it does to the main thread once it executes, so an async tag can still block interaction handling. Prove it with field data attributed to the interaction: INP breaks into input delay, processing and presentation, and each points elsewhere. Then move the work off the critical path.
What the interviewer is scoring
- Whether the candidate explains that async affects fetching, not main-thread execution
- That INP is decomposed into input delay, processing time and presentation delay rather than treated as one number
- Does the answer distinguish field data from lab data, and explain why lab testing often misses this entirely
- Whether long tasks and total blocking time are used as the mechanism linking the script to the symptom
- That INP is identified as measuring the worst interaction, not the average, so a rare stall still moves it
- Whether the candidate proposes evidence a non-engineer can accept, given the stakeholder disagreement
- Does the fix consider yielding, workers or deferred loading rather than only removing the tag
Answer
Short answer
async only means the download does not block parsing. Once the file arrives, it executes on the main thread like any other script, and if that execution takes 300ms nothing can respond to a click during it. The claim confuses fetching with running. Prove it with field data, decomposed into INP's three phases so you can point at which part grew, then move the work off the interaction path rather than arguing about the tag.
What INP actually measures
INP is not an average and not a page-load metric. It observes every interaction over the page's lifetime — clicks, taps, key presses — measures each from input to the next paint reflecting the result, and reports approximately the worst one. That design matters here: a script that stalls the thread once, for a third of a second, at an unlucky moment will move INP substantially even though the median interaction is unchanged.
Each interaction decomposes into three parts, and naming them is what turns "the page feels slow" into a diagnosis:
Input delay — from the user's action until the event handler starts. This is time spent waiting for the main thread to become free. A third-party script executing a long task lands here.
Processing time — the handler itself running.
Presentation delay — from the handler finishing until the browser paints the next frame, covering layout, style and paint work.
A third-party tag almost always inflates input delay, because the user clicked while the thread was busy executing someone else's code. If your measurement shows processing time growing instead, the tag is probably not the cause and you should be looking at your own handlers or at listeners the tag attached.
Getting evidence the argument cannot survive
Lab testing frequently shows nothing, and it is important to explain why before someone waves a green Lighthouse score. Lab runs load the page and often never interact with it, so INP is not produced at all. Tag managers commonly serve different payloads by geography, consent state, or campaign, so the script in a synthetic run may not be the script real users get. And a one-off run cannot see a p75 of the worst interaction across a population.
So the evidence has to come from the field, using the Event Timing API to attribute the delay:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.interactionId && entry.duration > 200) {
report({
duration: entry.duration,
inputDelay: entry.processingStart - entry.startTime, // thread was busy
processing: entry.processingEnd - entry.processingStart,
presentation: entry.startTime + entry.duration - entry.processingEnd,
target: entry.target?.tagName,
});
}
}
}).observe({ type: 'event', buffered: true, durationThreshold: 40 });
Pair that with a Long Animation Frame observation, which reports the script attributed to a blocking frame — including its source URL. That is the piece that closes the argument, because it names the file rather than implying it.
The presentation that works with a non-engineering stakeholder is a before-and-after of field p75 INP with the input-delay component broken out, alongside the deploy date of the tag. Two lines and a vertical marker. Nobody has to accept a theory about the event loop.
Fixing it without removing the tag
Removing the script is often not available to you, so have the alternatives ready.
Load it when the thread is idle. Most tags do not need to run during the interactive window. Loading on requestIdleCallback, after the first meaningful interaction, or on a delay moves the execution out of the period where users are clicking. Tag managers usually support a trigger for this and it is the single highest-value change.
Yield inside long tasks you control. If the work is yours — an analytics wrapper, a consent handler — break it up so the browser can service input between chunks:
async function processQueue(items) {
for (const item of items) {
handle(item);
if (navigator.scheduling?.isInputPending?.()) {
await scheduler.yield?.() ?? new Promise(r => setTimeout(r, 0));
}
}
}
Yielding does not reduce total work; it reduces the length of the longest uninterruptible block, which is what INP is sensitive to.
Move it off the main thread. Work that does not touch the DOM — hashing, serialisation, batching — belongs in a web worker. Some vendors offer worker-based or partytown-style sandboxing for exactly this.
Constrain what it may do. If the tag attaches listeners to document for click tracking, those listeners run on every interaction and add to input delay permanently. Scoping or replacing them with a passive delegated listener you own is often a bigger win than the load timing.
Stopping the next one
The systemic fix is a budget with a gate. Set a performance budget on total blocking time and third-party script weight, enforce it in CI for code you control, and require a field-data review after any tag manager change. The reason the regression got in was that a change to production behaviour bypassed the engineering pipeline entirely — the durable answer addresses that path, not just this script. Proposing it makes the difference between fixing an incident and removing a category of incident.
© 2026 Preptima. Originally published at preptima.com.
Likely follow-ups
- Which of the three INP sub-parts would a third-party script most likely inflate, and why?
- Lab tests in CI show no regression at all. What is your explanation?
- How would you attribute INP to a specific script rather than to the page in general?
- Marketing will not remove the tag. What can you still do?
- What would you put in place so the next tag cannot do this silently?
Related questions
- Field data says your page has an INP of 400 ms. How do you find the cause and fix it?hardAlso on core-web-vitals and inp4 min
- A page has a poor Largest Contentful Paint. How do you diagnose it and what do you actually change?hardAlso on core-web-vitals7 min
- Users say the page jumps around while it loads, but your synthetic audit reports no layout shift at all. How do you find it and fix it?hardAlso on core-web-vitals6 min
- How do you resolve unacceptable INP degradation caused by massive, synchronous JavaScript execution blocking the main thread?hardAlso on inp3 min