Third-Party Scripts and Their Impact on INP
Third-Party Scripts and Their Impact on INP (Complete Fix Guide)
Third-party scripts are the single biggest cause of INP failures across the web. They run on your main thread, compete with your own code for CPU time, fire JavaScript during user interactions, and you have limited control over what they do or when they do it. The fix strategy is: audit what you have, remove what you do not need, defer what you do need, and move what remains to a web worker. Most sites can eliminate 40–60% of their INP delay by addressing third-party scripts alone.
You have optimised your own JavaScript. You have fixed your React re-renders. You have broken up your long tasks. Your INP score is still failing.
The culprit is almost certainly a script you did not write.
Analytics platforms. Advertising networks. Chat widgets. Heatmap tools. A/B testing scripts. Social media pixels. Retargeting tags. Each one runs JavaScript on your main thread. Each one fires during user interactions. Each one adds to your INP measurement — and you have almost no control over the quality of their code.
This article covers exactly how third-party scripts cause INP failures, how to identify which ones are responsible on your specific site, and every fix available — from simple deferral to complete main thread offloading.
If you are still working out why your INP is failing, start with how to identify and fix long tasks in Chrome DevTools — that article shows you how to find the specific script causing your long tasks before coming back here to fix it. For the broader context on why INP replaced FID and why third-party scripts are now so much more impactful, see INP vs FID: what changed and why it matters for SEO.
Why third-party scripts are the biggest INP problem
Third-party scripts are uniquely damaging to INP for reasons that go beyond their file size or execution time.
They run on your main thread
Every third-party script you load runs on the same main thread as your own JavaScript, your CSS rendering, and your layout calculations. The browser is single-threaded. When a third-party analytics script runs a 200ms task, your users cannot click anything for 200ms — regardless of how well-optimised your own code is.
They fire during interactions
The most damaging pattern is a third-party script that fires in response to user interactions. When a user clicks Add to Cart, your event handler fires — and so does the Facebook Pixel AddToCart event, the Google Analytics ecommerce event, the Klaviyo tracking event, and the Hotjar interaction recording. All of them run synchronously on the main thread. The visual response to the user's click is delayed until all of them finish.
This is exactly the problem that INP vs FID made visible. Under FID, these tracking events fired after the first interaction and were invisible to the metric. Under INP, every interaction is measured — and every tracking event that fires during an interaction contributes to the INP score.
You cannot optimise their code
When your own JavaScript is slow, you fix it. When a third-party script is slow, you are dependent on the vendor to fix it — which may never happen. A chat widget vendor has no incentive to optimise their script for your INP score. An advertising network's script prioritises ad rendering speed, not your page's responsiveness.
Your only levers are: when the script loads, whether it loads at all, and whether it runs on the main thread or a worker.
They update without your knowledge
Third-party scripts update independently of your deployment pipeline. A script that performed well last month may have had new features added, doubling its execution time this month. Sites that were passing INP can start failing it after a third-party vendor silently ships a performance regression.
How much do third-party scripts actually cost?
Real-world data from PageSpeed Insights analysis across thousands of pages:
| Script Category | Typical Main-Thread Blocking Time | Common Scripts |
|---|---|---|
| Tag managers | 200–600ms | Google Tag Manager, Tealium |
| A/B testing | 300–800ms | Optimizely, VWO, AB Tasty |
| Chat widgets | 150–400ms | Intercom, Drift, Tidio, Crisp |
| Heatmaps/session recording | 200–500ms | Hotjar, Microsoft Clarity, FullStory |
| Social pixels | 100–300ms | Facebook Pixel, TikTok Pixel, Pinterest Tag |
| Analytics | 50–200ms | Google Analytics 4, Amplitude, Mixpanel |
| Advertising | 100–400ms | Google Ads remarketing, Criteo, AdRoll |
| Review widgets | 100–300ms | Trustpilot, Yotpo, Bazaarvoice |
A typical e-commerce site running one tool from each category has 1,150–3,500ms of third-party script blocking time per page visit. On a mid-range Android device with 4x CPU slowdown, this becomes 4,600–14,000ms. Every millisecond of this competes with your users' interactions for main thread time.
Step 1: Audit your third-party scripts
Before fixing anything, get a complete picture of what is running on your pages.
Method 1: PageSpeed Insights
Run your URL through pagespeed.web.dev. In the Diagnostics section, expand "Reduce the impact of third-party code".
This table shows every third-party script with:
- Transfer size — how large the script file is
- Main-thread blocking time — how long it blocks the main thread
Sort by main-thread blocking time — this is the INP-relevant metric. The scripts with the highest blocking time are your priority targets.
Method 2: Chrome DevTools Performance panel
As covered in detail in how to identify and fix long tasks in Chrome DevTools, the Performance panel flame chart shows long tasks with red triangles. For third-party script analysis:
- Record an interaction trace (click a button, submit a form, use a filter)
- In the flame chart, look for long tasks that originate from external domains
- Hover over script bars — the tooltip shows the source domain
- Group the findings by domain to see which third-party is responsible for the most blocking time
Method 3: Request Map
Go to requestmap.pages.dev and enter your URL. It generates a visual map of every request your page makes — including every third-party script domain. This gives you a complete inventory of third-party dependencies at a glance.
Method 4: Browser console audit
Run this in your browser console to see every third-party script loaded on the current page.
const scripts = Array.from(document.scripts);
const thirdParty = scripts.filter(s => {
if (!s.src) return false;
const scriptDomain = new URL(s.src).hostname;
const pageDomain = window.location.hostname;
return !scriptDomain.includes(pageDomain.replace('www.', ''));
});
console.log(`Third-party scripts: ${thirdParty.length}`);
thirdParty.forEach(s => console.log(new URL(s.src).hostname, s.src));This instantly lists every third-party script running on the page — the domain it comes from and the full URL. Compare this list against your actual tool usage to find scripts that are loading but serving no active purpose.
Step 2: Categorise and prioritise
Once you have the full list, categorise each script by its business value vs performance cost:
Category A — Revenue-critical, must keep Scripts directly tied to revenue generation: payment processors, core analytics, conversion tracking.
Category B — Useful but deferrable Scripts that provide value but do not need to run during the critical interaction window: heatmaps, session recording, social pixels.
Category C — Low value, high cost Scripts from tools you trialled but never fully adopted, plugins from previous vendors, widgets that duplicate functionality you already have elsewhere.
Category D — Unknown origin: Scripts you cannot identify. These must be investigated — they may be from old implementations, injected by other scripts (Google Tag Manager loading additional tags), or, in rare cases, malicious injections.
For Category A: defer and optimise loading timing. For Category B: delay until after user interaction. For Category C: remove entirely. For Category D: investigate and remove unless identified as necessary.
Step 3: Remove scripts you do not need
This is always the highest-impact fix — and it is consistently underutilised because removing scripts requires asking uncomfortable questions about tool ROI.
The ROI audit question
For every third-party script, ask: "If this script stopped working today, would anyone notice within a week?"
If the answer is no — remove it. Scripts from:
- Analytics tools you stopped using 18 months ago but never removed
- A/B testing platforms where the last experiment ended 6 months ago
- Heatmap tools whose data is never acted on
- Social pixels for ad platforms where campaigns are no longer running
- Chat widgets that were trialled but never properly launched
- Review widgets for products that are no longer sold
All of these are common findings in third-party script audits. Each one is costing your users real INP delay with zero business return.
WordPress: plugin script audit
For WordPress sites, every active plugin can add scripts to every page — including pages where the plugin has no function. Use the Asset CleanUp or Perfmatters plugin to disable specific scripts on specific pages:
- Install Asset CleanUp
- Go to each key page type (homepage, product page, blog post)
- Review the scripts loaded — disable any plugin script not needed on that page type
- A contact form plugin's JavaScript does not need to load on product pages
- A WooCommerce script does not need to load on blog posts
This page-level script management is one of the most impactful WordPress INP fixes available. As covered in how to eliminate render-blocking resources, reducing the number of scripts loading on each page reduces both render-blocking time and INP-phase blocking time.
Shopify: app script audit
Each Shopify app injects scripts on every page by default — even on pages where the app has no relevant function. The app review process:
- Go to Shopify Admin → Apps
- For each app, check when it was last actively used
- For apps you keep, check if they offer a "load only on relevant pages" setting
- Uninstall apps that are not generating measurable value
A Shopify store with 20 installed apps is typically running 8–12 scripts that are either unused or redundant. Removing them can cut third-party blocking time by 60–70%.
Step 4: Defer scripts that must stay
For scripts you cannot remove, defer their loading to minimise impact on INP-critical interactions.
Basic deferral with async and defer attribute
<!-- Synchronous — blocks rendering and delays interaction readiness -->
<script src="https://analytics.example.com/script.js"></script>
<!-- Async — downloads in parallel, executes when ready (may still block interactions) -->
<script src="https://analytics.example.com/script.js" async></script>
<!-- Defer — downloads in parallel, executes after HTML parsed -->
<script src="https://analytics.example.com/script.js" defer></script>Use async for completely independent scripts (analytics, pixels).
Use defer for scripts that may depend on DOM structure.
Never use synchronous loading for any third-party script.
Delay until after the page is interactive
async and defer still load scripts during the page load sequence — which means they can fire JavaScript during the LCP window and affect early interactions. For scripts that are not needed until the user actually does something, delay loading until after the page is fully interactive:
javascript
// Load third-party scripts after page is interactive
function loadThirdPartyScripts() {
const scripts = [
{ src: 'https://static.hotjar.com/c/hotjar-ID.js', async: true },
{ src: 'https://connect.facebook.net/en_US/fbevents.js', async: true },
{ src: 'https://cdn.amplitude.com/libs/amplitude-min.js', async: true },
];
scripts.forEach(({ src, async }) => {
const script = document.createElement('script');
script.src = src;
script.async = async;
document.head.appendChild(script);
});
}
// Option 1: Load after page fully loaded
window.addEventListener('load', () => {
setTimeout(loadThirdPartyScripts, 1000); // 1 second after load
});
// Option 2: Load after first user interaction (better for INP)
let scriptsLoaded = false;
function loadOnInteraction() {
if (scriptsLoaded) return;
scriptsLoaded = true;
loadThirdPartyScripts();
}
['mousedown', 'touchstart', 'keydown', 'scroll'].forEach(event => {
document.addEventListener(event, loadOnInteraction, {
once: true,
passive: true
});
});Option 2 — loading after first interaction — is particularly effective because it ensures the script does not interfere with the page load phase (LCP) or the first interaction (early INP). The tradeoff is that the very first interaction will not be tracked by analytics or pixels. For most business use cases, missing the tracking of 1 in 100 interactions is an acceptable tradeoff for a dramatically better user experience.
Google Tag Manager — the multiplier problem
Google Tag Manager deserves special attention because it is a multiplier — one GTM script loads and then fires additional scripts based on triggers. A site with GTM can have 5–15 additional scripts loading through GTM that do not appear as individual script tags in the HTML.
The GTM auditing process:
- Log into Google Tag Manager
- Go to Tags → All Tags
- Look at the firing triggers for each tag
- Identify tags firing on "All Pages" — these load for every visitor
- Identify tags firing on "All Page Views" — these fire on every pageview, including on scroll and interaction events
- Change non-essential tags to fire on specific page triggers or interaction triggers
Common GTM configuration fixes:
Before: Facebook Pixel — fires on "All Pages" and "All Clicks"
After: Facebook Pixel — fires on specific conversion pages only
Before: Hotjar — fires on "All Pages"
After: Hotjar — fires on key pages only (homepage, product pages, checkout)
Before: LiveChat — fires on "All Pages"
After: LiveChat — fires after 5-second timer triggerReducing GTM tag firing frequency is one of the highest-leverage fixes available — a single GTM configuration change can affect every page on your site simultaneously.
Step 5: Move scripts to web workers with Partytown
For third-party scripts you cannot remove, cannot delay, and that are causing the most INP damage — Partytown offers a more radical solution: move them completely off the main thread.
Partytown is an open-source library that relocates third-party scripts to a web worker. Web workers run in a separate thread — completely independent of the main thread. Scripts in a web worker cannot block user interactions because they run on a separate thread.
How Partytown works
Normal loading:
Browser main thread → loads GTM → loads GA4 → loads FB Pixel → blocks interactions
Partytown loading:
Browser main thread → continues normally, handles all interactions
Web worker thread → loads GTM → loads GA4 → loads FB Pixel → no main thread impactBasic Partytown setup
html
<head>
<!-- Step 1: Load Partytown -->
<script>
partytown = {
forward: ['dataLayer.push', 'gtag', 'fbq', 'ttq', 'klaviyo.push']
};
</script>
<script src="/~partytown/partytown.js"></script>
<!-- Step 2: Change third-party scripts to type="text/partytown" -->
<!-- Google Tag Manager -->
<script type="text/partytown">
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
</script>
<!-- Facebook Pixel -->
<script type="text/partytown">
!function(f,b,e,v,n,t,s){/* FB pixel code */}
fbq('init', 'XXXXXXXXXX');
fbq('track', 'PageView');
</script>
</head>Scripts with type="text/partytown" are intercepted by Partytown and executed in a web worker instead of the main thread. From the perspective of the analytics platforms, everything works identically — events are tracked, conversions are recorded, data flows as normal. The difference is invisible to the vendor and transformative for your users.
Partytown in Next.js
Next.js has first-class Partytown support through @next/partytown:
npm install @next/partytown// pages/_document.js or app/layout.js
import { Partytown } from '@builder.io/partytown/react';
import Script from 'next/script';
export default function Document() {
return (
<Html>
<Head>
<Partytown forward={['dataLayer.push', 'gtag', 'fbq']} />
</Head>
<body>
<Main />
<NextScript />
{/* GTM in Partytown */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"
strategy="worker"
/>
<Script id="gtag-init" strategy="worker">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
`}
</Script>
</body>
</Html>
);
}strategy="worker" in Next.js's <Script> component automatically uses Partytown when @next/partytown is installed. This is the cleanest implementation available for Next.js applications.
Partytown in WordPress
For WordPress, use the Partytown for WordPress plugin or implement manually:
- Download Partytown files from the npm package
- Upload to
/wp-content/themes/your-theme/partytown/ - Add the configuration to your theme's
header.php:
<script>
partytown = {
lib: '<?php echo get_template_directory_uri(); ?>/partytown/',
forward: ['dataLayer.push', 'gtag', 'fbq']
};
</script>
<script src="<?php echo get_template_directory_uri(); ?>/partytown/partytown.js"></script>- Change your GTM and analytics
<script>tags totype="text/partytown"
Partytown limitations to know
Partytown works for most analytics and marketing scripts but has limitations:
- Scripts that need to access the DOM directly may not work correctly in a worker
- Some scripts use
document.write()which is incompatible with Partytown - Chat widgets that render UI elements (Intercom, Drift) cannot run in a worker — they need main thread access
- Scripts that rely on synchronous return values from DOM APIs may behave differently
Test thoroughly after implementing Partytown. Verify that events are firing correctly in each platform's debug mode before deploying to production.
Step 6: Optimise how tracking events fire during interactions
Even with scripts loaded asynchronously or in Partytown, the tracking calls that fire in response to user interactions can still cause INP delays — particularly when multiple tracking events fire synchronously in sequence.
The sequential tracking problem:- Javascript
// Bad — three tracking calls firing synchronously on Add to Cart click
function handleAddToCart(product) {
addProductToCart(product); // your code
// These fire synchronously, blocking visual response
fbq('track', 'AddToCart', { content_ids: [product.id] });
gtag('event', 'add_to_cart', { items: [product] });
klaviyo.track('Added to Cart', { ProductID: product.id });
dataLayer.push({ event: 'add_to_cart', ecommerce: { items: [product] } });
}This pattern fires four tracking events synchronously before the browser can update the UI. The visual response — cart icon updating, confirmation message showing — is delayed until all four tracking calls complete.
The fix: defer tracking after visual update
// Good — visual response first, tracking after
async function handleAddToCart(product) {
// 1. Update UI immediately
addProductToCart(product);
updateCartIcon(product);
// 2. Yield to browser — lets it paint the visual response
await scheduler.yield();
// 3. Fire tracking events after the visual update
fbq('track', 'AddToCart', { content_ids: [product.id] });
gtag('event', 'add_to_cart', { items: [product] });
klaviyo.track('Added to Cart', { ProductID: product.id });
dataLayer.push({ event: 'add_to_cart', ecommerce: { items: [product] } });
}The user sees the visual response immediately. Tracking fires after the browser has painted the updated UI. INP is measured up to the first paint — which now happens before any tracking code runs.
Batch tracking events
For pages with many interactions that each fire tracking events (filter pages, multi-step forms), consider batching tracking events and sending them in groups rather than on every individual interaction:
// Batch tracker — collects events and sends in batches
const eventQueue = [];
let flushTimeout = null;
function trackEvent(eventName, data) {
eventQueue.push({ eventName, data, timestamp: Date.now() });
// Schedule flush after 500ms of inactivity
clearTimeout(flushTimeout);
flushTimeout = setTimeout(flushEventQueue, 500);
}
function flushEventQueue() {
if (!eventQueue.length) return;
const events = eventQueue.splice(0);
requestIdleCallback(() => {
events.forEach(({ eventName, data }) => {
gtag('event', eventName, data);
fbq('trackCustom', eventName, data);
});
});
}
// Replace direct tracking calls with batched version
function handleFilterChange(filter) {
applyFilter(filter); // immediate
trackEvent('filter_applied', { filter }); // batched, fires in idle time
}This pattern is particularly effective for e-commerce filter pages where users rapidly click multiple filters in sequence. Instead of 5 separate tracking calls, each contributing to INP, one batch fires in idle time after the user has finished filtering.
Platform-specific third-party script fixes
WordPress
Google Tag Manager via WP plugin:
If you are using the official GTM4WP plugin, enable the "Script loading method: Partytown" option if available, or switch to loading GTM via hardcoded <script> tags in header.php with type="text/partytown".
WooCommerce tracking:
WooCommerce's built-in Google Analytics and Facebook integrations fire tracking events synchronously on cart and checkout interactions. Replace the built-in integrations with a custom GTM-based implementation that uses the scheduler.yield() pattern above.
Cache plugins and scripts: WP Rocket, LiteSpeed Cache, and W3 Total Cache all have settings for delaying JavaScript execution. Enable "Delay JavaScript execution" in WP Rocket — it applies the interaction-based loading pattern to all scripts automatically, without manual implementation.
For a complete picture of how JavaScript loading connects to your LCP score on WordPress, see how to eliminate render-blocking resources. And for CLS issues caused by these same scripts injecting content dynamically, see fix CLS from dynamic ads and embeds.
Shopify
Shopify's theme architecture makes Partytown difficult to implement without custom development. The practical Shopify approach:
Step 1: Audit all app scripts using PageSpeed Insights → "Reduce the impact of third-party code"
Step 2: Remove apps with blocking time above 200ms that are not revenue-critical
Step 3: For remaining apps, check if they support loading their scripts after page load. Many modern Shopify apps added "performance mode" options in 2025 — check each app's settings.
Step 4: Move remaining analytics and pixel scripts into GTM and configure GTM to load after user interaction using a timer trigger
Next.js
Next.js provides the cleanest path to third-party script optimisation through its <Script> component strategies:
import Script from 'next/script';
export default function Layout({ children }) {
return (
<>
{children}
{/* Critical: load as soon as possible */}
<Script
src="/critical-polyfill.js"
strategy="beforeInteractive"
/>
{/* Analytics: load after page is interactive */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"
strategy="afterInteractive"
/>
{/* Non-essential: load in web worker via Partytown */}
<Script
src="https://static.hotjar.com/c/hotjar-ID.js"
strategy="worker"
/>
{/* Low priority: load during idle time */}
<Script
src="https://widget.reviews.io/rich-snippet-reviews-widgets/dist/widget.js"
strategy="lazyOnload"
/>
</>
);
}Match the strategy to the script's actual priority. Most analytics and marketing scripts should use afterInteractive. Session recording tools like Hotjar should use worker (Partytown). Social proof widgets and review embeds should use lazyOnload.
Monitoring third-party script impact over time
Third-party scripts change without notice. A script that passed your INP threshold last month may fail it this month after a vendor update. Set up ongoing monitoring:
Real User Monitoring with web-vitals
import { onINP } from 'web-vitals/attribution';
onINP((metric) => {
// The attribution tells you which element triggered the slow interaction
const { interactionTarget, interactionType, inputDelay,
processingDuration, presentationDelay } = metric.attribution;
sendToAnalytics({
metric: 'INP',
value: metric.value,
rating: metric.rating,
interactionTarget,
inputDelay: Math.round(inputDelay),
processingDuration: Math.round(processingDuration),
presentationDelay: Math.round(presentationDelay),
page: window.location.pathname
});
});The processingDuration field is particularly useful — a high processing duration on an Add to Cart button points directly to synchronous tracking events as the cause.
Long Task Observer for third-party attribution
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
// attribution identifies which script caused the long task
const attribution = entry.attribution?.[0];
const scriptUrl = attribution?.containerSrc || 'unknown';
const isThirdParty = scriptUrl &&
!scriptUrl.includes(window.location.hostname);
if (isThirdParty) {
sendToAnalytics({
metric: 'third_party_long_task',
duration: Math.round(entry.duration),
script: new URL(scriptUrl).hostname,
page: window.location.pathname
});
}
}
}
});
observer.observe({ type: 'longtask', buffered: true });This sends a data point to your analytics every time a third-party script creates a long task in production. Over time, you can see which vendors are most frequently causing long tasks and whether vendor updates are making things better or worse.
How third-party scripts connect to your full Core Web Vitals picture
Third-party scripts do not just affect INP. Their impact reaches across all three Core Web Vitals.
Third-party scripts → LCP:
Scripts loaded synchronously in <head> block rendering and delay when the LCP element can paint. Deferring third-party scripts is one of the fixes covered in how to eliminate render-blocking resources. For the connection between script loading and LCP timing, see what is a good LCP score and how to preload your LCP image.
Third-party scripts → CLS: Scripts that inject content dynamically — ad networks, promotional bars, cookie consent tools — cause layout shift. This is covered in depth in fix CLS from dynamic ads and embeds and what causes cumulative layout shift.
Third-party scripts → TTFB: Scripts loaded from slow third-party domains add DNS lookup and connection time to your overall load sequence. Preconnecting to critical third-party domains reduces this. The broader TTFB picture is covered in how to fix slow server response time.
Third-party scripts → long tasks: The diagnostic process for identifying which third-party scripts are causing long tasks is covered in how to identify and fix long tasks in Chrome DevTools. The JavaScript execution time context — how third-party scripts fit into the broader JavaScript performance picture — is in how to reduce JavaScript execution time.
The complete Core Web Vitals guide ties all three metrics and their third-party script connections together in one prioritised action plan.
Third-party script INP checklist
| Action | Effort | INP Impact | Does it require a Developer |
|---|---|---|---|
| Audit scripts with PageSpeed Insights | Very low | N/A (diagnostic) | No |
| Remove unused third-party scripts | Low | Very high | No |
| Add async/defer to remaining scripts | Low | High | No |
| Configure GTM tag firing triggers | Low | High | No |
| Delay the load until after the interaction | Medium | Very high | No |
| Defer tracking after visual update (yield) | Medium | High | Yes |
| Move scripts to Partytown web worker | Medium | Very high | Yes |
| Replace GA4 with lightweight analytics | Medium | High | No |
| Batch tracking events on filter pages | High | High | Yes |
| Set up Long Task Observer monitoring | Medium | N/A (monitoring) | Yes |
Frequently asked questions
Q1. Which third-party scripts cause the most INP damage?
A/B testing scripts (Optimizely, VWO) and tag managers with many loaded tags (GTM with 15+ tags) consistently cause the most INP damage. They run extensive JavaScript both during page load and during interactions. Chat widgets (Intercom, Drift) and heatmap tools (Hotjar, FullStory) are the next most impactful, particularly on mobile devices.
Q2. Can I use Partytown with Google Analytics 4?
Yes. GA4 works in Partytown for standard event tracking. The forward configuration needs to include gtag and dataLayer.push. Some advanced GA4 features that rely on synchronous DOM access may behave differently — test thoroughly in GA4's DebugView before deploying.
Q3. Does deferring analytics scripts cause data loss?
Minimal data loss occurs with most deferral strategies. Loading analytics after page interaction means the very first interaction may not be tracked — affecting approximately 5–15% of sessions depending on how quickly users interact. For most analytics use cases, this is an acceptable tradeoff. For conversion-critical tracking, use the scheduler.yield() approach (defer tracking after visual update) rather than delaying the script load entirely.
Q4. My GTM has 30+ tags. Where do I start?
Start with tags firing on "All Pages" with interaction triggers (All Clicks, Form Submissions). These fire on every user interaction and directly contribute to every INP measurement. Change these to fire only on specific pages or specific elements. Then audit tags firing on "All Pages" on page load — remove any that are not actively used.
Q5. Why is my INP still failing after implementing Partytown?
The most common reasons are: some scripts cannot run in a worker and were excluded from Partytown, the forward configuration is missing some API calls causing scripts to not function correctly, or the INP failure is caused by your own JavaScript rather than third-party scripts. Use the Chrome DevTools long task identification process to confirm the source of remaining long tasks after Partytown implementation.
Q6. Does removing third-party scripts affect my marketing performance?
Removing scripts from tools you are actively using will reduce data collection. Before removing any revenue-impacting script, evaluate: how much of your marketing budget relies on this data, whether the data is available through other means (server-side tracking, first-party data), and whether the INP improvement could increase conversion rates enough to offset any measurement loss.
Q7. How do I handle third-party scripts that must load synchronously?
Some scripts genuinely need to be synchronous — particularly A/B testing tools that need to modify page content before rendering to avoid flicker, and certain consent management platforms. For these, minimise their size by working with the vendor to provide a lightweight version, use server-side implementations where possible, and accept that some synchronous loading is unavoidable while optimising everything else.
Summary
Third-party scripts are the single biggest cause of INP failures across the web — more impactful than framework re-renders, DOM size, or your own JavaScript. They run on your main thread, fire during interactions, and update without your knowledge.
The six-step fix process in priority order:
- Audit — PageSpeed Insights + Chrome DevTools + browser console to get the complete list with blocking times
- Categorise — revenue-critical vs useful vs low-value vs unknown
- Remove — every script not generating measurable business value
- Defer — async/defer attributes, load after interaction, delay by 1–2 seconds after page load
- Optimise GTM — change tag firing triggers from All Pages/All Clicks to specific pages and specific elements
- Move to Partytown — offload remaining high-impact scripts to a web worker
Combined with breaking up long tasks, optimising JavaScript execution time, and addressing the broader Core Web Vitals picture, fixing your third-party scripts is the highest-leverage single action available for most sites failing INP in 2026.
