Third-Party Scripts and the Main-Thread Bottleneck

Website performance is typically measured through user-centric metrics such as time to interactive (TTI), total blocking time (TBT), and first input delay (FID). These metrics matter because the majority of the world's users do not have access to high-speed Internet or fast CPUs. Even a well-designed site can become unusable for these users if it is weighed down by heavy assets. The average web page now exceeds 2 megabytes and triggers over 200 requests, with third-party scripts frequently accounting for a significant portion of that load.

Third-party scripts—code embedded in your site but not under your developers' control—compete directly with your own JavaScript for the browser's main thread. This competition delays content rendering and makes sites feel sluggish. Google's Web Fundamentals documentation lists several common issues caused by these scripts, including excessive network requests, resource-intensive parsing and execution, poor HTTP caching, and the use of harmful legacy APIs like document.write(). On mobile devices, all this JavaScript is why the average web page takes more than 14 seconds to load and become interactive. That slowness hurts Lighthouse scores, Core Web Vitals, and search rankings.

The core problem is that JavaScript is a single-threaded language. Even with modern techniques like minification, code-splitting, and async or defer attributes, only one script can execute on the main thread at a time. Offloading third-party scripts to web workers running in background threads is an attractive solution, but it introduces a challenge: web workers lack direct DOM access and communicate with the main thread only asynchronously via postMessage. Any approach must provide synchronous DOM access from within the worker while keeping the underlying communication asynchronous.

Moving Scripts to Background Threads with Partytown

Partytown is a lightweight, open-source library maintained by Builder.io that addresses this challenge. It is currently in beta. Partytown offloads resource-intensive third-party scripts into a web worker, freeing up the browser's main thread to run your first-party code—the code responsible for handling user input and painting the screen. It does not solve every third-party script bottleneck, but it targets the biggest ones by:

  • Freeing main-thread resources for primary web app execution;
  • Sandboxing third-party scripts and allowing or denying their access to main-thread APIs;
  • Isolating long-running tasks within the web worker thread;
  • Reducing layout thrashing by batching DOM setters and getters into group updates;
  • Throttling third-party scripts' access to the main thread;
  • Executing third-party scripts exactly as they are coded, with no alterations.

The architecture relies on lazy-loaded JavaScript to redirect scripts to a worker. Consider Google Analytics, which uses navigator.sendBeacon() to send tracking data. This is a background task that could run asynchronously, but Google Analytics still requires synchronous DOM API access when reading values from document and window. Partytown enables scripts like this to run from the background while accessing the DOM as if they were on the main thread.

Diagram showing how Partytown redirects third-party scripts to a web worker

The Synchronous Proxy Mechanism

Partytown achieves synchronous DOM access from within a web worker by combining JavaScript proxies, service workers, and synchronous XHR requests. DOM API access inside the worker is proxied. When a third-party script accesses something like document.title or window.screen.width, the proxy creates a synchronous XHR request containing the methods and values being accessed.

A service worker intercepts these requests and uses postMessage to relay them to the main thread asynchronously. However, because each DOM API request is mapped to a synchronous XHR, the web worker pauses its execution until the service worker responds. From the third-party script's perspective, the operation is fully synchronous.

This approach means you do not need to rewrite or refactor third-party scripts to work within a web worker. The scripts execute exactly as coded, simply running from the background thread instead. Additionally, since all DOM API access is proxied, Partytown can log every read and write and restrict access to specific DOM APIs if needed.

Opting In and Setting Up

Partytown does not automatically move all third-party scripts to a web worker. Developers must explicitly choose which scripts run through Partytown by installing the library via npm and adding the type="text/partytown" attribute to each targeted script.

import { partytownSnippet } from '@builder.io/partytown/integration';

This attribute serves two purposes: it prevents the main thread from executing the script, and it provides a selector for Partytown to query, such as document.querySelectorAll('script[type="text/partytown"]').

<script type="text/partytown">
    // Third-party script code to offload
</script>

The next step is inlining the Partytown snippet in the <head> of your page. If you are using React, the recommended approach is using the <Partytown/> React component. Partytown works with any HTML page and does not require a specific framework, though integrations are available for Next.js, Nuxt.js, React, and Shopify Hydrogen. The project also provides walkthroughs for common services like Facebook Pixel, Adobe Launch, and Google Tag Manager.

<Partytown />

A minor amount of configuration may be required for special cases. Builder.io recommends testing Partytown on a few pages first and measuring improvements with Google PageSpeed Insights before enabling it sitewide.

Real-World Impact

The Builder.io website combined Partytown with Qwik, Builder.io's open-source HTML-first framework, to cut 99% of its JavaScript. This produced a 100/100 Google Lighthouse score on PageSpeed Insights even on mobile, along with significant decreases in total blocking time and time to interactive. The online footwear store Atoms uses Partytown on several marketing pages, including Why Atoms, About, Press, and Gift Cards, and is working to enable it across the entire site.

Who Is Partytown For?

Partytown is currently in beta, and Builder.io acknowledges that not every third-party script is compatible. The team maintains a public list of trade-offs and known limitations, and encourages developers to test the library in real projects. Feedback and contributions are welcome via the Partytown GitHub repository, where users can file issues, request integrations, or submit code.

The larger goal at Builder.io is making high performance the default rather than the exception. The company believes fast sites should not require elaborate configuration, and it has pursued that vision with open-source projects like Partytown and Qwik. Both tools are aimed at reducing the JavaScript burden on the main thread, which is a key step toward making near-zero-JavaScript websites achievable for a wider range of developers.

Current Status and Community Input

Because Partytown is still in active development, real-world usage is shaping its roadmap. Builder.io is specifically looking for developers to test edge cases and report their findings. This feedback loop is critical for improving script compatibility and for growing the list of officially supported integrations.

Beyond Partytown itself, the Builder.io ecosystem includes Qwik, a framework designed for resumability and minimal hydration. Together, these projects represent a push toward shifting heavy work off the main thread and reducing the amount of JavaScript that must be downloaded and executed upfront.

Additional References

Further Reading on Performance and Architecture

Smashing Editorial