HomeMethod

Knowledge

Web VitalsTechniquesSnippetsAnswersImpactsBottlenecks

Third-Party Scripts in Service Worker

Move third-party analytics and tracking scripts off the main thread by running them in a service worker.

Overview

A service worker is a JavaScript worker that runs in a background thread, separate from the browser’s main thread. Third-party scripts that do not interact with the DOM — analytics trackers, conversion pixels, A/B testing data collectors, and session recorders — can be proxied through a service worker to remove their execution overhead from the main thread entirely. The technique is sometimes called ‘party town’ after the Partytown library, which automates the migration.

Impact grade, A+ to D: how much of the Lighthouse score this technique can move. Unaffected: LCP, CLS, TTFB.

The Problem

Third-party analytics and marketing scripts collectively represent the largest non-controllable source of main thread blocking on most marketing-oriented WordPress sites. Google Tag Manager, Facebook Pixel, LinkedIn Insight, Hotjar, Intercom, and similar tools download and execute JavaScript that occupies the main thread for 50–400 ms each. Combined, a typical marketing site may load 8–15 such scripts, collectively blocking the main thread for 2–5 seconds. This directly inflates Total Blocking Time and degrades Interaction to Next Paint scores.

Performance Impact

TBT

20–60%

third-party script execution moved off main thread eliminates their contribution to long tasks

FCP

Indirect

less main-thread competition during initial render benefits first contentful paint

SI

Indirect

earlier FCP due to freed main thread contributes to faster visual fill

INP

Significant

main thread is substantially more available for interaction processing when 3P scripts run in worker

Risk: Medium

DOM-dependent scripts are incompatible; requires specific COOP/COEP HTTP headers that may break third-party iframes

How it works

  1. 01

    Service workers run in a separate thread

    Service workers execute in a background thread that cannot directly access the DOM. They communicate with the main thread via the postMessage API. For analytics scripts that only send data to external servers (they read cookies and properties, then fire XHR/fetch requests), this communication overhead is negligible.

  2. 02

    Partytown proxies DOM access

    The Partytown library solves the DOM access problem by using a synchronous-looking proxy: when a third-party script in the worker calls document.cookie, Partytown serializes the call, sends it to the main thread via postMessage, returns the result synchronously (via Atomics.wait), and returns control to the worker. Scripts see a real DOM interface while executing entirely off-thread.

  3. 03

    Identify compatible scripts

    Scripts that only read from the DOM and send data to external APIs are ideal candidates: Google Analytics 4, Facebook Pixel, LinkedIn Insight Tag, HubSpot, and Segment. Scripts that manipulate the DOM (injecting banners, modifying page content) are incompatible and must remain on the main thread.

  4. 04

    WordPress integration via script_loader_tag

    For each compatible third-party script, change its type attribute to text/partytown. Partytown intercepts script tags with this type and routes them to the worker. In WordPress, this is done via the script_loader_tag filter.

Code Example

Before
<!-- Google Tag Manager: executes on main thread, blocks interaction -->
<script async src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXX"></script>
After
<!-- type="text/partytown" routes execution to service worker -->
<script type="text/partytown" src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXX"></script>

<!-- Partytown config (add before partytown.js) -->
<script>
  partytown = {
    lib: '/wp-content/themes/my-theme/js/~partytown/',
    forward: ['dataLayer.push'] // forward GTM dataLayer calls from main thread to worker
  };
</script>
<script src="/wp-content/themes/my-theme/js/~partytown/partytown.js"></script>

Download Partytown via npm: npm install @builder.io/partytown. Copy the files from node_modules/@builder.io/partytown/lib to your theme’s JS directory. Configure the lib path to point to that directory.

Limitations

  • Scripts that modify the DOM — injecting HTML, adding event listeners to elements, or reading element sizes — cannot run in a service worker and must remain on the main thread.
  • Partytown’s synchronous DOM proxy uses Atomics.wait, which requires SharedArrayBuffer. This requires specific HTTP response headers: Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp — which may break third-party iframes (ads, embeds).
  • Debug complexity increases: scripts running in a worker are harder to inspect in DevTools. Errors in proxied scripts may appear with less context than main-thread errors.

Common Mistakes

Moving GTM to a service worker without forwarding the dataLayer

If your main-thread code pushes events to dataLayer (e.g., from button click handlers), those calls must be forwarded to the worker where GTM is running. Configure Partytown’s forward option to include all calls that cross the thread boundary.

Assuming all analytics scripts are compatible without testing

Test each script individually in Partytown’s sandbox before deploying to production. Conversion tracking scripts that read from the DOM (e.g., Hotjar session recording) are typically incompatible and will produce silent failures — events stop firing with no visible error.

Test this techniqueThird PartyRun the tool

Targeted fixes, not guesswork.

Start an Engagement
Support our family now