The Real Cost of Third-Party Scripts
Performance budgets and code-level optimizations are fine in theory, but the reality for many sites is that a significant portion of page weight comes from third-party scripts. Analytics, heatmaps, A/B testing, personalization — these are often dropped in via a tag manager, making it trivially easy for anyone on the team to add another script without much thought about the consequences. The result is a crowded main thread where every resource competes for attention.
The main thread is the single lane of traffic for all page activity. HTML parsing, CSS handling, rendering, and JavaScript execution all happen there. JavaScript is single-threaded with one call stack and one memory heap, meaning code executes synchronously in order. If one function takes too long, everything behind it gets blocked. This is what the “fight for the main thread” really describes: the competition between your own code and the growing pile of third-party scripts your site depends on.
Using Reports to Diagnose Blocking
Lighthouse in DevTools is usually the first stop for performance diagnosis. It provides the standard metrics: Time to First Byte (TTFB), First Contentful Paint (FCP), Largest Contentful Paint (LCP), and Cumulative Layout Shift (CLS). But those scores don't tell you what is causing the problem.
The Total Blocking Time (TBT) metric gets closer — it measures the time between FCP and Time to Interactive (TTI). A high TBT means the main thread is so busy that the user can't interact with the page in a reasonable time. In a heavy site test with a more detailed tool, the TBT can easily stretch into the thousands of milliseconds. That kind of delay is unacceptable even on a desktop machine with a high-speed connection.
Long Tasks and Waterfalls
The real culprits behind high TBT are long tasks — JavaScript operations that run for more than 50 milliseconds. Reports that highlight these long tasks in the timeline make it easier to spot where the problems are.
Waterfall views add another layer of detail. Beyond showing what loads at each point in time, expanded views reveal whether individual assets are blocking the thread, and by how much. Assets loading before FCP are the most important suspects.
Digging further can separate first-party from third-party scripts, showing which developers own the problem.
Once you identify a specific third-party source as a blocker, you can set up custom tracking to monitor its behavior over time. Comparing its requests, sizes, long tasks, and render-blocking behavior against other assets builds a solid case for optimization or removal.
From First Input Delay to Interaction to Next Paint
First Input Delay (FID) has been the core Web Vital for measuring load responsiveness, looking at the delay between a user's first interaction — a click, keydown, or pointerdown event, for example — and the browser's response. FID is hard to replicate in lab settings since it depends on real user interactions, but it correlates with TBT, making TBT a useful lab proxy for identifying long tasks.
Starting in March 2024, a new metric will replace FID: Interaction to Next Paint (INP). FID's key limitation is that it looks only at the first interaction. INP measures the responsiveness of all interactions on a page, aiming to keep the pause between user input and the next painted frame as short as possible, not just for the first interaction but throughout the session.
“The goal of INP is to ensure the time from when a user initiates an interaction until the next frame is painted is as short as possible for all or most interactions the user makes.” — Jeremy Wagner
INP is even more strongly correlated with TBT than FID was. It captures a fuller picture of responsiveness, covering interactions that take longer to respond alongside fast ones. Performance monitoring services are already integrating INP into their dashboards. One report shows INP worsening as the total time of long tasks increases across visitors.
That kind of continuous monitoring provides insight not just into isolated tests, but into how real users experience the page over time, which is what the main-thread fight ultimately comes down to.
Weighing the Cost of a Script
Scripts aren't inherently bad. The problem is that many are loaded without a clear sense of what they actually cost. Before adding anything to a page, it helps to ask a few pointed questions about who it serves, when it needs to run, and where it lives.
Who Benefits From It?
Some scripts benefit the business. Others benefit the user. Web fonts are a rare case where they can do both — a font is both a branding asset and a legibility aid. But even then, the cost is real. Instead of cutting fonts entirely, you might optimize them: self-host the files to avoid an extra third-party connection, or load only a subset of characters.
Analytics is a harder call. For a small site, the data may rarely justify the cost of the script. But for a business that relies on usage reports to guide improvements, analytics can be essential. If a script genuinely serves the user in some way, it is worth keeping. If it only serves internal reporting, it's worth scrutinizing harder.
When Does It Really Need to Run?
A script can be useful without being urgent. Customer support chat is a good example. It's valuable for e-commerce and SaaS, but a user can't benefit from it if the rest of the page is still loading. Loading the widget up front only makes everything else slower. It's better to defer that work until the core content is interactive.
Where Is It Coming From?
Third-party scripts don't have to live on third-party domains. Font files can be self-hosted, analytics can be run from your own infrastructure, and even Google Tag Manager supports custom domains. The point is to look beyond just what a script does and consider the cost of the extra connection. Grouping first- and third-party resources in your monitoring reports makes it easier to spot those opportunities.
What Else Does It Load?
A single script rarely loads alone. Many third-party scripts pull in their own stylesheets and additional assets, which all need to be fetched and rendered. You might think you're loading one file, but you can end up paying for a chain of dependencies.
Shifting Work Off the Main Thread
The goal is to reduce the amount of JavaScript that runs on the main thread. There are several well-established techniques for doing this, and each has its own tradeoffs.
Web Workers
Web Workers allow you to run tasks on separate threads, parallel to the main thread. They don't have direct DOM access and can't share variables with the main thread, but they are effective for offloading heavy computation. This approach is well documented across the Web Workers spec, MDN's guide, and articles on off-main-thread work and handling long-running tasks in React apps.
Code Splitting
Instead of shipping one large JavaScript bundle, code splitting breaks the code into smaller pieces. The browser only downloads what's needed for the current page, which reduces the parsing and execution work. You can split code at the route level, the component level, or with tools like Next.js's built-in support.
Async and Defer
The async and defer attributes both let scripts load without blocking the DOM, but they behave differently. With async, the script executes as soon as it's downloaded. With defer, it waits until the DOM is fully parsed. Choosing between them depends on whether the script can run before the page is ready.
Preconnecting Early
The preconnect value on the rel attribute of a <link> tag tells the browser to establish a connection to another domain early. That saves time later when the actual resource is requested. The downside: it exposes the user's IP address to that third party, which has GDPR implications, particularly for resources like Google Fonts.
Non-Technical Fixes
Not every performance problem has a code-level solution. Some are organizational. Developers see every issue as a technical one, but the culture and process around how scripts get added often matter just as much.
Identify Script Owners
Many scripts end up on a page with no clear owner. Tag managers make it easy for different teams to inject scripts, and soon no one remembers why a particular tag is there. It's worth auditing the page for third-party and render-blocking scripts, then tracking down whoever is responsible for each one. An honest conversation about what's actually critical can lead to removing a lot of dead weight.
Use Tag Managers for Management
Tag managers have a bad reputation for bloating pages, but that's usually a misuse of the tool. The real value of a tag manager isn't just that it makes adding tags easy — it's that it provides controls for when and how those tags run. Used properly, it can be a way to keep scripts in check rather than a source of bloat.
Performance Is A Judgment Call
Performance work rarely ends with a single, definitive answer. While metrics provide objective data, the interpretation of that data is deeply subjective. Scripts differ in size, resources, and purpose, and what matters most to one organization’s users may be irrelevant to another’s. There is no universal threshold for “fast enough,” only the question of whether your specific scripts meet your specific goals.
Free tools like Lighthouse in DevTools are a practical entry point for diagnosing main-thread bottlenecks. They give you a baseline without requiring a budget. For deeper analysis, paid options such as SpeedCurve can surface more targeted insights and generate visual reports that help communicate the case for performance work to teammates and stakeholders.
None of these tools are a silver bullet. They are starting points that only become valuable when paired with a deliberate performance strategy. A structured checklist can help you move from raw data to actionable priorities.




