DEV Community

Alex Spinov
Alex Spinov

Posted on

Partytown Has Free Web Worker Magic — Here's How to Move Third-Party Scripts Off the Main Thread

Google Analytics, Facebook Pixel, chat widgets — they all block your main thread. Partytown moves them to a web worker so your site stays fast.

The Problem

Third-party scripts (analytics, ads, chat) can add 500ms-2s to your page load. They compete with your app for the main thread.

The Solution

Partytown runs third-party scripts in a web worker. Your main thread stays free for your app.

Before: Main Thread = Your App + Analytics + Ads + Chat (competing)
After:  Main Thread = Your App only (fast)
        Web Worker  = Analytics + Ads + Chat (isolated)
Enter fullscreen mode Exit fullscreen mode

Quick Start

bun add @builder.io/partytown
Enter fullscreen mode Exit fullscreen mode

Vanilla HTML

<script>
  partytown = { forward: ['dataLayer.push'] };
</script>
<script src="/~partytown/partytown.js"></script>

<!-- Add type="text/partytown" to move scripts to worker -->
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>
<script type="text/partytown">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXX');
</script>
Enter fullscreen mode Exit fullscreen mode

Next.js

import Script from 'next/script';

export default function Layout({ children }) {
  return (
    <html>
      <head>
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"
          strategy="worker"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Astro

---
import { Partytown } from '@builder.io/partytown/integration';
---
<html>
  <head>
    <Partytown forward={['dataLayer.push']} />
    <script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>
  </head>
</html>
Enter fullscreen mode Exit fullscreen mode

What Scripts Can Be Moved

  • Google Analytics / GTM
  • Facebook Pixel
  • Intercom / Drift / Crisp chat
  • Hotjar / FullStory
  • Any script that does not directly manipulate visible DOM

Performance Impact

Lighthouse Score (typical e-commerce site):
Before Partytown: 62
After Partytown:  89

Total Blocking Time:
Before: 1,200ms
After:  300ms
Enter fullscreen mode Exit fullscreen mode

Configuration

import { Partytown } from '@builder.io/partytown/react';

<Partytown
  forward={['dataLayer.push', 'fbq']}  // Forward these calls to worker
  resolveUrl={(url) => {                 // Proxy third-party scripts
    if (url.hostname === 'www.googletagmanager.com') {
      return new URL(`/proxy?url=${encodeURIComponent(url.href)}`, location.origin);
    }
    return url;
  }}
/>
Enter fullscreen mode Exit fullscreen mode

How It Works

  1. Partytown intercepts <script type="text/partytown"> tags
  2. Moves them to a Web Worker
  3. Creates a synchronous-like DOM API proxy using Atomics and SharedArrayBuffer
  4. Third-party scripts think they are on the main thread (they access document, window, etc.)
  5. Main thread stays unblocked

Need to optimize your data pipeline too? Check out my Apify actors — fast, optimized web scraping. For custom solutions, email spinov001@gmail.com.

Top comments (0)