<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged thirdpartyscripts</title>
<link>https://coderlegion.com/tag/thirdpartyscripts</link>
<description>Powered by Question2Answer</description>
<item>
<title>Third-Party Scripts and Performance: How to Identify and Fix the Worst Offenders</title>
<link>https://coderlegion.com/15959/third-party-scripts-and-performance-how-to-identify-and-fix-the-worst-offenders</link>
<description>&lt;p&gt;Most “performance projects” start with images and fonts. Fair enough. But the pages that still feel bad after a hero image is optimised, preloaded, and served from a CDN are often suffering from a different problem: &lt;strong&gt;third-party&lt;/strong&gt; JavaScript. Tag managers, chat widgets, A/B tests, and social embeds do not have to be evil. Left unmanaged, they absolutely compete with your first paint, your &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/tag/lcp&quot;&gt;LCP&lt;/a&gt;, and the interactions that &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/tag/inp&quot;&gt;INP&lt;/a&gt; measures. This guide is a practical way to name the worst offenders, decide what to cut or delay, and prove the win before the marketing team files a ticket because “the numbers look wrong”.&lt;/p&gt;&lt;h2&gt;What “third party” really means in performance work&lt;/h2&gt;&lt;p&gt;A third-party script is any JavaScript, iframe, or stylesheet you did not write that loads from another origin: analytics, ads, reviews, personalisation, consent platforms, and the tag manager that wires them together. Browsers do not care whether a script is “small business friendly”. They still parse it, sometimes execute it in the hot path, and every long task on the main thread delays input handling and the next paint.&lt;/p&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;Core Web Vitals&lt;/a&gt; are the clearest public scorecard, but the mechanism underneath is the same in smaller shops and enterprise:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;LCP&lt;/strong&gt; can move if a late-loading script or font pushes your hero, or if third-party work delays rendering.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;INP&lt;/strong&gt; gets worse when the main thread is busy; third-party long tasks and heavy event listeners sit in front of your own code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Total Blocking Time (TBT)&lt;/strong&gt; in lab tools like Lighthouse measures main-thread blocking after &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/fcp&quot;&gt;First Contentful Paint&lt;/a&gt;; it often &lt;strong&gt;correlates&lt;/strong&gt; with poor &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/inp&quot;&gt;INP&lt;/a&gt; in the field, but &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/tbt&quot;&gt;TBT is not a substitute for INP&lt;/a&gt;: it can miss slow interactions that happen after load (where a lot of third-party widgets do their work).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So the job is not “remove all third parties”. The job is to &lt;strong&gt;order&lt;/strong&gt; them, &lt;strong&gt;time&lt;/strong&gt; them, and &lt;strong&gt;measure&lt;/strong&gt; so you are not optimising in the dark.&lt;/p&gt;&lt;h2&gt;Step 1: Get a defensible list of what actually loads&lt;/h2&gt;&lt;p&gt;You cannot fix what you cannot see. Start with a cold, hard inventory:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;View source and search for&lt;/strong&gt; &lt;code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;src=&lt;/code&gt;.** Note every external host. Do the same for &lt;code&gt;link rel=&quot;preconnect&quot;&lt;/code&gt; and &lt;code&gt;import()&lt;/code&gt; chains if you use a modern bundler.&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Open DevTools, Network, disable cache, hard reload.&lt;/strong&gt; Sort by “Initiator” or group by “Domain” so you see which product pulled in which chain. A single GTM or Segment container often fans out to twenty requests.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use your tag manager’s preview mode&lt;/strong&gt; to log which tags fire on which page templates. A homepage does not have to carry the same load as a logged-in account area, but in practice one container often rules them all until someone audits it.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.apogeewatcher.com/blog-images/32-chrome-devtools-network-by-domain.png&quot; alt=&quot;Chrome DevTools Network panel: request waterfall, status and type columns, and Initiator column showing chains from gtm.js and other third-party scripts&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Read the &lt;strong&gt;Initiator&lt;/strong&gt; column and the waterfall to see which script pulled in which chain. Use &lt;strong&gt;Group by&lt;/strong&gt; options in the table header if you want rows collapsed by &lt;strong&gt;Domain&lt;/strong&gt; (wording varies by Chrome version).&lt;/em&gt;&lt;/p&gt;&lt;p&gt;For clients, this inventory belongs in the same place as your design system: a short internal doc, not a one-off email. When a new pixel appears, you can ask “which tag added this?” and roll back a single change instead of re-running a mystery hunt every quarter.&lt;/p&gt;&lt;h2&gt;Step 2: Use Lighthouse to rank third-party &lt;em&gt;cost&lt;/em&gt; (not just bytes)&lt;/h2&gt;&lt;p&gt;Lighthouse in Chrome (or the &lt;strong&gt;PageSpeed Insights&lt;/strong&gt; “Diagnose performance issues” section) surfaces third-party impact in a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/third-party-summary&quot;&gt;dedicated audit&lt;/a&gt; (title: &lt;strong&gt;Reduce the impact of third-party code&lt;/strong&gt;). It lists transfer size, CPU time, and main-thread blocking time by origin. Under the documented rules, Lighthouse &lt;strong&gt;fails&lt;/strong&gt; this check when third-party code blocks the main thread for &lt;strong&gt;more than 250ms in total&lt;/strong&gt; during the load it measures. Treat that as a first “who is expensive?” table before you dig into traces.&lt;/p&gt;&lt;p&gt;Depending on Lighthouse version, you may see the same idea under newer &lt;strong&gt;Performance insights&lt;/strong&gt; (for example third-party coverage in &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://developer.chrome.com/blog/lighthouse-13-0&quot;&gt;Lighthouse 13’s insight model&lt;/a&gt;); the underlying job is unchanged: quantify cost per provider.&lt;/p&gt;&lt;p&gt;Pair it with:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;“Reduce JavaScript execution time”&lt;/strong&gt;, &lt;strong&gt;“Reduce the impact of third-party code”&lt;/strong&gt; (above), and &lt;strong&gt;“Minimize main-thread work”&lt;/strong&gt; where those audits appear (Lighthouse UI uses US spelling). The exact labels move between releases; the intent does not: find scripts that add long tasks and network overhead. For a walkthrough, see &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/identify-slow-third-party-javascript&quot;&gt;Identify slow third-party JavaScript&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A lab run on the slowest realistic conditions&lt;/strong&gt; (mobile, throttled) so the ranking matches how your users experience the page, not a developer laptop on Wi-Fi.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.apogeewatcher.com/blog-images/32-lighthouse-reduce-third-party-code.png&quot; alt=&quot;Lighthouse report: Reduce the impact of third-party code, showing per-origin transfer size, main thread time, and blocking time&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;The same audit appears in PageSpeed Insights under performance diagnostics; use it as your first sorted table of “who costs what” before DevTools deep dives.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Lab data is not field data, but for third-party work it is often &lt;em&gt;more&lt;/em&gt; actionable: you can block a host in DevTools, reload, and see the same page without the tag.&lt;/p&gt;&lt;h2&gt;Step 3: Use DevTools to find the &lt;em&gt;moment&lt;/em&gt; a script hurts&lt;/h2&gt;&lt;p&gt;Lighthouse points at winners and losers. DevTools shows &lt;strong&gt;when&lt;/strong&gt; they run:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Performance panel:&lt;/strong&gt; record a page load, then look for long yellow blocks (Scripting) and the &lt;strong&gt;Main&lt;/strong&gt; flame chart. The &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/PerformanceLongTaskTiming&quot;&gt;Long Tasks API&lt;/a&gt; uses a &lt;strong&gt;50ms&lt;/strong&gt; threshold for a “long task”; tasks longer than that contribute to how “busy” the main thread feels. Heavy ads or frameworks often show 50–200ms+ slices.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Bottom-up / Call tree&lt;/strong&gt; on the same recording, filtered by a third-party domain, tells you if time is in parse, compile, or your own app code &lt;em&gt;after&lt;/em&gt; a third party schedules work.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Coverage tab:&lt;/strong&gt; load a page, then record which portions of a third-party file actually run. A 400KB file that was fully downloaded but only 5% “used” is a candidate for &lt;strong&gt;lazy&lt;/strong&gt; loading or removal, not a pat on the back for gzip.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.apogeewatcher.com/blog-images/32-chrome-devtools-performance-main-thread.png&quot; alt=&quot;Chrome DevTools Performance: Main thread track with long scripting tasks; yellow blocks show where the CPU is busy during load or interaction&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Record a load (and, for INP, a real click or menu open). Long &lt;strong&gt;Scripting&lt;/strong&gt; slices on the main thread are what make interactions feel delayed.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.apogeewatcher.com/blog-images/32-chrome-devtools-coverage-third-party.png&quot; alt=&quot;Chrome DevTools Coverage: per-file used vs unused bytes for a large third-party script, highlighting dead code to defer or remove&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Coverage answers “did we even execute this?” High unused percentage means you may be shipping JS you never needed on that route.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;If you are chasing INP, repeat the recording with a &lt;strong&gt;real&lt;/strong&gt; interaction: open the menu, add to cart, open chat. The worst third-party work often appears &lt;strong&gt;after&lt;/strong&gt; first load, when the widget initialises on scroll or on first click.&lt;/p&gt;&lt;h2&gt;Step 4: Map findings to CWV and business impact&lt;/h2&gt;&lt;p&gt;Not every big script is worth a fight. Sort candidates like this:&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Question&lt;/th&gt;&lt;th&gt;If “yes”&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Does it sit on the critical path before first meaningful paint?&lt;/td&gt;&lt;td&gt;Push it later or to a worker pattern (see below).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Does it add long main-thread work during typical interactions?&lt;/td&gt;&lt;td&gt;It is a prime INP target.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Is it on every page but only used on checkout?&lt;/td&gt;&lt;td&gt;Load it on checkout routes only.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Is it duplicated (same vendor, two tags)?&lt;/td&gt;&lt;td&gt;Merge at the source; duplicate pixels are a classic agency waste.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Does the marketing team need it for attribution this quarter?&lt;/td&gt;&lt;td&gt;Optimise the delivery first; removal is a product decision, not a dev-only one.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;In multi-site and agency work, the same “standard” GTM install often ships to every property. A template fix in the container is cheaper than renegotiating a vendor contract, so fix the &lt;strong&gt;shared&lt;/strong&gt; layer before you re-architect a single site.&lt;/p&gt;&lt;h2&gt;Step 5: Fix patterns that work in production&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Defer what you can.&lt;/strong&gt; Non-critical script tags should not sit synchronously in &lt;code&gt;&lt;/code&gt;. Your framework or CMS may be injecting them; override at the template level where possible. For scripts you truly need early, you are trading against LCP: keep the list as short as your analytics owner allows.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Load on interaction, not on paint.&lt;/strong&gt; Chat widgets, non-critical A/B tools, and “nice to have” personalisation can wait until scroll, a tab click, or a 2–3 second idle timeout. &lt;code&gt;requestIdleCallback&lt;/code&gt; is not supported everywhere, but a small &lt;code&gt;setTimeout&lt;/code&gt; after &lt;code&gt;load&lt;/code&gt; is still a step up from “block first paint”.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Facade heavy embeds where it makes sense for your content.&lt;/strong&gt; A static placeholder that loads the real YouTube, map, or social widget on click (or on entering the viewport) cuts initial JavaScript and often improves LCP on content-heavy pages. See &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/efficiently-load-third-party-javascript&quot;&gt;Efficiently load third-party JavaScript&lt;/a&gt; and implement facades in a way that does not break keyboard users or your consent flow.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Move work off the main thread for eligible scripts.&lt;/strong&gt; &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://partytown.builder.io/&quot;&gt;Partytown&lt;/a&gt; and similar patterns run particular scripts in a web worker. They are not a free lunch (serialisation, compatibility), but for analytics and support scripts that can cooperate, they reduce main-thread contention. Fit them into your &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/the-complete-guide-to-performance-budgets-for-web-teams&quot;&gt;performance budget&lt;/a&gt; as an experiment, not a silent default, until you have tested INP and edge cases.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Server-side and edge tagging.&lt;/strong&gt; If your use case is “send a conversion to ad platforms”, a server GTM on Cloud Run, or API-based server events, can remove a client tag entirely. The implementation cost is higher; the client-side win is real on interaction-heavy pages.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Govern the tag manager.&lt;/strong&gt; One owner, naming conventions, a rule that new tags do not go live in “All Pages” without review, and a quarterly cull of unused tags will save more CPU than another round of &lt;code&gt;webpack&lt;/code&gt; tweaks.&lt;/p&gt;&lt;h2&gt;Step 6: Prove the change and set a floor so it sticks&lt;/h2&gt;&lt;p&gt;Re-run the same Lighthouse and DevTools profile after the change. Keep a one-page before/after note: &lt;em&gt;third-party main-thread ms&lt;/em&gt;, &lt;em&gt;LCP&lt;/em&gt;, &lt;em&gt;INP&lt;/em&gt; (if you have field data in &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://search.google.com/search-console&quot;&gt;Search Console’s Core Web Vitals report&lt;/a&gt; or RUM), and a screenshot of the GTM version number. If someone re-imports a container without your fixes, you have an audit trail.&lt;/p&gt;&lt;p&gt;For portfolios, that proof is the difference between “we sped you up” and “we keep you fast when the next tag ships”. Tying the numbers to a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-set-up-automated-pagespeed-monitoring-for-multiple-sites&quot;&gt;monitoring&lt;/a&gt; or budget alert means a regression is an email, not a surprise in a QBR. Apogee Watcher is built for that loop: schedule PageSpeed runs, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-budget-thresholds-template&quot;&gt;set budgets&lt;/a&gt; per site or template, and get alerts when lab metrics drift. We do not replace your tag manager; we give you a steady signal that the work you just shipped (or the tag someone added at 5 p.m. Friday) is still within the thresholds you and the client agreed.&lt;/p&gt;&lt;p&gt;If you are still building a governance story for your team, the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/core-web-vitals-monitoring-checklist-for-agencies&quot;&gt;Core Web Vitals monitoring checklist for agencies&lt;/a&gt; is a good companion: it includes a third-party pass as part of ongoing ops, not a one-off launch audit.&lt;/p&gt;&lt;h2&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Are third-party scripts the main cause of bad Core Web Vitals?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not always, but they are a common cause of high INP and TBT, and they keep turning up in audits for LCP and CLS when they shift layout or delay rendering. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://web.dev/articles/tbt&quot;&gt;TBT in the lab and INP in the field are related but not the same&lt;/a&gt; (post-load interactions matter for INP). &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/5-common-pagespeed-mistakes-that-are-killing-your-website&quot;&gt;Your own images and font strategy&lt;/a&gt; still matter. Treat third parties as a parallel track you measure with the same rigour as first-party code.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should I use only field data to prioritise?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Field data (CrUX, RUM) tells you who suffers in the real world. Lab data and DevTools help you &lt;em&gt;attribute&lt;/em&gt; that pain to a specific script before you change contracts or tags. Use both. For more on the split, read &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights vs automated monitoring: when manual checks are not enough&lt;/a&gt; and &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://apogeewatcher.com/blog/understanding-inp-newest-core-web-vital&quot;&gt;Understanding INP: the newest Core Web Vital&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What is the fastest win?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In our experience, the fastest win is cutting duplicate tags and loading chat and secondary widgets after load or on interaction, before you touch your core bundle. The slowest is migrating to full server-side tagging, which pays off for large programmes but is not a Friday afternoon change.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Will delaying analytics break reporting?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It can change “session” definitions if you delay too aggressively or if your vendor counts page views before a delayed tag fires. Align with whoever owns the data model. Often you can still send one lightweight pageview early and load heavier remarketing and enrichment after idle.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How do I explain this to a non-technical stakeholder?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Framed the right way, it is a cost conversation: every script has a time cost on the user’s device. The table from Lighthouse, plus one before/after number for LCP or INP, is usually enough to get approval for a staged rollout.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/15959/third-party-scripts-and-performance-how-to-identify-and-fix-the-worst-offenders</guid>
<pubDate>Mon, 27 Apr 2026 09:12:45 +0000</pubDate>
</item>
</channel>
</rss>