Third Party Scripts Are Eating Your Page Speed (Here's the Fix)

Analytics, pixels, chat widgets, ads. They look harmless one at a time. Together they slowly murder your page speed. Time to take inventory.

Illustration showing a browser window with floating third party script tag chips being filtered through a shield

I'm going to make a bold claim. The single biggest reason most websites fail Core Web Vitals in 2026 is not the hero image, not the bloated CSS, not even the slow server. It's third party scripts. Google Tag Manager, Meta Pixel, Hotjar, Intercom, the cute little chat bubble in the corner, the 12 marketing tags somebody added in 2022 and forgot about. Each one looks innocent. Together they're a slow motion mugging.

Over 94 percent of sites ship at least one third party script. The average site ships eight. Stack five or six and you've added a full second of load time, blocked the main thread for 1.6 seconds, and watched your INP score quietly slide into the danger zone. Then you wonder why your INP is bad. Spoiler. It's the chat widget.

What "third party script" actually means

Anything loaded from a domain you don't control. Analytics, ad networks, A/B testing tools, customer support widgets, social embeds, fonts (yes), payment SDKs, marketing pixels, heatmap recorders, cookie consent managers, anti bot services. If you didn't ship the file from your own server, it counts.

The reason these break Core Web Vitals so badly is not really their fault. They're scripts. Scripts run on the main thread. The main thread is also where your page paints, where your buttons respond, where everything that feels fast happens. So a 200 ms tracker that runs synchronously during page load is a 200 ms gap during which your hero cannot paint and your buttons cannot respond.

The damage in real numbers

This is not theoretical. Chrome's research team measured the cost of the most popular third party scripts. The top offenders block the main thread for over 1.6 seconds on a mid range Android phone. That's not 1.6 seconds of network. That's 1.6 seconds of CPU work, parsing and executing JavaScript, while your page sits frozen.

Script categoryTypical LCP delayTypical INP delay
Google Tag Manager200 to 500 ms50 to 200 ms
Google Analytics 4100 to 300 ms40 to 100 ms
Meta Pixel150 to 400 ms60 to 200 ms
Chat widgets (Intercom, Drift, Crisp)300 to 800 ms100 to 400 ms
Heatmap recorders (Hotjar, FullStory)400 to 1000 ms150 to 500 ms
Ad networks500 to 2000 ms200 to 800 ms

Run that table in your head. If you have GTM, GA4, Meta Pixel, a chat widget, and Hotjar all loading on first paint, you're easily over a full second of LCP delay and probably half a second of INP delay before you write a single line of your own code.

Step 1: Audit what you actually have

Most teams do not know what's loading on their site. Marketing added stuff. Sales added stuff. Customer support added stuff. The intern added stuff. Nobody removed anything.

Open Chrome DevTools, go to the Network tab, filter by JS, reload the page. Sort by domain. Anything that's not your own domain is a third party. Make a list.

Then for each one, ask three questions:

  1. Do we still use this?
  2. If yes, can it run later instead of on first paint?
  3. If yes, can it run off the main thread entirely?

You will be surprised how many "yes we still use this" actually turn into "wait, we replaced that two years ago and the script is just here" when you start asking around.

The boring audit always wins

I have audited a Shopify store with 47 active third party scripts. After four hours of asking the team what each one did, we removed 31 of them. Same site. Same business. LCP dropped from 4.2 s to 2.1 s. The marketing director cried tears of joy. Or maybe panic. Hard to tell.

Step 2: Defer everything you can

For scripts you actually need, the next move is to keep them out of the critical path. Add the defer or async attribute and they will not block HTML parsing.

<!-- Bad: blocks parsing -->
<script src="https://www.googletagmanager.com/gtag/js?id=G-X"></script>

<!-- Better: defer -->
<script defer src="https://www.googletagmanager.com/gtag/js?id=G-X"></script>

<!-- Even better: load on user interaction or after paint -->
<script>
window.addEventListener('load', () => {
  setTimeout(() => {
    const s = document.createElement('script');
    s.src = 'https://www.googletagmanager.com/gtag/js?id=G-X';
    s.async = true;
    document.head.appendChild(s);
  }, 1500);
});
</script>

The third pattern is what teams who actually care about performance do. They wait for window.load (page is mostly interactive), then wait another second or two, then load analytics. Analytics still works. Page metrics improve dramatically. We have a deeper defer JavaScript guide if you want all the patterns.

Step 3: Partytown is the cheat code

Builder.io's Partytown is a tiny library that proxies third party scripts onto a web worker, off the main thread entirely. The script still runs. Tracking still works. But it doesn't block your main thread.

Setup is genuinely two steps. Add Partytown to your HTML head, then change the type attribute on third party scripts:

<script>partytown = { lib: '/~partytown/' }</script>
<script src="/~partytown/partytown.js"></script>

<script type="text/partytown">
  // Whatever GA, GTM, Pixel snippet you used to have
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-X');
</script>
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-X"></script>

That's it. The browser sees type="text/partytown" and ignores the script. Partytown picks it up, runs it on a worker, proxies any DOM access back to the main thread asynchronously. Your INP improves dramatically because the analytics script is no longer eating main thread time.

Real numbers. Sites that move GTM, GA4, and Meta Pixel to Partytown typically see INP drop by 50 to 70 percent. LCP also improves because the browser has more main thread budget for hero rendering. The catch is that scripts which need synchronous DOM access (like some chat widgets) don't work in Partytown. So Partytown is best for analytics and tracking, less great for interactive widgets.

Step 4: Facade pattern for embeds

YouTube embeds, Twitter embeds, Maps embeds, all heavy. A YouTube iframe alone loads 500 KB before anyone clicks play. Most users will not click play. So why pay the cost?

The facade pattern shows a static placeholder that looks like the embed. When the user clicks, you swap in the real iframe.

<div class="yt-facade" data-id="dQw4w9WgXcQ">
  <img src="https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg">
  <button class="yt-play">►</button>
</div>

<script>
document.querySelectorAll('.yt-facade').forEach(el => {
  el.addEventListener('click', () => {
    const id = el.dataset.id;
    el.innerHTML = `<iframe src="https://www.youtube.com/embed/${id}?autoplay=1"
      allow="autoplay; encrypted-media" allowfullscreen></iframe>`;
  });
});
</script>

Same idea for Twitter embeds, Disqus comments, Calendly widgets, anything heavy that the user might not interact with. lite-youtube-embed is a popular small library that does this for you. There's also lite-vimeo-embed, lite-twitter, lite-disqus. Pick the lite version of whatever you embed.

Step 5: Self host what you can

Some third party assets do not need to come from third parties. Google Fonts can be self hosted (and should be, see our font loading guide). Static analytics scripts can be downloaded and served from your CDN, then updated periodically.

Self hosting kills the third party DNS hop, lets you cache aggressively, and removes one source of supply chain risk. Tradeoff: when the third party updates the script, you have to update your local copy. Either accept that and run a weekly check, or use a tool like docu-fonts or self-hosted-google-fonts that does it automatically.

Step 6: Lazy load the chat widget

Almost every chat widget vendor will tell you their snippet "won't impact your performance." Almost every chat widget vendor is wrong. Chat widgets typically add 300 ms of main thread work, install an open WebSocket, and ship a few hundred KB of JS.

The fix: do not load the chat widget on page load. Load it only when the user shows intent. A floating button that says "Need help?" is enough. When clicked, lazy load the real chat widget.

const helpBtn = document.querySelector('#help-button');
helpBtn.addEventListener('click', async () => {
  if (!window.intercom) {
    await import('/path/to/intercom-loader.js');
  }
  window.Intercom('show');
}, { once: true });

You give up the analytics value of "track if user opened chat" but you save 300 to 800 ms of LCP for the 90 percent of users who never open chat anyway. Worth it.

Step 7: Consent banners are a special hell

If you operate in the EU, you probably have a consent banner. Most consent banners themselves are heavy third party scripts, ironically blocking the very thing they're supposed to gate.

Recommendations:

If the consent banner is itself a 100 KB blocking script, you have made everything worse in the name of compliance. Audit it specifically.

Step 8: Set a third party script budget

Performance budgets work because they create a clear "no" answer when marketing wants to add yet another tag. The budget I recommend:

Audit quarterly. Anything that violates the budget either gets deferred, partytown'd, or removed. No exceptions.

Step 9: The Privacy Sandbox future

Google Chrome is phasing out third party cookies in 2026 and pushing the Privacy Sandbox APIs (Topics, Protected Audience, Attribution Reporting) as replacements. Big upside: these APIs are designed to be lightweight and run in a privacy preserving way without traditional script overhead. If you migrate from cookie based tracking to Privacy Sandbox, you will probably see a measurable Core Web Vitals improvement just from removing redirect chains and cookie syncing scripts.

It is early days. Most ad and analytics vendors are still building support. But for new projects in 2026, default to Privacy Sandbox APIs over legacy cookie based tracking.

The third party scripts checklist

  1. Audit every third party script. Make a list with owner and purpose.
  2. Delete anything nobody owns or uses.
  3. Defer everything that can be deferred.
  4. Move analytics and tracking to Partytown.
  5. Use facade pattern for heavy embeds (YouTube, Twitter, Maps).
  6. Lazy load chat widgets behind user intent.
  7. Self host fonts and any cacheable assets.
  8. Set a 5 script and 100 KB budget. Enforce quarterly.
  9. Profile main thread with Lighthouse and DevTools Performance tab. INP regressions almost always trace back here.
  10. Test on a real mid range Android phone. Desktop tests hide the damage.

How this connects to the rest of your CWV work

Third party script optimization mostly attacks INP and LCP. It does not directly help CLS or TTFB much. But once you've cleaned up scripts, every other optimization gets easier because the main thread has breathing room. Hero images render faster. Hydration finishes sooner. Buttons feel responsive.

If you've already done LCP work and your scores still won't budge, third party scripts are almost certainly the problem. Go audit. It's the boring fix that beats every clever trick.

How to actually have the script audit conversation with marketing

Here is the part of third party script optimization that nobody writes about. The technical work is easy. Convincing your team to remove a tracker is hard.

Marketing added the Hotjar script in 2022 because the previous head of growth wanted heatmaps. The previous head of growth quit in 2023. Nobody has looked at a Hotjar heatmap in eight months. But the script is still there because nobody dares delete a marketing tag.

The fix is to have a structured conversation, not a unilateral cleanup. Marketing teams are reasonable when you give them data and choices.

The script inventory spreadsheet

Make a spreadsheet. Columns:

Walk through every script with the relevant owner. Most of them will agree to defer or lazy load once they see the cost. Some will insist on first paint loading because "we need accurate data on bouncers." For those, ask: when was the last time you actually used this data to make a decision? Often the answer is "I don't know" or "two years ago."

Show them the numbers in context

"This script costs you 200 ms of LCP" is abstract. "200 ms of LCP delay drops conversion rate by 1.4 percent according to Google's research, which on your traffic is roughly $42,000 of monthly revenue" is concrete. Frame the cost in their language.

For chat widgets specifically: "Loading the chat widget on every page costs us 600 ms of LCP. Lazy loading it behind a help button reduces page speed cost to zero, and we still get the chat conversion. Same outcome, faster site." Almost no marketer pushes back on that.

The defer-by-default policy

The most useful policy I've seen teams adopt is "all new scripts default to defer or lazy load. First paint loading requires written approval from engineering AND marketing leadership." This sounds bureaucratic but it works. The barrier to "just throw another tracker in" goes up. The barrier to "lazy load this one new thing" stays low.

Six months in, you typically have half the third party scripts you started with, and the team is happier because the site is faster.

The Tag Manager tradeoff

Google Tag Manager exists because non engineers wanted to add tags without filing tickets. That's a real need. But GTM itself is heavy, and once you have GTM, it tends to accumulate tags forever because the friction is too low.

For new projects in 2026, consider skipping GTM entirely and using a lighter alternative like Stape, Server Side Tag Manager, or just direct script tags. Server side tagging in particular shifts most of the cost off the user's browser entirely. The marketing team still gets to add tags. Your INP score does not pay for it.

Frequently asked questions

How many third party scripts is too many?

More than five loaded on first paint. Real production sites I respect ship one or two on first paint and lazy load everything else. Anything past five is almost always tag bloat that nobody pruned.

Will Partytown break my analytics?

For Google Analytics, Google Tag Manager, Meta Pixel, Plausible, Fathom, and most major analytics tools, no. Partytown has dedicated config recipes for each. For weird custom tracking that pokes at the DOM in synchronous ways, sometimes yes. Test in staging first.

Should I just remove Google Tag Manager?

If you only use it to load one or two analytics scripts, yes, remove it and load them directly. GTM adds overhead. Only worth it if you genuinely manage many tags through it.

Does deferring scripts hurt tracking accuracy?

Slightly. If a user lands on the page and bounces in 500 ms, deferred analytics might miss them. For most sites this is in the noise. For sites obsessed with bounce rate metrics, fire a single lightweight beacon early and load full analytics deferred.

Can I use both Partytown and defer together?

Yes. Partytown handles main thread offloading. Defer handles execution timing. They solve different problems and they compose well.

What about ad networks specifically?

Ad networks are the worst offenders. Their scripts inject more scripts, which inject more scripts, in a chain. There is no magic fix. The best you can do is lazy load ad slots into reserved space (avoid CLS, see our CLS guide), use lighter ad providers, and limit slots above the fold.

Find Out Which Scripts Are Killing Your Site

Run your URL through VitalsFixer. We list every third party script, measure their main thread cost, and tell you exactly which ones to defer or kill.

Free Script Audit →

Want us to clean up the script jungle?

We audit, defer, partytown, or remove every third party script on your site. Real engineers. 48 hour turnaround. Money back if your scores do not improve.

View Expert Fix Service →