DEV Community

Cover image for How I Fixed Lighthouse Score Drops Caused by Google Tag Manager & Analytics
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

How I Fixed Lighthouse Score Drops Caused by Google Tag Manager & Analytics

Hello, I'm Maneshwar. I'm working on FreeDevTools online currently building *one place for all dev tools, cheat codes, and TLDRs* — a free, open-source hub where developers can quickly find and use tools without any hassle of searching all over the internet.

Sometimes your site might be perfectly optimized — lightweight, fast, and SEO-friendly — but your Lighthouse or PageSpeed Insights scores refuse to hit 100.

The reason? Google Tag Manager (GTM) or Google Analytics scripts.

That’s exactly what happened to me while building Free Devtools.
The site itself was blazing fast, yet those analytics scripts were dragging the score down.

Here’s how I fixed it.

The Fix: Lazy-Load GTM and Analytics

Instead of loading GTM immediately, I deferred it until the user interacts with the page or the browser goes idle.
That means no blocking JS, no network noise, and a faster LCP/TBT.

Here’s the simple script that made the difference:

<!-- Optimized GTM loading -->
<script>
  (function() {
    const GA_MEASUREMENT_ID = 'G-'; // your GA ID if needed
    const GTM_ID = "GTM-"; // your GTM container ID

    // minimal dataLayer init
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({ "gtm.start": new Date().getTime(), event: "gtm.js" });

    function loadGTM() {
      if (window.__gtmLoaded) return;
      window.__gtmLoaded = true;

      const s = document.createElement("script");
      s.async = true;
      s.src = `https://www.googletagmanager.com/gtm.js?id=${GTM_ID}`;
      document.head.appendChild(s);
    }

    // trigger load on first interaction or after idle timeout
    const trigger = () => loadGTM();
    ["scroll", "pointerdown", "keydown"].forEach(evt =>
      window.addEventListener(evt, trigger, { once: true, passive: true })
    );

    if ("requestIdleCallback" in window)
      requestIdleCallback(loadGTM, { timeout: 5000 });
    else
      setTimeout(loadGTM, 5000);
  })();
</script>
Enter fullscreen mode Exit fullscreen mode

Result:

  • Lighthouse hit 100 again.
  • JS transfer size dropped dramatically.
  • LCP and TBT improved because the browser wasn’t parsing GTM early.

Other Options Worth Knowing

1. Preconnect, Lazy-Load, Server-Side & When to Use Each

If GTM’s slowing your site, there are three main levers to pull:
preconnect, lazy-load, and server-side tagging.
Each helps differently and has trade-offs.

Preconnect / Resource Hints

You can tell the browser early which domains you’ll need, reducing latency on first use:

<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
<link rel="dns-prefetch" href="//www.googletagmanager.com">
Enter fullscreen mode Exit fullscreen mode

Use preconnect if:

  • GTM or analytics must load right after first paint.
  • You want to reduce connection handshake time.

Avoid it if:

  • You defer or consent-gate tags (no point opening early sockets).
  • Your site rarely uses those domains on first view.

Lazy-Load / Defer / Consent-Gated Tags

If your GTM fires non-critical tags (heatmaps, A/B testing, marketing pixels, etc.), don’t load them instantly.

How to do it:

  • In GTM, use triggers based on first user interaction.
  • Wrap tags inside events fired after consent or idle time.
  • Keep non-essential scripts out of <head>.

When to use: lots of optional tags, consent laws, or performance goals.
When not to: revenue-critical tags that must fire immediately (like conversion or bidding pixels).

Server-Side Tagging (sGTM)

Move heavy lifting from the browser to your server.

What happens:

  • Browser sends lightweight events.
  • Your server processes and forwards them to GA, FB, etc.

Pros:

  • Reduces client JS work.
  • Improves privacy, avoids ad-blockers.
  • More consistent data.

Cons:

  • Costs infrastructure and setup time.
  • Some features won’t work outside client context.
  • Adds another moving part to maintain.

Load GTM Fast with Partytown

Partytown moves third-party scripts like GTM off the main thread into a Web Worker.

It’s ideal if you don’t want to build server-side tagging but still want to isolate GTM’s performance impact.

Pros: almost zero main-thread blocking.
Cons: some GTM scripts may break if they depend on direct DOM access.

Measure the Impact

Always measure before and after.

Phase Setup Metrics
Baseline Lab: Lighthouse, WebPageTest; Field: CrUX, Analytics, RUM LCP, INP, CLS, TBT, JS size, request count
After change Same device/network/pages Compare deltas: LCP down? TBT reduced? Any INP or event loss?
Ongoing Add RUM/performance budgets Watch regressions; monitor by device & network type

Common Pitfalls

  • Don’t compare inconsistent lab conditions (e.g., Fast 3G vs Slow 4G).
  • Expect noise in field metrics, especially with low traffic.
  • Delaying tags too much may lose early conversions.
  • Don’t optimize blindly — performance should support your business goals, not fight them.

Final Thoughts

Performance optimization is all about trade-offs.

If GTM or GA is holding your score hostage, lazy-loading is your fastest win — often pushing your PageSpeed score to 100 again.

Combine it with smart preconnects, possible server-side tagging, and ongoing measurement — and you’ll have both speed and insight, not one at the cost of the other.

FreeDevTools

I’ve been building for FreeDevTools.

A collection of UI/UX-focused tools crafted to simplify workflows, save time, and reduce friction in searching tools/materials.

Any feedback or contributors are welcome!

It’s online, open-source, and ready for anyone to use.

👉 Check it out: FreeDevTools
⭐ Star it on GitHub: freedevtools

Top comments (0)