Trade-Offs

Nothing is without trade-offs. Using Partytown to orchestrate third-party scripts vs. adding them to your pages the traditional way has the following considerations:

Intercepted Network Requests

You'll notice in the network tab there may be hundreds of requests to proxytown. Even though these requests are listed in the network tab, each of these are intercepted by the service worker and handled by Partytown locally, and they are not external HTTP requests. Using these locally intercepted network requests is how the service worker communication layer is able to work.

These requests showing up are more of an annoyance than anything else, since they shouldn't be affecting performance or Lighthouse scores. Additionally, they can give you an insight into what certain third-party scripts are up to. See the debugging documentation for more info.

To hide them while debugging, filter them out of the network tab with -url:proxytown in Chrome DevTools.

Throttled DOM Operations

DOM operations within the worker are purposely throttled, slowing down their execution compared to the same code running on the main thread. (We also see this as a feature.) Because their code is running in another thread and needs to send and receive data between the two, it may take a few milliseconds to perform a blocking operation. This ties into why UI intensive scripts may not be the best fit for Partytown.

Partytown does however batch most operations together to reduce the calls between threads.

UI Intensive Third-Party Scripts

For a third-party script that is UI intensive, meaning the script builds up a mini-app within your page, Partytown may not be best suited for that script. For example, the third-party script may popup a dialog with a form inside of it.

Every script is different, and each are performing operations in different ways, so it's difficult to state exactly which services do and do not work well with Partytown. While Partytown may work great for some UI implementations, it may not work well for others. For this reason, Partytown is opt-in, and you can explicitly set which scripts to use it on.

Partytown is best suited for third-party scripts such as Google Tag Manager or Facebook Pixel, since they're only handling user events and lazily posting data to their services in the background. Third-party scripts that insert a large amount of DOM nodes to a page may not be the best candidates.

Third-Party Scripts Without CORS Headers

While most third-party scripts add the correct Cross-Origin Resource Sharing (CORS) headers, such as Access-Control-Allow-Origin: *, not all do. Please see the Proxying Requests documentation on how to use Partytown with any services that do not add the correct headers.

Events Cannot Prevent Default

Events handled by third-party scripts that call event.preventDefault() will have no effect. Partytown is able to block when the code is ran within the web worker, but not in the other direction.

For example, when a user clicks a link on the main thread, a third-party script may have an event handler on that same link, which may have event.preventDefault(). By the time the web worker receives an event that the link was clicked, it is no longer a synchronous operation and calling preventDefault() has no effect. As a side note, you could also see this as a feature when third-party scripts are abusing scroll events without using passive event listeners.

Cross-Origin IFrame Cookies And Storage

If an iframe was created with Partytown, and the iframe is cross-origin, then Partytown is unable to get or set the origin's document.cookie, localStorage or sessionStorage. The code will continue to work, however, cookies and storage will not persist.

Setting document.cookie is a noop and will not assign anything, and getting a cookie will always return an empty string. Both localStorage and sessionStorage work as expected, however, the localStorage data is not saved across browser sessions. In these scenarios a console.warn will be logged.

Note this is only an issue for iframes, created from within a Partytown script, and the created iframe is cross-origin. Partytown scripts, and iframes that have the same origin, do not have this issue.

Page Exit Events

Handlers that third-party scripts add for page exit events, such as pagehide, visibilitychange and beforeunload, are not reliable when the page is unloading (a real navigation, reload or tab close; SPA route changes are not affected).

The main thread only forwards the event to the web worker and returns right away, so the browser goes on to unload the page. The web worker belongs to the page and is terminated with it, often before the handler has run. Even when the handler does start, any DOM read it makes (such as document.cookie or document.hasFocus()) needs an answer from the main thread, which is no longer available. The main thread cannot wait for the web worker either, since browsers block synchronous requests during page dismissal.

For example, the automatic Google Analytics 4 user_engagement event, which reports the remaining engagement time when the user leaves the page, is not sent when GA4 runs in Partytown. Events sent while the page is open, such as page_view, are not affected. If exit tracking is important, load that script on the main thread instead.

Service Worker

For the Service Worker build, a total of three threads are used: Main Thread, Web Worker, and Service Worker. Note that the Atomics build only uses two threads.

Not Always The Best Fit

While Partytown works great for some third-party scripts, it may not be the best fit for every single script out there (and that's ok). For example, some third-party scripts have a setInterval() loop that continually reads through the entire document every X milliseconds. This is just bad practice to begin with, but when these scripts are run from Partytown then it's visible that Partytown is overworked trying to keep up the script's layout thrashing code. Since every script is different, it's difficult to state exactly which scripts do and do not work well with Partytown. For this reason, Partytown is opt-in, and you can explicitly set which scripts to use it on.