# Technical Documentation: QwikDev/partytown

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/QwikDev/partytown)

### Overview (`README.md`)

# Partytown 🎉

<img width="838" alt="Partytown github fit 2x" src="https://user-images.githubusercontent.com/452425/134568488-f36f4640-9ada-4a78-a969-2b8315cf7f47.png">

- [Introducing Partytown: Run Third-Party Scripts From a Web Worker](https://dev.to/adamdbradley/introducing-partytown-run-third-party-scripts-from-a-web-worker-2cnp)
- [How Partytown's Sync Communication Works](https://dev.to/adamdbradley/how-partytown-s-sync-communication-works-4244)
- [How we cut 99% of our JavaScript with Qwik + Partytown](https://www.builder.io/blog/how-we-cut-99-percent-js-with-qwik-and-partytown)
- [Partytown is now in Beta](https://www.builder.io/blog/partytown-is-now-in-beta)

> A fun location for your third-party scripts to hang out

Partytown is a lazy-loaded library to help relocate resource intensive scripts into a [web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), and off of the [main thread](https://developer.mozilla.org/en-US/docs/Glossary/Main_thread). Its goal is to help speed up sites by dedicating the main thread to your code, and offloading third-party scripts to a web worker.

> Note: Partytown is not guaranteed to work in every scenario. Please see our [FAQ](https://partytown.qwik.dev/faq) and [Trade-Off](https://partytown.qwik.dev/trade-offs) sections for more info.

The philosophy is that the main thread should be dedicated to your code, and any scripts that are not required to be in the [critical path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path) should be moved to a web worker. Main thread performance is, without question, more important than web worker thread performance.

- [Getting Started](https://partytown.qwik.dev/getting-started)
- [Integrations](https://partytown.qwik.dev/integrations)
- [Configuration](https://partytown.qwik.dev/configuration)
- [Releases](https://github.com/BuilderIO/partytown/releases)
- [FAQs](https://partytown.qwik.dev/faq)



## Community

- [@QwikDev](https://twitter.com/QwikDev)
- [@Builderio](https://twitter.com/builderio)
- [Local Development](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#local-development)
- [For Plugin Authors / Developers](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#plugin-authors-developers)

## Related Projects

- [Qwik](https://github.com/BuilderIO/qwik): An open-source framework designed for best possible time to interactive, by focusing on resumability of server-side-rendering of HTML, and fine-grained lazy-loading of code.
- [Mitosis](https://github.com/BuilderIO/mitosis): Write components once, run everywhere. Compiles to Vue, React, Solid, Angular, Svelte, and more.
- [Builder](https://github.com/BuilderIO/builder): Drag and drop page builder and CMS for React, Vue, Angular, and more.

<br>
<br>
<p align="center">
   <a href="https://www.builder.io/m/developers">
      <picture>
         <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/844291/230786554-eb225eeb-2f6b-4286-b8c2-535b1131744a.png">
         <img width="250" alt="Made with love by Builder.io" src="https://user-images.githubusercontent.com/844291/230786555-a58479e4-75f3-4222-a6eb-74c5af953eac.png">
       </picture>
   </a>
</p>

---

### Overview (`.changeset/README.md`)

# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

---

### Overview (`docs/README.md`)

# Qwik App ⚡️

- [Qwik Docs](https://qwik.dev/)
- [Discord](https://qwik.dev/chat)
- [Qwik GitHub](https://github.com/QwikDev/qwik)
- [@QwikDev](https://twitter.com/QwikDev)
- [Vite](https://vitejs.dev/)

---

## Project Structure

This project is using Qwik with [QwikRouter](https://qwik.dev/docs/). QwikRouter is just an extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more.

Inside your project, you'll see the following directory structure:

```
├── public/
│   └── ...
└── src/
    ├── components/
    │   └── ...
    └── routes/
        └── ...
```

- `src/routes`: Provides the directory-based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.dev/docs/routing/) for more info.

- `src/components`: Recommended directory for components.

- `public`: Any static assets, like images, can be placed in the public directory. Please see the [Vite public directory](https://vitejs.dev/guide/assets.html#the-public-directory) for more info.

## Add Integrations and deployment

Use the `pnpm qwik add` command to add additional integrations. Some examples of integrations includes: Cloudflare, Netlify or Express Server, and the [Static Site Generator (SSG)](https://qwik.dev/docs/guides/static-site-generation/).

```shell
pnpm qwik add # or `pnpm qwik add`
```

## Development

Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development.

```shell
npm start # or `pnpm start`
```

> Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build.

## Preview

The preview command will create a production build of the client modules, a production build of `src/entry.preview.tsx`, and run a local server. The preview server is only for convenience to preview a production build locally and should not be used as a production server.

```shell
pnpm preview # or `pnpm preview`
```

## Production

The production build will generate client and server modules by running both client and server build commands. The build command will use Typescript to run a type check on the source code.

```shell
pnpm build # or `pnpm build`
```

## Cloudflare Pages

Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run:

```
pnpm serve
```

Then visit [http://localhost:8787/](http://localhost:8787/)

### Deployments

[Cloudflare Pages](https://pages.cloudflare.com/) are deployable through their [Git provider integrations](https://developers.cloudflare.com/pages/platform/git-integration/).

If you don't already have an account, then [create a Cloudflare account here](https://dash.cloudflare.com/sign-up/pages). Next go to your dashboard and follow the [Cloudflare Pages deployment guide](https://developers.cloudflare.com/pages/framework-guides/deploy-anything/).

Within the projects "Settings" for "Build and deployments", the "Build command" should be `pnpm build`, and the "Build output directory" should be set to `dist`.

### Function Invocation Routes

Cloudflare Page's [function-invocation-routes config](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes) can be used to include, or exclude, certain paths to be used by the worker functions. Having a `_routes.json` file gives developers more granular control over when your Function is invoked.
This is useful to determine if a page response should be Server-Side Rendered (SSR) or if the response should use a static-site generated (SSG) `index.html` file.

By default, the Cloudflare pages adaptor _does not_ include a `public/_routes.json` config, but rather it is auto-generated from the build by the Cloudflare adaptor. An example of an auto-generate `dist/_routes.json` would be:

```
{
  "include": [
    "/*"
  ],
  "exclude": [
    "/_headers",
    "/_redirects",
    "/build/*",
    "/favicon.ico",
    "/manifest.json",
    "/service-worker.js",
    "/about"
  ],
  "version": 1
}
```

In the above example, it's saying _all_ pages should be SSR'd. However, the root static files such as `/favicon.ico` and any static assets in `/build/*` should be excluded from the Functions, and instead treated as a static file.

In most cases the generated `dist/_routes.json` file is ideal. However, if you need more granular control over each path, you can instead provide you're own `public/_routes.json` file. When the project provides its own `public/_routes.json` file, then the Cloudflare adaptor will not auto-generate the routes config and instead use the committed one within the `public` directory.

---

### Overview (`tests/nextjs/README.md`)

```bash
npm run dev
```

[http://localhost:3000](http://localhost:3000)

---

### Src Routes Index (`docs/src/routes/index.mdx`)

---
title: Introduction
description: Partytown - Run third-party scripts from a web worker
---

# Run third-party scripts from a web worker

Partytown is a lazy-loaded library to help relocate resource-intensive scripts into a [web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), and off of the [main thread](https://developer.mozilla.org/en-US/docs/Glossary/Main_thread). Its goal is to help speed up sites by dedicating the main thread to your code, and offloading third-party scripts to a web worker.

> Note: Partytown is not guaranteed to work in every scenario. Please see our [FAQ](/faq) and [Trade-Off](/trade-offs) sections for more info.

Even with a fast and highly tuned website following all of today's best practices, it's all too common for your performance wins to be erased the moment third-party scripts are added. By third-party scripts we mean code that is embedded within your site, but not directly under your control. A few examples include: analytics, metrics, ads, A/B testing, trackers, etc.

Partytown is maintained by [QwikDev](https://github.com/QwikDev).

- [Partytown, Google Slides Presentation](https://docs.google.com/presentation/d/10aKHUokby6hQydL_xuOtct4CPwAkgay5l0-FqgO8-3g/edit?usp=sharing)
- [Smashing Magazine: How Partytown Eliminates Website Bloat From Third-Party Scripts](https://www.smashingmagazine.com/2022/04/partytown-eliminates-website-bloat-third-party-apps/)

## Goals

We set out to solve this situation, so that apps of all sizes will be able to continue to use third-party scripts without the performance hit. Some of Partytown's goals include:

- Free up main thread resources to be used only for the primary web app execution.
- Sandbox third-party scripts and allow or deny their access to main thread APIs.
- Isolate long-running tasks within the web worker thread.
- Reduce layout thrashing coming from third-party scripts by batching DOM setters/getter into group updates.
- Throttle third-party scripts' access to the main thread.
- Allow third-party scripts to run exactly how they're coded and without any alterations.
- Read and write main thread DOM operations _synchronously_ from within a web worker, allowing scripts running from the web worker to execute as expected.

## Web Workers

Partytown's philosophy is that the main thread should be dedicated to your code, and any scripts that are not required to be in the [critical path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path) should be moved to a [web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). Main thread performance is, without question, more important than web worker thread performance. Please see the [test pages in the repository](https://github.com/QwikDev/partytown/tree/main/tests) for examples you can run locally.



## Negative Impacts from Third-Party Scripts

Below is a summary of potential issues after adding third-party scripts, referenced from [Loading Third-Party JavaScript](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript):

- Firing too many network requests to multiple servers. The more requests a site has to make, the longer it can take to load.
- Sending too much JavaScript which keeps the main thread busy. Too much JavaScript can block DOM construction, delaying how quickly pages can render.
- CPU-intensive script parsing and execution can delay user interaction and cause battery drain.
- Third-party scripts that were loaded without care can be a single-point of failure (SPOF).
- Insufficient HTTP caching, forcing resources to be fetched from the network often.
- The use of legacy APIs (e.g `document.write()`), which are known to be harmful to the user experience.
- Excessive DOM elements or expensive CSS selectors.
- Including multiple third-party embeds that can lead to multiple frameworks and libraries being pulled in several times, which exacerbates the performance issues.
- Third-party scripts also often use embed techniques that can block `window.onload`, even if the embed is using async or defer.

## Use-Cases

While full webapps "can" run from within Partytown, it's actually best intended for code that doesn't need to be in the [critical rendering path](https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path). Most third-party scripts fall into this category, as they're not required for the first-paint. Additionally, the asynchronous nature of most third-party script works well with Partytown, as they can lazily receive user events and post data to their respective services.

Below are just a few examples of third-party scripts that might be a good candidate to run from within a web worker. The goal is to continue validating commonly used services to ensure Partytown has the correct API, but Partytown itself does not hardcode to any specific services. Help us test and contribute to this page in Github when you find good working scripts!

- [Google Tag Manager (GTM)](https://marketingplatform.google.com/about/tag-manager/)
- [Google Analytics (GA)](https://analytics.google.com/)
- [Facebook Pixel](https://www.facebook.com/business/learn/facebook-ads-pixel)
- [Mixpanel](https://mixpanel.com/)
- [Hubspot](https://www.hubspot.com/)
- [Segment](https://segment.com/)
- [Amplitude](https://amplitude.com/)

## "Ready to Party" Plugins / Libraries

We try and keep a list of all the plugins and libraries that we know of that work out-of-the-box in Partytown, but we would love your help as plugin & library authors and contributors to keep this list growing.

We have [some documentation](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#plugin-authors--developers) on how you could create and check-in an integration test that shows how your library / plugin works on Partytown. And if it works, then we would love to have the configuration needed (if any) on our [Common Services page](/common-services)

## Articles

- <a
    href="https://www.smashingmagazine.com/2022/04/partytown-eliminates-website-bloat-third-party-apps/"
    target="_blank"
    rel="noopener"
  >
    Smashing Magazine: How Partytown Eliminates Website Bloat From Third-Party
    Scripts
  </a>
- <a
    href="https://dev.to/adamdbradley/introducing-partytown-run-third-party-scripts-from-a-web-worker-2cnp"
    target="_blank"
    rel="noopener"
  >
    Introducing Partytown: Run Third-Party Scripts From a Web Worker
  </a>
- <a
    href="https://dev.to/adamdbradley/how-partytown-s-sync-communication-works-4244"
    target="_blank"
    rel="noopener"
  >
    How Partytown's Sync Communication Works
  </a>
- <a
    href="https://www.builder.io/blog/how-we-cut-99-percent-js-with-qwik-and-partytown"
    target="_blank"
    rel="noopener"
  >
    How we cut 99% of our JavaScript with Qwik + Partytown
  </a>
- <a
    href="https://www.builder.io/blog/partytown-is-now-in-beta"
    target="_blank"
    rel="noopener"
  >
    Partytown is now in Beta
  </a>
- <a
    href="https://www.patterns.dev/posts/third-party/"
    target="_blank"
    rel="noopener"
  >
    Patterns: Optimize loading third-parties
  </a>

---

### Src Routes Angular Index (`docs/src/routes/angular/index.mdx`)

---
title: Angular
---

# Angular

To setup Partytown in an Angular project take the following steps.

## Installation

Run the command below to install the dependencies

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

Add the path to the Partytown JS files into the assets array in your `angular.json` file

```json
"projects": {
    ...
    "{project-name}": {
        ...
        "architect": {
            ...
            "build": {
                ...
                "options": {
                    "assets": [...,
                      {
                        "glob": "**/*",
                        "input": "node_modules/@qwik.dev/partytown/lib",
                        "output": "/~partytown"
                      }
                    ]
                }
            }
        }
    }
}
```

## Script Setup

The snippet below shows you how to setup Partytown scripts in your `index.html` file. The first script tag takes the Partytown [configuration](/configuration). The second script tag references the Partytown JS file and the third file takes the third-party scripts to be loaded on the web-worker.

```html
<head>
  /* Partytown config properties */
  <script>
    partytown = {
      ...
    };
  </script>

  /* Inlined Partytown Snippet */
  <script src="/~partytown/debug/partytown.js"></script>

  <script type="text/partytown">
    /* Third-Party Script goes here */
  </script>
</head>
```

---

### Src Routes Astro Index (`docs/src/routes/astro/index.mdx`)

---
title: Astro
---

# Astro

There is a first-class [Astro integration for partytown](https://github.com/withastro/astro/tree/main/packages/integrations/partytown).

## Automatic Setup

Astro includes a CLI tool for adding integrations. Using the `astro add` command will automatically install Partytown and configure your project.

```bash
npx astro add partytown
yarn astro add partytown
pnpx astro add partytown
```

## Partytown Script

Add `type: 'text/partytown'` [attribute](/partytown-scripts) to any scripts you want to be handled by Partytown.

```html
<script type="text/partytown" src="https://example.com/analytics.js"></script>
```

Note that the [Astro Partytown](https://github.com/withastro/astro/tree/main/packages/integrations/partytown) integration already handles copying the library files to the correct location.

---

### Src Routes Atomics Index (`docs/src/routes/atomics/index.mdx`)

---
title: Atomics
---

# Atomics

Partytown will use [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics) and [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) when they're available by the browser. Some of the advantages include:

- 10x faster communication between threads compared to the service-worker requests
- 5% smaller build file compared to the service-worker build
- No `proxytown` requests in the network tab
- Fewer http requests to initialize the Partytown library
- Partytown service-worker and iframe is no longer used

It's important to note that [not all browsers support Atomics](#browser-atomics-support), and the server hosting the site must be configured with the correct response headers. If neither of those are true, then Partytown will fallback to using the service-worker communication layer instead.

## Document Response Headers

To enable Atomics communication, the browser's [crossOriginIsolated](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated) readonly property should be `true`. The `crossOriginIsolated` property is only set to true, by the browser, when the document includes these http response headers:

```
Cross-Origin-Embedder-Policy: credentialless
Cross-Origin-Opener-Policy: same-origin
```

- [Cross-Origin-Embedder-Policy (COEP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) response header prevents a document from loading any cross-origin resources that don't explicitly grant the document permission. At the time of writing, `credentialless` is not a supported value in Safari, so Safari will fallback to using the Service Worker communication. An alternative to `credentialless` is to use `require-corp`, which does work in Safari too. Please see [Setting Cross-Origin Attribute](#setting-cross-origin-attribute) for more info.
- [Cross-Origin-Opener-Policy (COOP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) response header allows you to ensure a top-level document does not share a browsing context group with cross-origin documents.

## Setting Cross-Origin Attribute

An alternative to setting `Cross-Origin-Embedder-Policy: credentialless`, is to instead use `Cross-Origin-Embedder-Policy: require-corp`. The biggest thing to highlight is that the `require-corp` does not allow images, scripts, videos, etc. to be loaded from another origin. For example, when this header is set, any scripts or images to a CDN will no longer work.

However, the [crossorigin](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) attribute can be used on individual elements, such as `<audio>`, `<img>`, `<link>`, `<script>`, and `<video>`, which allows these requests to go through and not be blocked.

Below is an example of setting the `crossorigin` attribute on an image:

```html
<img src="https://c.tenor.com/8wBCqZH60U8AAAAC/computer-cat.gif" crossorigin />
```

## Browser Atomics Support

[Can I Use: Atomics](https://caniuse.com/mdn-javascript_builtins_atomics)

- Desktop:
  - Chrome 68+ (Jul 2018)
  - Edge 79+ (Jan 2020)
  - Firefox 78+ (June 2020)
  - Safari 15.2+ (Dec 2021)
- Mobile:
  - Android, Chrome 97+
  - Android, Edge 97+
  - Android, Firefox 98+
  - iOS, Safari 15.2+ (Dec 2021)

## Test Atomics

You can test if a browser is capable of enabling Atomics by visiting these test pages which respond with the correct headers.

- [Test COEP "credentialless"](https://partytown.qwik.dev/tests/atomics/)
- [Test COEP "require-corp"](https://partytown.qwik.dev/tests/atomics/?coep=require-corp)

## Additional Resources

- [Making your website "cross-origin isolated" using COOP and COEP](https://web.dev/coop-coep/)
- [Cross-Origin-Embedder-Policy: credentialless](https://wicg.github.io/credentiallessness/)
- [COEP: credentialless. Isolation w/o Opt-In?](https://github.com/WICG/credentiallessness)
- [Understanding "same-site" and "same-origin"](https://web.dev/same-site-same-origin/)

---

### Src Routes Browser Support Index (`docs/src/routes/browser-support/index.mdx`)

---
title: Browser Support
---

# Browser Support

Partytown works to ensure that all browsers can still run third-party scripts, whether they have support for service workers, atomics, or neither. This means if you're supporting legacy browsers such as IE11, the scripts should continue to work as if Partytown wasn't being used.

At its core, Partytown uses Service Workers or Atomics to do its synchronous communication from the web worker to the main thread. However, when a browser does not support either of those, it'll fallback to run the scripts the traditional way (the way it works today without Partytown).

## How Feature Support Works

1. Browser checks to see if it has support for [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics) using the [crossOriginIsolated](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated) boolean found on `window`.
1. If the browser and site do not have support for Atomics, it'll then check to see if the browser has support for [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). Currently this is the most commonly used one.
1. If the browser does not have support for Service Workers or Atomics, it'll then find all the `type="text/partytown"` scripts and reset them to be traditional scripts and execute normally.

> Note: Atomics are still experimental, and also require specific server-side response headers for them to work. Please see the [Enabling Atomics](/atomics) section for more info.

## Web API Feature Support

- [Atomics](https://caniuse.com/mdn-javascript_builtins_atomics)
- [JavaScript Proxy](https://caniuse.com/proxy)
- [Service Workers](https://caniuse.com/serviceworkers)
- [Web Workers](https://caniuse.com/webworkers)

---

### Src Routes Common Services Index (`docs/src/routes/common-services/index.mdx`)

---
title: Common Services
---

# Common Services

Partytown is built with the goal that any third-party script can be ran from within it. At the lowest level, any script can add the `type="text/partytown"` attribute to have it executed from a web worker.

Below is a list of plugins / libraries that are tested & known to be working with Partytown with their commonly used [forward configs](/forwarding-events) and [proxied domains](/proxying-requests).

| Service                                                                                       | Forward Config                      | Proxy Domain                                        | Additional Config                          |
| --------------------------------------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------- | ------------------------------------------ |
| [Facebook Pixel](/facebook-pixel)                                                             | "fbq"                               | "connect.facebook.net"                              |                                            |
| [FullStory](https://help.fullstory.com/hc/en-us/articles/360020623574)                        | "FS.identify", "FS.event"           |                                                     | `strictProxyHas: true` (if loaded via GTM) |
| [Google Tag Manager](/google-tag-manager)                                                     | "dataLayer.push"                    |                                                     |                                            |
| [Hubspot Tracking](https://developers.hubspot.com/docs/api/events/tracking-code)              | "\_hsq.push"                        |                                                     |                                            |
| [Intercom](https://developers.intercom.com/installing-intercom/docs/intercom-javascript)      | "Intercom"                          |                                                     |                                            |
| [Klaviyo](https://developers.klaviyo.com/en/docs/javascript-api)                              | "\_learnq.push"                     | "static.klaviyo.com", "static-tracking.klaviyo.com" |                                            |
| [TikTok Pixel](https://ads.tiktok.com/marketing_api/docs?rid=959icq5stjr&id=1701890973258754) | "ttq.track", "ttq.page", "ttq.load" |                                                     |                                            |
| [Mixpanel](https://developer.mixpanel.com/docs/javascript-quickstart)                         | "mixpanel.track"                    |                                                     |                                            |

If you would like to add to this list,

- Refer to the ["for Plugin Authors / Developers"](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#plugin-authors--developers) section to see how you can validate whether a library / plugin works with Partytown.
- Send us a PR so that we can have a scenario checked in that validates it.
- Please [edit this doc](https://github.com/BuilderIO/partytown/edit/main/docs/common-services.md) to add your plugin / library and its configuration so that others can start using it!

## FullStory with Google Tag Manager

When loading FullStory via Google Tag Manager (GTM), you need to enable the `strictProxyHas` configuration option. This is because FullStory checks for namespace conflicts using the `in` operator (e.g., `if (!("FS" in window))`), and by default, Partytown's window proxy always returns `true` for the `in` operator for backwards compatibility.

```html
<script>
  partytown = {
    forward: ['FS.identify', 'FS.event'],
    strictProxyHas: true,
  };
</script>
```

Without `strictProxyHas: true`, FullStory will detect a false "namespace conflict" and fail to initialize when loaded via GTM's Custom HTML tag. This configuration ensures the `in` operator accurately checks property existence on the window object.

---

### Src Routes Configuration Index (`docs/src/routes/configuration/index.mdx`)

---
title: Configuration
---

# Configuration

Partytown does not require a config for it to work, however a config can be set to change the defaults. At the lowest level, it's configured by setting the `window.partytown = {...}` object before the Partytown snippet script. However, higher-level integrations, such as the `<Partytown/>` component found in `@qwik.dev/partytown/react`, should provide utilities to make setting the config easier

| Config                    | Description                                                                                                                                                                                                                                                                 |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `debug`                   | When `true`, Partytown scripts are not inlined and not minified. See the [Debugging](/debugging) docs on how to enable more logging.                                                                                                                                        |
| `forward`                 | An array of strings representing function calls on the main thread to forward to the web worker. See [Forwarding Events and Triggers](/forwarding-events) for more info.                                                                                                    |
| `lib`                     | Path where the Partytown library can be found your server. Note that the path must both start and end with a `/` character, and the files must be hosted from the same origin as the webpage. Default is `/~partytown/`                                                     |
| `loadScriptsOnMainThread` | An array of strings or regular expressions (RegExp) used to filter out which script are executed via Partytown and the main thread. An example is as follows: `loadScriptsOnMainThread: ["https://test.com/analytics.js", "inline-script-id", /regex-matched-script\.js/]`. |
| `resolveUrl`              | Hook that is called to resolve URLs which can be used to modify URLs. The hook uses the API: `resolveUrl(url: URL, location: URL, method: string)`. See the [Proxying Requests](/proxying-requests) for more information.                                                   |
| `resolveSendBeaconRequestParameters` | Hook that is called before every `navigator.sendBeacon` request to override its fetch parameters, e.g. `keepalive`. The hook uses the API: `resolveSendBeaconRequestParameters(url: URL, location: URL)` and returns a `SendBeaconParameters` object, or `null`/`undefined` to keep the defaults. |
| `mainWindowAccessors`     | An array of global names the worker reads from the main thread window instead of its own, e.g. `mainWindowAccessors: ["mySettings"]`. Useful when a script running in the worker needs data or methods from an object created on the main thread. Note that [forwarded](/forwarding-events) globals stay local to the worker.  |
| `mainElementProperties`   | An array of property names worker scripts set on DOM elements for the main thread to read, e.g. `mainElementProperties: ["loadAds"]`. Setting one also sets it on the real element, a function as a main thread function that calls back into the worker. Useful when main thread code, such as an iframe's inline `onload`, calls a function a script stored on an element. |
| `nonce`                   | The nonce property may be set on script elements created by Partytown. This should be set only when dealing with content security policies and when the use of `unsafe-inline` is disabled (using `nonce-*` instead).                                                       |
| `strictProxyHas`          | When `true`, the `in` operator will accurately check if properties exist on the window object. Required for scripts that check for namespace conflicts, such as FullStory loaded via GTM. Default is `false` for backwards compatibility.                                   |
| `fallbackTimeout`         | A timeout in ms until Partytown initialization is considered as failed & fallbacks to the regular execution in main thread. Set to `0` to disable the fallback entirely. Default is 9999                                                                                    |

## Vanilla Config

What we mean by "vanilla config", is that the Partytown config can be set without any higher-level integration. Below is an example of setting the `debug` config. Notice that the config script tag is _before_ the Partytown snippet script. Additionally, the config or snippet scripts should _NOT_ contain the `type="text/partytown"` attribute (this small amount of JavaScript we need to run on the main thread to initialize everything).

```html
<html>
  <head>
    <title>Vanilla Config Example</title>
    <script>
      partytown = {
        debug: true,
      };
    </script>
    <script>
      /* Inlined Partytown Snippet */
    </script>
  </head>
  <body>
    ...
  </body>
</html>
```

Please see the [integration guides](/integrations) for more information.

---

### Src Routes Copy Library Files Index (`docs/src/routes/copy-library-files/index.mdx`)

---
title: Copy Library Files
---

# Copy Library Files

The [@qwik.dev/partytown](https://www.npmjs.com/package/@qwik.dev/partytown) NPM package provides the static `lib` files that need to be served from your site. Since Partytown is using a service worker, these files must be served from the same origin as your site, and cannot be hosted from a CDN. Each site is different, and how the Partytown `lib` files are hosted depends on individual setup.

The `/~partytown/` directory should serve the static files found within [@qwik.dev/partytown/lib](/distribution). The quickest way is to copy the `lib` directory into a public `/~partytown` directory within your static server. Another option would be to set up a copy task within the project's bundler, or create a build step.

You can also use the [lib config](/configuration) if your site must host these files from a directory other than the default `/~partytown/`. Please see the [integration guides](/integrations) for more info on copying library files.

## Copy Task Command

For convenience, the Partytown CLI provides a `copylib` task. The last argument should be the directory where the Partytown lib files should be copied to. In the example below, the lib files are copying to the directory `public/~partytown`, relative to the current working directory:

```bash
partytown copylib 'public/~partytown'
```

This command can be used before a build script. Below is an example of copying the Partytown lib files before a Nextjs build command, using npm scripts:

```json
{
  "scripts": {
    "build": "npm run partytown && next build",
    "partytown": "partytown copylib 'public/~partytown'"
  }
}
```

## Copy Task API

The same code that the `partytown copylib` CLI task uses, is also exposed as an API and can be imported by any NodeJS script. Below is an example of importing the `@qwik.dev/partytown/utils` API and copying the lib files to the given directory. Both examples of an ESM import or CommonJS require should work.

```js
import { copyLibFiles } from "@qwik.dev/partytown/utils"; // ESM
// const { copyLibFiles } = require('@qwik.dev/partytown/utils'); // CommonJS

async function myBuildTask() {
  await copyLibFiles("path/to/public/~partytown");
}
```

## Rollup

> Available as of Partytown 0.3.6

Import the `partytownRollup` plugin from `@qwik.dev/partytown/utils` into your `rollup.config.js` config file. Next, add `partytownRollup(opts)` to the `plugins` [option](https://rollupjs.org/guide/en/#using-plugins).

The Rollup plugin will copy Partytown `lib` directory to the given destination, which must be an absolute file path. The copying will happen at the time of the `writeBundle()` hook.

Below is an example of using a [Rollup config](https://rollupjs.org/guide/en/#using-plugins) to copy the Partytown `lib` to a `dist` build directory:

```js
// rollup.config.js
import path from "path";
import { partytownRollup } from "@qwik.dev/partytown/utils";

export default {
  plugins: [
    partytownRollup({
      dest: path.join(__dirname, "dist", "~partytown"),
    }),
  ],
};
```

## Vite

> Available as of Partytown 0.3.6

Import the `partytownVite` plugin from `@qwik.dev/partytown/utils` into your `vite.config.js` config file. Next, add `partytownVite(opts)` to the `plugins` [option](https://vitejs.dev/config/#plugins).

The Vite plugin will copy Partytown `lib` directory to the given destination, which must be an absolute file path. The copying will happen at the time of the `writeBundle()` hook. When in dev mode, the Partytown lib files will be served using the Vite Dev Server.

Below is an example of using a [Vite config](https://vitejs.dev/config/) to copy the Partytown `lib` to a `dist` build directory:

```js
// vite.config.js
import path from "path";
import { partytownVite } from "@qwik.dev/partytown/utils";

export default ({ command }) => ({
  plugins: [
    partytownVite({
      dest: path.join(__dirname, "dist", "~partytown"),
    }),
  ],
});
```

## Webpack

Below is an example of using [Webpack's copy plugin](https://webpack.js.org/plugins/copy-webpack-plugin/) to copy the source `lib` directory found in the [@qwik.dev/partytown](https://www.npmjs.com/package/@qwik.dev/partytown) package, to the `public/~partytown/` directory:

```js
// webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const partytown = require("@qwik.dev/partytown/utils");

module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        {
          from: partytown.libDirPath(),
          to: path.join(__dirname, "public", "~partytown"),
        },
      ],
    }),
  ],
};
```

## Laravel Mix

Below is an example of using [Mix's copy()](https://laravel-mix.com/docs/6.0/copying-files/) to copy the source `lib` directory found in the [@qwik.dev/partytown](https://www.npmjs.com/package/@qwik.dev/partytown) package, to the `public/~partytown/` directory:

```js
// webpack.mix.js
const mix = require("laravel-mix");
const partytown = require("@qwik.dev/partytown/utils");

mix.copy(partytown.libDirPath(), "public/~partytown");
```

---

### Src Routes Debugging Index (`docs/src/routes/debugging/index.mdx`)

---
title: Debugging
---

# Debugging

With `debug` mode and logging enabled, below is an example of the Partytown logs showing all calls, getters and setters:



The [debug config](/configuration) must be `true` in order to see more verbose logging messages. The config table below lists all of the possible log configurations.

If you are using Chrome DevTools to see these logs, make sure that the `Verbose` log level is selected in Console

| Log Config Property     | Description                         |
| ----------------------- | ----------------------------------- |
| `logCalls`              | Log method calls                    |
| `logGetters`            | Log getter calls                    |
| `logSetters`            | Log setter calls                    |
| `logForwardedEvents`    | Log forwarded event calls           |
| `logImageRequests`      | Log Image() src requests            |
| `logScriptExecution`    | Log script executions               |
| `logSendBeaconRequests` | Log navigator.sendBeacon() requests |
| `logStackTraces`        | Log stack traces                    |

Please see the [debug file docs](/distribution#libdebug) more information about the distribution.

---

### Src Routes Distribution Index (`docs/src/routes/distribution/index.mdx`)

---
title: Distribution
---

# Distribution

Partytown is distributed from [@qwik.dev/partytown](https://www.npmjs.com/package/@qwik.dev/partytown) using NPM. Within the distribution there are a few directories and submodules, each with their own purpose.

```bash
@qwik.dev/partytown/
├── integration/
├── lib/
├── react/
├── services/
└── utils/
```

## `@qwik.dev/partytown/lib`

The `lib` directory contains the static files that should be hosted from the same [origin](https://developer.mozilla.org/en-US/docs/Glossary/Origin) as the website. Hosting from the same origin is a requirement of the [service worker scope](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope). The `lib` static files are minified and meant for production use.

```bash
@qwik.dev/partytown/lib/
├── partytown-atomics.js
├── partytown-media.js
├── partytown-sw.js
└── partytown.js
```

The `partytown.js` file must be in the `<head>` before all other third-party scripts, and should _not_ have the `async` or `defer` attributes. Because the script must be executed immediately, and since it's such a small file, it's always preferred to inline the `partytown.js` script content, rather than it being an additional http request.

> Note: When the service worker is correctly installed, the service worker itself handles the request to the `partytown-sandbox-sw.html` file and provides the content. The network tab will show `partytown-sandbox-sw.html`, and the service worker provides the response, but the file itself is not in the distribution. If you receive a 404 for this file then it means the service worker is not installed correctly. Please try uninstalling any existing Partytown service workers and ensure the Partytown files are loading correctly.

### `lib/debug/`

The `lib/debug` directory has the same purpose as the `lib`, but instead will console log more information and the files themselves are not minified. Additionally, you'll notice there are more debug files than the production lib files, and that's because the production lib files inline many scripts. For example, the web worker script is inlined, rather than being a separate request.

The `lib/debug` files are not meant to be used in production. See the [Partytown Configuration](/configuration) docs on how to enable debug mode.

```bash
@qwik.dev/partytown/lib/debug/
├── partytown-atomics.js
├── partytown-media.js
├── partytown-sandbox-sw.js
├── partytown-sw.js
├── partytown-ww-atomics.js
├── partytown-ww-sw.js
└── partytown.js
```

## `@qwik.dev/partytown/integration`

The `integration` submodule provides functions that can be used for integrations.

| Export             | Description                                                                                                                             |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| partytownSnippet() | Function that returns the Partytown snippet as a string which can be used as the innerHTML of the inlined Partytown script in the head. |
| SCRIPT_TYPE        | The value for the script type attribute: `text/partytown`                                                                               |

```js
import { partytownSnippet } from "@qwik.dev/partytown/integration";

const snippetText = partytownSnippet();
```

## `@qwik.dev/partytown/react`

The `react` submodule is where you'll find the React specific components, which is just a wrapper around the `partytown.js` snippet code. Please see the [React](/react) docs for more information.

```js
import { Partytown } from "@qwik.dev/partytown/react";

export function Head() {
  return (
    <>
      <Partytown />
    </>
  );
}
```

## `@qwik.dev/partytown/services`

The `services` submodule provides some of the commonly used [forward events](/forwarding-events), such as Google Tag Manager or Facebook Pixel. Please see the [Common Services](/common-services) docs for more information.

## `@qwik.dev/partytown/utils`

The `utils` submodule provides some convenience utilities, such as the the [Copy Task CLI and API](/copy-library-files).

| Export                | Description                                      |
| --------------------- | ------------------------------------------------ |
| copyLibFiles(destDir) | Async copy the `lib` directory to the `destDir`. |
| libDirPath()          | Returns an absolute path to the `lib` directory. |
| partytownRollup()     | [Rollup plugin](/copy-library-files#rollup).     |
| partytownVite()       | [Vite plugin](/copy-library-files#vite).         |

---

### Src Routes Drupal Index (`docs/src/routes/drupal/index.mdx`)

---
title: Drupal
---

# Drupal

The [Drupal](https://drupal.org) integration relies on a contributed module called ["PartyTown"](https://drupal.org/project/partytown), which can either be installed manually, or by using composer.

## Install

### Using Composer

 1. Use composer to download the Drupal module

``` bash
composer require drupal/partytown
```

 2. Add the following code to your `composer.json` in the `repositories` section

``` json

partytown": {
    "type": "package",
    "package": {
        "name": "quikdev/partytown",
        "version": "1.0.0",
        "type": "drupal-library",
        "dist": {
            "url": "https://registry.npmjs.org/@qwik.dev/partytown/-/partytown-1.0.0.tgz",
            "type": "tar"
        },
        "license": "MIT"
    }
}

```

 3. Install the PartyTown JS library

``` bash
composer require quikdev/partytown
```

### Using The Composer Merge Plugin

 1. Use composer to download the Drupal module

``` bash
composer require drupal/partytown
```

 2. If not already installed, install Merge Plugin: 
 
``` bash
composer require wikimedia/composer-merge-plugin
```

 3. Merge the PartyTown library from the module's `composer.json`: 
 
 ``` bash
 composer config extra.merge-plugin.include --json '[ "web/modules/contrib/partytown/composer.libraries.json" ]'
 ```

### Manually

 > **Note**: this method does not install the PartyTown JS library for you and may be a little more difficult to manage. However, it is provided as a fallback because some Drupal web sites are not managed using composer but may still benefit from this module. You will need to refer to the [HTML](/html) integration instructions or that of your favorite JS framework in order to make use of these instructions. In this context, the Drupal module will simply act as a GUI for managing your integration settings. Furthermore, you will need to configure the "Lib Path" setting in the Drupal module to point at your installation location.

 1. Download and unzip the Drupal module from the [PartyTown release page](https://www.drupal.org/project/partytown/releases) 
 
 2. Install the `partytown` module in the Drupal `modules` directory (usually `<webroot>/modules` or `<webroot>/modules/contrib`)
 
 3. Visit the Admin > Extend page of your Drupal installation and enable the PartyTown module
 
 4. Install the PartyTown JS library in whatever method you deem appropriate
 
 5. Ensure that the "Lib Path" setting points to your PartyTown installation location

> **Note**: Because the Drupal module and PartyTown integration in this method are essentially de-coupled, you will need to ensure that the PartyTown JS library loads **after** the module-provided `partytown/config` library. This ensures that PartyTown can use the settings you set in the Drupal admin. You also may need to implement a Drupal hook that prevents the default `partytown/lib` library from being loaded by Drupal.
 
## Configure

All configuration for the PartyTown module takes place in the Drupal admin interface. You can manage most of the PartyTown API settings graphically at `/admin/config/development/partytown`.

## Managing Scripts With PartyTown

### Google Tag Manager

The PartyTown module for Drupal comes with a submodule called "PartyTown Google Tag" for PartyTown-ing Google Tag Manager. Once installed, you will probably want to configure the PartyTown module to forward `dataLayer.push`.

### Other scripts

Other scripts can be PartyTown-ed by setting the type to be `text\partytown`. Using a `*.libraries.yml` this can be achieved with something similar to:

``` yaml
foo:
  js:
    js/foo.js: { attributes: { type: "text/partytown"} }

```

---

### Src Routes Facebook Pixel Index (`docs/src/routes/facebook-pixel/index.mdx`)

---
title: Facebook Pixel
---

# Facebook Pixel

## Add the Pixel Script

- [Meta (Facebook) Pixel](https://www.facebook.com/business/learn/facebook-ads-pixel)
- [How to Set Up and Install a Meta Pixel](https://www.facebook.com/business/help/952192354843755?id=1205376682832142)

## Partytown Script

Set the script element's `type` attribute to `text/partytown`. For example:

```html
<script type="text/partytown">
  // insert pixel script here
</script>
```

## Proxy Requests

The `connect.facebook.net` response does not provide the correct CORS header, and a reverse proxy should be used. Below is an example of setting the `resolveUrl` config to proxy the `connect.facebook.net` requests. Please see [Proxying Requests](/proxying-requests) for more information.

## Proxying with Server Handlers

If you're using a server framework like Nuxt 3, you can handle proxying dynamically using API routes. Below is an example configuration that dynamically fetches resources based on the provided URL and returns the response with appropriate headers:

```js
export default defineEventHandler(async (event) => {
  const query = getQuery(event);
  const url = String(query?.url) || null;

  if (!url || !url.includes("connect.facebook.net")) {
    throw createError({
      status: 500,
      message: "Invalid URL",
    });
  }

  // Fetch the file content dynamically based on the URL
  const response = await $fetch(url).catch((error) => {
    throw createError({
      status: 500,
      message: `Failed to fetch resource: ${error.message}`,
    });
  });

  setResponseHeaders(event, {
    "Access-Control-Allow-Origin": "*", // Ensures proper CORS handling
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE",
    "Content-Type": "application/x-javascript; charset=utf-8",
    "Cache-Control":
      "public, max-age=5, s-maxage=5, stale-if-error=2678400, stale-while-revalidate=86400", // Add necessary caching headers
  });

  return response;
});
```

## Forward Events

Facebook Pixel uses the [fbq()](https://www.facebook.com/business/help/402791146561655?id=1205376682832142) function to send events. In order for Partytown to forward the calls to `window.fbq({..})`, the forward config should add `"fbq"`. Please see [forwarding events and triggers](/forwarding-events) for more information.

## Example Config

```js
// https://partytown.qwik.dev/configuration
{
  resolveUrl: function(url) {
    if (url.hostname === "connect.facebook.net") {
      var proxyUrl = new URL('https://my-reverse-proxy.com/');
      proxyUrl.searchParams.append('url', url.href);
      return proxyUrl;
    }
    return url;
  },
  forward: [
    "fbq"
  ]
}
```

Please see the [integration docs](/integrations) for framework specific configuration.

---

### Src Routes Faq Index (`docs/src/routes/faq/index.mdx`)

---
title: FAQs
---

# FAQs

## Can all scripts use Partytown?

Not necessarily. While Partytown covers many cases that allow it to work great in many cases, there are also scenarios where your script may hit an internal error and silently fail. We encourage you to thoroughly test when running any scripts first in a development environment, and then in production. Please also see the [Trade-Offs](/trade-offs) docs.

## How do I know when a script is not working with Partytown?

Test test test! There are endless scenarios in which a script could have been written, and the tricks they could be doing. While Partytown has worked to [test](/tests/) many of these scenarios, there's a good chance a certain example isn't being accounted for. We encourage you to thoroughly test when running any scripts first in a development environment, and then in production.

## What do I do if my script is not working with Partytown?

Please first search through the [Github issues](https://github.com/BuilderIO/partytown/issues) for a similar issue. If a similar issue exists, please add a comment with as much additional information as possible.

If a similar [issue](https://github.com/BuilderIO/partytown/issues) does not already exist, please [open an issue](https://github.com/BuilderIO/partytown/issues/new/choose) that includes:

- Minimal Reproduction Case: If maintainers and contributors are unable to reproduce the same error, then it makes it very difficult to debug and fix. Any issued opened without a minimal reproduction example will be closed.
- E2E Test: A good example of an End-to-end test is one where the test fails before the fix, and passes after the fix. But also, all the other tests pass too. Please see [Submitting Issues And Writing Tests](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#submitting-issues-and-writing-tests) for more details.

## Why do some scripts work, and others don't with Partytown?

Most of yesterday's and today's third-party scripts were built from the ground-up to work only on the main UI thread, rather than from a web worker which does not have access to the DOM or window. Partytown does its best to access the main thread from a web-worker, synchronously so the script continues to work as expected. However, because this architecture is different from what's the original designers expected, the script may have an internal error. For all these reasons we encourage you to first thoroughly test your scripts when using them with Partytown. Please also see the [Trade-Offs](/trade-offs) docs.

## Will you debug why my script is not working for me?

Unfortunately, the project contributors and maintainers don’t have the capacity to debug every single third-party script on external websites. As an Open-Source project, Partytown's goal is to help encourage the community to assist one another. Helping to improvement the project can come in many forms:

- [Opening issues](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#submitting-issues-and-writing-tests) with minimal reproduction cases
- Creating fixes with [Pull Requests](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#submitting-issues-and-writing-tests)
- Adding [End-to-end tests](/tests/)

Additionally, Github issues is a place to explain a problem in detail, along with a reproduction case for maintainers. However, Github issues is not the best place to ask how-to questions since project contributors and maintainers don’t have the capacity to debug external websites and the many third-party scripts. Any issues opened asking that are not following these guidelines will be closed.

## Is Partytown production ready?

Many sites are already successfully using Partytown in production. However, what's most important is testing your scripts first, as what works for one website using a certain third-party script, may not work for your site using a different script. If your scripts work in production that’s great, they shouldn't suddenly stop working (no different that a traditional third-party script).

However, if you're struggling with a certain scenario, please see the [Submitting Issues And Writing Tests](https://github.com/BuilderIO/partytown/blob/main/CONTRIBUTING.md#submitting-issues-and-writing-tests).

---

### Src Routes Forwarding Events Index (`docs/src/routes/forwarding-events/index.mdx`)

---
title: Forwarding Events And Triggers
---

# Forwarding Events And Triggers

Many third-party scripts add a global variable to `window` which user code calls in order to send data to the service. For example, Google Tag Manager uses a [Data Layer](https://developers.google.com/tag-manager/devguide) array, and by pushing data to the array, the data is then sent on to GTM Servers. Because we're moving third-party scripts to a web worker, the main thread needs to know which variables to patch on `window`, and when these services are called, the data is correctly forwarded to the web worker. This includes queuing any events that may have happened before Partytown has even finished initializing.

For example, Google Tag Manager adds the `dataLayer` array to `window`, and Facebook Pixel adds the `fbq` function. Below is some quick pseudo code of what they're doing:

```js
// Google Tag Manager
window.dataLayer = [];

// Facebook Events
window.fbq = function(){...};
```

Because GTM and Facebook Pixel objects are added immediately in the `<head>` by each service, then anywhere within the webpage, your code and their code, can safely call `dataLayer.push(...)` or `fbq(...)`.

However, since GTM and Facebook Pixel were actually loaded in the web worker, then we need to forward these calls. The `forward` config is used to set which `window` variables should be patched and forwarded on. The forward string value is of the function to call, and since GTM is pushing to an array, the function to call is `dataLayer.push`.

```js
<script>
  partytown = {
    forward: ['dataLayer.push', 'fbq']
  };
</script>
```

Notice the forward configs are just strings, not actual objects. We're using strings here so we can easily serialize what service variable was called, along with the function argument values. When the web worker receives the information, it then knows how to correctly apply the call and arguments that were fired from the main thread.

You can customize each forwarded variable with the following settings:

- ## preserveBehavior

  In addition to the `forward` config, we also provide a `preserveBehavior` property. This property allows you to customize each forwarded property, preserving the original behavior of the function.

  When `preserveBehavior` is set to `true`, the original function's behavior on the main thread is maintained, while also forwarding the calls to partytown. This is useful in cases where the function has side effects on the main thread that you want to keep.

  If `preserveBehavior` is not explicitly set, its default value is `false`. This means that, by default, calls will only be forwarded to partytown and won't execute on the main thread.

  Here's an example of how to use it:

  ```js
  <script>
    partytown = {
      forward: [
        ['dataLayer.push', { preserveBehavior: true }],
        ['fbq', { preserveBehavior: false }],
        'gtm.push'
      ]
    };
  </script>
  ```

  In this example, calls to `dataLayer.push` will execute as normal on the main thread and also be forwarded to partytown. Calls to `fbq` will only be forwarded to partytown, and won't execute on the main thread. For `gtm.push`, since preserveBehavior is not explicitly set, it will behave as if preserveBehavior was set to false, meaning it will only be forwarded to partytown.

## Integrations

Please see the [Integrations](/integrations) section for examples using the `forward` config.

## Common Services

Please see the [Common Services](/common-services) section for a list of known configs for various services.

---

### Src Routes Gatsby Index (`docs/src/routes/gatsby/index.mdx`)

---
title: Gatsby
---

# Gatsby

The Gatsby setup is largely the same as the [React integration guide](/react), except it goes further into how to use the [Gatsby](https://gatsbyjs.com/) framework's `setHeadComponents` function, which is used to inject scripts and other common tags for websites.

For additional information, please see [How to Add Google Analytics gtag to Gatsby Using Partytown](https://www.gatsbyjs.com/blog/how-to-add-google-analytics-gtag-to-gatsby-using-partytown/).

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

## Configure

The `<Partytown/>` component is imported from the `@qwik.dev/partytown/react` submodule. The [config properties](/configuration) are JSX props.

The following is an example of including the `<Partytown/>` component in `gatsby-ssr.js`. Notice the `<Partytown/>` component is in `setHeadComponents`, and the example analytics script has the `type="text/partytown"` attribute.

```jsx
import React from "react";
import { Partytown } from "@qwik.dev/partytown/react";

export const onRenderBody = ({ setHeadComponents, setPreBodyComponents }) => {
  setHeadComponents([
    <Partytown key="partytown" debug={true} forward={["dataLayer.push"]} />,
    <script
      key="analytics"
      src="https://example.com/analytics.js"
      type="text/partytown"
    />,
  ]);

  // For GTM, we will need to add this noscript tag to the body of the HTML
  setPreBodyComponents([
    <noscript
      key="gtm"
      dangerouslySetInnerHTML={{
        __html: `
                  <iframe src="https://www.googletagmanager.com/ns.html?id=xxx-xxxxxxx" height="0" width="0"
                      style="display:none;visibility:hidden"></iframe>
                `,
      }}
    />,
  ]);
};
```

## Partytown Script

Add the `type="text/partytown"` [prop](/partytown-scripts) for each script that should run from a web worker. The example below is using the React specific way of inlining a script with [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml).

```jsx
<script
  type="text/partytown"
  dangerouslySetInnerHTML={{
    __html: "/* Inlined Third-Party Script */",
  }}
/>
```

## Copy Library Files

Copy library files to `static/~partytown`. How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the correct directory. Below is an example of using Gatsby's `onPreBuild` extension point. This can be added to `gatsby-node.js`.

```jsx
const path = require("path");
const { copyLibFiles } = require("@qwik.dev/partytown/utils");

exports.onPreBuild = async () => {
  await copyLibFiles(path.join(__dirname, "static", "~partytown"));
};
```

It's worth noting `onPreBuild` is only called during the build process. If you need to use `copyLibFiles` while in development you can use [onPreBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPreBootstrap) which is called when running both `gatsby build` or `gatsby develop`.

---

### Src Routes Getting Started Index (`docs/src/routes/getting-started/index.mdx`)

---
title: Getting Started
---

# Getting Started

Partytown is fairly different from most web development libraries in mainly what’s required for its setup and configuration. At the lowest level, Partytown can work with just vanilla HTML, meaning it doesn’t need to be a part of a build process, doesn’t need a bundler, doesn’t require a specific framework, etc. Because it can integrate with any HTML page, it also makes it much easier to then create wrapper components or plugins for almost any ecosystem, such as Shopify, WordPress, Nextjs, Gatsby and much more.

What's different from most web development libraries is that Partytown does _not_ get bundled with your existing site's JavaScript. Instead it purposely wants to stay separate from your code so that it can run within a web worker, and allow your code to run on the main thread. If the two were bundled we've already lost the battle.

## Install NPM package

```
npm install @qwik.dev/partytown
```

## Next Steps

1. [Add Partytown type attribute to Third-Party Scripts](/partytown-scripts)
2. [Add Partytown snippet to the `<head>`](/integrations)
3. [Copy Partytown library files](/copy-library-files)

---

### Src Routes Google Tag Manager Index (`docs/src/routes/google-tag-manager/index.mdx`)

---
title: Google Tag Manager
---

# Google Tag Manager

## Add the Google Tag Manager Script

- [Install Google Tag Manager for web pages](https://developers.google.com/tag-platform/tag-manager/web)

## Partytown Script

Set the script element's `type` attribute to `text/partytown`. For example:

```html
<script
  type="text/partytown"
  src="https://www.googletagmanager.com/gtag/js?id=YOUR-ID-HERE"
></script>
<script type="text/partytown">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'YOUR-ID-HERE');
</script>
```

## Google Analytics 4 (GA4)

GA4 responses come with the correct CORS headers, so you will not have to [proxy](/proxying-requests) the requests to `www.google-analytics.com`. [Older versions of Google Analytics](https://support.google.com/analytics/answer/11583528?sjid=5512098847312629397-NA) required proxying, but have been sunset by Google and are no longer supported.

Note that the automatic `user_engagement` event GA4 sends when the user leaves the page is not reliable from a web worker. Please see [page exit events](/trade-offs#page-exit-events) for more information.

## Forward Events

Google Tag Manager uses the [dataLayer](https://developers.google.com/tag-platform/tag-manager/web/datalayer) array to send events. In order for Partytown to forward the calls to `window.dataLayer.push({..})`, the forward config should add `"dataLayer.push"`. Please see [forwarding events and triggers](/forwarding-events) for more information.

## Example Config

```json
{
  "forward": ["dataLayer.push"]
}
```

Please see the [integration docs](/integrations) for framework specific configuration.

---

### Src Routes How Does Partytown Work Index (`docs/src/routes/how-does-partytown-work/index.mdx`)

---
title: How Does Partytown Work
---

# How Does Partytown Work

- [How Partytown's Service Worker Sync Communication Works](https://dev.to/adamdbradley/how-partytown-s-sync-communication-works-4244)

Traditionally, communicating between the main thread and worker thread _must_ be [asynchronous](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Concepts). Meaning that for the two threads to communicate, they cannot use blocking calls.

Partytown is different. It allows code executed from the web worker to access DOM _synchronously_. The benefit from this is that third-party scripts can continue to work exactly how they're coded.

For example, the code below works as expected within a web worker:

```javascript
const rect = element.getBoundingClientRect();
console.log(rect.x, rect.y);
```

First thing you'll notice is that there's no async/await, promise or callback. Instead, the call to `getBoundingClientRect()` is blocking, and the returned `rect` value contains the expected `x` and `y` properties.

Partytown relies on [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API), [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), and a communication layer between them all.

There are currently two ways to communicate synchronously between the web worker and main thread, and that's sync xhr requests combined with Service Workers, and Atomics.

## Designating Web Worker Scripts

It's important to note that Partytown does not automatically move all scripts to the web worker, but prefers an opt-in approach. Meaning, it's best that the developer can pick and choose exactly which scripts should use Partytown, while all the others would go unchanged. Please see the [Partytown Scripts](/partytown-scripts) for more info.

Partytown is only enabled for specific scripts when they have the `type="text/partytown"` attribute. This `type` attribute does two things:

1. Prevent the main thread from executing the script.
2. Provides a selector for Partytown to query, such as `document.querySelectorAll('script[type="text/partytown"]')`

### Adding Partytown Attribute

Below is an example of adding the `type="text/partytown"` attribute to an existing `<script>`.

```diff
- <script>...</script>
+ <script type="text/partytown">...</script>
```

## Service Worker

1. Scripts are disabled from running on the main thread by using the `type="text/partytown"` attribute on the `<script/>` tag.
1. Service worker creates an `onfetch` handler to intercept specific requests.
1. Web worker is given the scripts to execute within the worker thread.
1. Web worker creates JavaScript Proxies to replicate and forward calls to the main thread APIs (such as DOM operations).
1. Any call to the JS proxy uses [_synchronous_ XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#example_http_synchronous_request) requests.
1. Service worker intercepts requests, then is able to asynchronously communicate with the main thread.
1. When the service worker receives the results from the main thread, it responds to the web worker's request.
1. From the point of view of code executing on the web worker, everything was synchronous, and each call to the document was blocking.

## Atomics

Please see the [Atomics communication layer docs](/atomics) on how to enable them. When Atomics are not enabled, the fallback is to use the Service Worker instead. In the end, Atomics are preferred because they're roughly 10x faster in transferring data between the web worker and main thread.

1. Scripts are disabled from running on the main thread by using the `type="text/partytown"` attribute on the `<script/>` tag.
1. Main thread detects Atomics communication can be used, and loads the Atomics build instead of the Service Worker build.
1. Web worker is given the scripts to execute within the worker thread.
1. Web worker creates JavaScript Proxies to replicate and forward calls to the main thread APIs (such as DOM operations).
1. Any call to the JS proxy will use [Atomics.store()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/store) and `postMessage()` to send the data to the main thread, and run [Atomics.wait()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait).
1. [Atomics.load()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/load) is used once the web worker receives the results data from the main thread.
1. From the point of view of code executing on the web worker, everything was synchronous, and each call to the document was blocking.

## Serialization

Data passed between the main thread and web worker must be [serializable](https://en.wikipedia.org/wiki/Serialization). Partytown automatically handles the serializing and deserializing of data passed between threads. This works for primitive values, such as a `string`, `boolean` or `number`, and also functions, which get unique IDs assigned that are passed to the opposite thread and can be called.

---

### Src Routes Html Index (`docs/src/routes/html/index.mdx`)

---
title: HTML
---

# HTML

## Minimal Example

The smallest possible setup is a static page served next to the Partytown [library files](/copy-library-files), with no build tool at all:

```bash
mkdir -p demo/~partytown && cd demo/~partytown
curl -O -L https://unpkg.com/@qwik.dev/partytown@latest/lib/partytown.js
curl -O -L https://unpkg.com/@qwik.dev/partytown@latest/lib/partytown-sw.js
cd .. && python3 -m http.server 8080
```

```html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script src="/~partytown/partytown.js"></script>
  </head>
  <body>
    <script type="text/partytown">
      console.log('Hello from a web worker!');
    </script>
  </body>
</html>
```

Open `http://localhost:8080/` and the message is logged from the web worker. The one requirement is that the `/~partytown/` directory is served from your own origin.

At the lowest level, Partytown is not tied to one specific framework or build tool. Because of this, Partytown can be used in any webpage as long as the HTML is updated, and the [library scripts](/copy-library-files) are hosted from the origin.

While the `partytown.js` file _could_ be an external request, it's recommended to inline the script instead. How the Partytown snippet is inlined into the page depends on each site's setup and an [integration](/integrations) may already exist for your framework.

```html
<head>
  <script>
    /* Inlined Partytown Snippet */
  </script>
  <script type="text/partytown" src="https://example.com/analytics.js"></script>
</head>
```

One option to load the snippet is from the `partytownSnippet()` function, exported from the [@qwik.dev/partytown/integration](/distribution#builderiopartytownintegration) submodule.

```js
import { partytownSnippet } from "@qwik.dev/partytown/integration";

const snippetText = partytownSnippet();
```

## Configure

The [configuration](/configuration) should be added to `window` using the `partytown` global object.

Below is an HTML example of setting up the [forwarding](/forwarding-events) for [Google Tag Manager](/google-tag-manager). Note that the config is before the inlined partytown script.

```html
<head>
  <script>
    partytown = {
      forward: ["dataLayer.push"],
    };
  </script>
  <script>
    /* Inlined Partytown Snippet */
  </script>
</head>
```

## Partytown Script

Add the `type="text/partytown"` [attribute](/partytown-scripts) for each script that should run from a web worker.

```html
<script type="text/partytown">
  /* Inlined Third-Party Script */
</script>
```

## Copy Library Files

How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the public directory.

---

### Src Routes Integrations Index (`docs/src/routes/integrations/index.mdx`)

---
title: Integration Guides
---

# Integration Guides

Partytown can work with any HTML page, and doesn't require a specific framework. However, to make it easier to use in various frameworks or services, plugins/wrappers can be made for their ecosystem. Below is a current list of integrations. Please help us add more!

- [Angular](/angular)
- [Astro](/astro)
- [Drupal](/drupal)
- [Gatsby](/gatsby)
- [HTML](/html)
- [NextJS](/nextjs)
- [Nuxt](/nuxt)
- [Qwik](https://qwik.builder.io/docs/integrations/partytown/)
- [React](/react)
- [Remix](/remix)
- [Shopify Hydrogen](/shopify-hydrogen)
- [Solid](/solid)
- [SvelteKit](/sveltekit)
- [TanStack Start](/tanstack-start)
- [WordPress](/wordpress)

See something missing and would like to contribute? Please [open an issue](https://github.com/BuilderIO/partytown/issues/new/choose) and we'd love to work with you to get your integration up and running and listed here. It may be as simple as just writing a doc, similar to the ones above, detailing how to best implement Partytown in the framework or service.

---

### Src Routes Magento2 Index (`docs/src/routes/magento2/index.mdx`)

---
title: Magento 2
---

# Magento 2

To integrate the partytown library functionality into your Magento 2 project, you can use the integration module for Magento2 :

<a href="https://github.com/rostilos/perspective-partytown">
  Module for integrating BuilderIO/partytown library functionality into Magento
  2 project
</a>

## Requirements

<ul>
  <li>PHP 8.1 or higher</li>
  <li>Magento 2.4.4 or higher</li>
  <li>Node.js v16 or higher</li>
  <li>
    configured https for the domain ( for correct work of service wokers )
  </li>
  <li>
    Optional : configured reverse proxy for correct loading of some scripts (
    see below )
  </li>
</ul>

## Install

```bash
composer config repositories.perspective-magento2-partytown git git@github.com:rostilos/perspective-partytown.git
composer require perspective/magento2-partytown dev-master
php bin/magento setup:upgrade
bin/magento setup:di:compile
php bin/magento setup:static-content:deploy
```

Next, clear all the cache

## Updating partytown lib npm packages

The library files provided by the npm package @qwik.dev/partytown are already added to the module files, but in case you want to update them, it is recommended to do the following :

```bash
cd <magento-root>/vendor/perspective/magento2-partytown
npm install ( node v16+ required )
npm run partytown
```

## Configure

In order for scripts to be loaded and executed in a separate thread of the webworker - you need to set the appropriate type ( text/partytown ) when connecting them. Using the example of GMT :

```html

<script type="text/partytown">
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
  'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
  })(window,document,'script','dataLayer','GTM-XXXXXXXX');
</script>

```

Configuration of the module is managed through the admin panel, where you can select the list of available analytics services that will be allocated for execution in the webworker, as well as specify other configurations that affect the functionality of the library

You can find the configurations at the following path :

Stores -> Configuration -> Perspective -> Partytown

## Optional: reverse-proxying scripts

Given the peculiarities of the partytown library, you may encounter CORS errors when using certain scripts whose resources do not give the required headers. To avoid this, use reverse-proxying, the peculiarities and possible implementations are described here:

<a href="https://partytown.qwik.dev/proxying-requests">Proxying Requests</a>

You can also try using a self-hosted reverse-proxy solution
( see example here <a href="https://github.com/rostilos/perspective-partytown/blob/2.0.0-alpha/docs/reverse-proxy.md">Node.js reverse-proxy example for partytown library</a> and here <a href="https://github.com/rostilos/perspective-partytown/blob/2.0.0-alpha/docs/reverse-proxy.md">Nginx reverse-proxy example for partytown library ( for warden ) </a> ).

## Troubleshooting

If you encounter errors when using the integration module for Magento 2 - you can also create an issue in the <a href="https://github.com/rostilos/perspective-partytown">source repository</a>

---

### Src Routes Nextjs Index (`docs/src/routes/nextjs/index.mdx`)

---
title: Next.js
---

# Next.js

The Next.js setup is largely the same as the [React integration guide](/react), except it goes further into how to add to the [NextJS](https://nextjs.org/) framework's `<Head/>` component.

## Worker Strategy

The Next.js `<Script/>` component provides an experimental `worker` strategy, which uses Partytown under-the-hood. Please see the Next.js [Script documentation](https://nextjs.org/docs/api-reference/next/script#worker) for more information.

> Note: The `worker` strategy is currently unsupported with the Next.js 13+ `app` directory.

---

> Below are the instructions if you are not using the experimental [Worker Strategy](#worker-strategy).

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

## Configure

The `<Partytown/>` component is imported from the `@qwik.dev/partytown/react` submodule. The [config properties](/configuration) are JSX props.

The following is an example of including the `<Partytown/>` component in a Nextjs page. Notice the `<Partytown/>` component is in the `<Head>`, and the example analytics script has the `type="text/partytown"` attribute.

```jsx
import Head from "next/head";
import { Partytown } from "@qwik.dev/partytown/react";

const Home = () => {
  return (
    <>
      <Head>
        <title>My App</title>
        <Partytown debug={true} forward={["dataLayer.push"]} />
        <script src="https://example.com/analytics.js" type="text/partytown" />
      </Head>
      <main>...</main>
    </>
  );
};

export default Home;
```

## Partytown Script

Add the `type="text/partytown"` [prop](/partytown-scripts) for each script that should run from a web worker. The example below is using the React specific way of inlining a script with [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml).

```jsx
<script
  type="text/partytown"
  dangerouslySetInnerHTML={{
    __html: "/* Inlined Third-Party Script */",
  }}
/>
```

## Copy Library Files

> Below are the instructions if you are not using the experimental [Worker Strategy](#worker-strategy).

Copy library files to `public/~partytown`. How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the public directory. Below is an example of creating a "partytown" NPM script which could run before the build:

```json
"scripts": {
  "build": "npm run partytown && next build",
  "partytown": "partytown copylib public/~partytown"
}
```

---

### Src Routes Nuxt Index (`docs/src/routes/nuxt/index.mdx`)

---
title: Nuxt
---

# Nuxt

There is a first-class [Nuxt integration for partytown](https://github.com/nuxt-community/partytown-module).

## Install

Add `@nuxtjs/partytown` dependency to your project.

```bash
npm install --save-dev @nuxtjs/partytown
yarn add --dev @nuxtjs/partytown
pnpm install --save-dev @nuxtjs/partytown
```

## Configure

Add `@nuxtjs/partytown` to the `modules` section of `nuxt.config.ts`. Use the `partytown` property for the [configuration](/configuration).

```js
import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: ["@nuxtjs/partytown"],
  partytown: {
    /* any partytown-specific configuration */
  },
});
```

## Partytown Script

Add `type: 'text/partytown'` [attribute](/partytown-scripts) to any scripts you want to be handled by partytown.

```html
<template>
  <div>
    <script type="text/partytown" src="https://example.com/analytics.js" />
  </div>
</template>
```

Note that the [Nuxt Partytown](https://github.com/nuxt-community/partytown-module) module already handles copying the library files to the correct location.

---

### Src Routes Partytown Scripts Index (`docs/src/routes/partytown-scripts/index.mdx`)

---
title: Partytown Scripts
---

# Partytown Scripts

## Partytown Script Type

Add the `type="text/partytown"` attribute to each individual third-party script to run from a web worker. Note that each script is opt-in, meaning that the updated `type` attribute should only be added to scripts that should run with Partytown. Partytown will _not_ automatically upgrade any scripts unless this attribute is added.

```diff
- <script>...</script>
+ <script type="text/partytown">...</script>
```

## Why `type="text/partytown"`?

The `type="text/partytown"` attribute does two things:

1. Informs the browser to _not_ process the script. By giving the script a [type attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type) which the browser does not recognize: "The embedded content is treated as a data block which won't be processed by the browser."
2. Provides a query selector so Partytown can find all the scripts to run from within the web worker. When the document is ready and Partytown has initialized, Partytown will then query selector for all of the `script[type="text/partytown"]` script elements. You'll notice that after a script has been executed in the web worker, it'll then get an updated type attribute of `type="text/partytown-x"`.

## Dynamically Appending Scripts

Commonly, scripts will already be a part of the DOM when the document loads, and once the document is ready and the window has loaded, Partytown will find the scripts and start executing them in the web worker. However, if a script is dynamically appended to the DOM, _after_ Partytown has initialized, you can still dispatch the `ptupdate` custom event on window to notify Partytown there are new scripts to find.

Below is an example of dynamically appending a script to the document, then notifying Partytown to run its update again. Notice that _before_ the script is appended, the `type` property (or attribute) is already set to `text/partytown`.

```js
const script = document.createElement("script");
script.type = "text/partytown";
script.innerHTML = `console.log("New partytown script!")`;
document.head.appendChild(script);

window.dispatchEvent(new CustomEvent("ptupdate"));
```

## Integrations

Please see the [integration guides](/integrations) for more information on how to setup Partytown.

---

### Src Routes Proxying Requests Index (`docs/src/routes/proxying-requests/index.mdx`)

---
title: Proxying Requests
---

# Proxying Requests

Often third-party scripts are added to the page by appending a script tag, such as:

```javascript
var script = document.createElement("script");
script.url = "http://some-third-party-script.com/tracking.js";
document.head.appendChild(script);
```

When the `<script>` element is appended to the `<head>` using this traditional approach, the script's HTTP response _does not_ require [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) headers.

However, because Partytown requests the scripts within a web worker using [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), then the script's response _requires_ the correct CORS headers.

Many third-party scripts already provide the correct CORS headers, but not all do. For services that do not add the correct headers, then a [reverse proxy](#reverse-Proxy) to another domain must be used in order to provide the CORS headers.

## CORS Response Header

```
Access-Control-Allow-Origin: *
```

## Configuring URL Proxies

When executed from within Partytown, every URL is resolved by Partytown, which also gives users the ability to inspect and modify any and every URL being resolved. The `resolveUrl()` config can be used to check for a specific URL, and optionally return the proxied URL instead. For example, in the code below we're checking if the URL to be resolved is for Google Analytics, and if so, return a different URL that points to a [reverse proxy](#reverse-Proxy).

### Vanilla Config Example

```javascript
partytown = {
  resolveUrl: function (url, location, type) {
    if (type === "script") {
      var proxyUrl = new URL("https://my-reverse-proxy.com/");
      proxyUrl.searchParams.append("url", url.href);
      return proxyUrl;
    }
    return url;
  },
};
```

Please see the [integration guides](/integrations) and [configuration](/configuration) for more information.

## Reverse Proxy

Below are a few examples of [reverse proxies](https://en.wikipedia.org/wiki/Reverse_proxy) that could be used.

- [Apache](https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html)
- [AWS: Creating a Reverse Proxy for Partytown with AWS Cloudfront](https://nystudio107.com/blog/creating-a-reverse-proxy-for-partytown-with-aws-cloudfront)
- [Cloudflare](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/)
- [Gatsby Cloud: Redirects and Rewrites](https://support.gatsbyjs.com/hc/en-us/articles/1500003051241-Working-with-Redirects)
- [Netlify: Proxy to another service](https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service)
- [NGINX](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/)
- [Vercel: Rewrites](https://vercel.com/docs/cli#project-configuration/rewrites)

## Serving Resources Locally

Another option to work around the `Access-Control-Allow-Origin` issue _without_ using a proxy is to serve your third-party JavaScript and other resources locally.

So instead of inserting something like this on your page for [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs):

```html

<script type="text/partytown">
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('send', 'pageview');
</script>

```

You instead download the `analytics.js` JavaScript resource, and serve it locally from your domain like this:

```html

<script type="text/partytown">
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://example.com/analytics.js','ga');

  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('send', 'pageview');
</script>

```

Since you are serving the resource from your own server, you control the headers that come along with it, including the `Access-Control-Allow-Origin` header that the proxy work-around is sometimes needed for.

As a bonus, serving these resources locally is one less DNS lookup that needs to happen before the client can load your site.

You can manually download these self-hosted third-party JavaScript resources, or you can use a webpack plugin like [save-remote-file-webpack-plugin](https://www.npmjs.com/package/save-remote-file-webpack-plugin) to do it as part of your build process:

```js
const SaveRemoteFilePlugin = require("save-remote-file-webpack-plugin");
module.exports = {
  plugins: [
    new SaveRemoteFilePlugin([
      {
        url: "https://google-analytics.com/analytics.js",
        filepath: "js/analytics.js",
      },
    ]),
  ],
};
```

---

### Src Routes React Index (`docs/src/routes/react/index.mdx`)

---
title: React
---

# React

The Partytown NPM package already comes with a React component, which is a thin wrapper to the Partytown snippet. This React component should be usable from most React/Preact projects.

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

## Configure

The `<Partytown/>` component is imported from the `@qwik.dev/partytown/react` submodule. The [config properties](/configuration) are JSX props.

Below is an example of setting the `debug` config to `true`, and [forward](/forwarding-events) config for [Google Tag Manager](/google-tag-manager).

```jsx
import { Partytown } from "@qwik.dev/partytown/react";

export function Head() {
  return (
    <>
      <Partytown debug={true} forward={["dataLayer.push"]} />
    </>
  );
}
```

## Partytown Script

Add the `type="text/partytown"` [prop](/partytown-scripts) for each script that should run from a web worker. The example below is using the React specific way of inlining a script with [dangerouslySetInnerHTML](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html).

```jsx
<script
  type="text/partytown"
  dangerouslySetInnerHTML={{
    __html: "/* Inlined Third-Party Script */",
  }}
/>
```

## Copy Library Files

Copy library files to `public/~partytown`. How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the public directory. Below is an example of creating a "partytown" NPM script which could run before the build:

```json
"scripts": {
  "partytown": "partytown copylib public/~partytown"
}
```

---

### Src Routes Remix Index (`docs/src/routes/remix/index.mdx`)

---
title: Remix
---

# Remix

The Remix setup is largely the same as the [React integration guide](/react), except it goes further into how to add to the [Remix](https://remix.run/) framework's app root component.

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

## Configure

The `<Partytown/>` component is imported from the `@qwik.dev/partytown/react` submodule. The [config properties](/configuration) are JSX props.

The following is an example of including the `<Partytown/>` component in the app's root component. Notice the `<Partytown/>` component is in the `<head>` and before the `<Meta/>` component. The example below is setting the [forward](/forwarding-events) config for [Google Tag Manager](/google-tag-manager).

```jsx
import { Partytown } from "@qwik.dev/partytown/react";
import { Links, Meta, Outlet } from "@remix-run/react";

export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <Partytown debug={true} forward={["dataLayer.push"]} />
        <Meta />
        <Links />
      </head>
      <body>...</body>
    </html>
  );
}
```

## Partytown Script

Add the `type="text/partytown"` [prop](/partytown-scripts) for each script that should run from a web worker. The example below is using the React specific way of inlining a script with [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml).

```jsx
<Partytown debug={true} forward={['dataLayer.push']} />
<script
  type="text/partytown"
  dangerouslySetInnerHTML={{
    __html: '// inlined third-party script',
  }}
/>
```

## Copy Library Files

Copy library files to `public/~partytown`. How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the public directory. Below is an example of creating a "partytown" NPM script which could run before the build:

```json
"scripts": {
  "build": "npm run partytown && cross-env NODE_ENV=production remix build",
  "partytown": "partytown copylib public/~partytown"
}
```

---

### Src Routes Sandboxing Index (`docs/src/routes/sandboxing/index.mdx`)

---
title: Sandboxing
---

# Sandboxing

Third-party scripts are often a black-box with large amounts of code. What's buried within the obfuscated code is difficult to tell. It's minified for good reason, but regardless it becomes very difficult to understand what third-party scripts are executing on _your_ site and _your_ user's devices.

Partytown on the other hand, is able to isolate and sandbox third-party scripts within a web worker, and allow, or deny, access to main thread APIs. This includes cookies, localStorage, or the entire document. Because the code is executed within the worker, and their access to the main thread _must_ go through the proxy, Partytown is able to give developers control over what the scripts can execute.

Essentially, Partytown lets you:

- Isolate third-party scripts within a sandbox ([web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)).
- Configure which browser APIs specific scripts can, and cannot, execute.
- Option to log API calls and passed in arguments in order to give better insight as to what the scripts are doing.

---

### Src Routes Shopify Hydrogen Index (`docs/src/routes/shopify-hydrogen/index.mdx`)

---
title: Shopify Hydrogen
---

# Shopify Hydrogen

The [Shopify Hydrogen](https://hydrogen.shopify.dev/) setup is largely the same as the [React integration guide](/react), except it goes further into how to add to the framework's app root component.

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

## Configure

The `<Partytown/>` component is imported from the `@qwik.dev/partytown/react` submodule. The [config properties](/configuration) are JSX props.

The following is an example of including the `<Partytown/>` component in a root [Shopify component](https://shopify.dev/). Notice the `<Partytown/>` component before the `<DefaultSeo/>` component.

```jsx
import { DefaultRoutes } from "@shopify/hydrogen";
import { Suspense } from "react";

import DefaultSeo from "./components/DefaultSeo.server";
import NotFound from "./components/NotFound.server";
import AppClient from "./App.client";
import LoadingFallback from "./components/LoadingFallback";
import { Partytown } from "@qwik.dev/partytown/react";

export default function App({ log, pages, ...serverState }) {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <AppClient helmetContext={serverState.helmetContext}>
        <Partytown debug={true} forward={["dataLayer.push"]} />
        <DefaultSeo />
        <DefaultRoutes
          pages={pages}
          serverState={serverState}
          log={log}
          fallback={<NotFound />}
        />
      </AppClient>
    </Suspense>
  );
}
```

The example above is setting the [forward](/forwarding-events) config for [Google Tag Manager](/google-tag-manager).

## Partytown Script

Add the `type="text/partytown"` [prop](/partytown-scripts) for each script that should run from a web worker. The example below is using the React specific way of inlining a script with [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml).

```jsx
<Partytown debug={true} forward={['dataLayer.push']} />
<script
  type="text/partytown"
  dangerouslySetInnerHTML={{
    __html: '// inlined third-party script',
  }}
/>
```

## Copy Library Files

Copy library files to `public/~partytown`. How the files are copied or served from your site is up to each site's setup. A `partytown copylib` CLI [copy task](/copy-library-files) has been provided for convenience which helps copy the Partytown library files to the public directory. Below is an example of creating a "partytown" NPM script which could run before the build:

```json
  "scripts": {
    "dev": "npm run partytown && vite",
    "build": "npm run partytown && yarn build:client && yarn build:server && yarn build:worker",
    "build:client": "vite build --outDir dist/client --manifest",
    "build:server": "vite build --outDir dist/server --ssr src/entry-server.jsx",
    "build:worker": "cross-env WORKER=true vite build --outDir dist/worker --ssr worker.js",
    "partytown": "partytown copylib public/~partytown"
  }
```

---

### Src Routes Shopify Os2 Index (`docs/src/routes/shopify-os2/index.mdx`)

---
title: Shopify OS 2.0
---

# Shopify OS 2.0

Shopify OS 2.0 frontends are built with the Liquid templating language. Since it compiles to HTML, the [HTML integration guide](./html) is a good starting point. There are however a few platform based challenges and limitations you have to work around.

## Theme Files & Partydawn

The integration of Partytown largely depends on the theme you're using and the structure of its files. It's impossible to cover all different cases and you'll need to figure stuff out based on the examples given on this page. This should be viewed more as a template and not a full guide.

Shown code and steps are based on [Partydawn](https://github.com/j0Shi82/shopify-partydawn), an example of Shopify's Dawn theme that integrates Partytown.

## Requirements

- You need to be able to [set up an app proxy](https://github.com/edlaver/cloudflare-worker-partytown-shopify-app-proxy/tree/main) that can serve partytown assets
- Learn the basics of [Shopify Web Pixels](https://shopify.dev/docs/apps/marketing/pixels)

### Can't Hurt

- [Shopify's Customer Privacy API](https://shopify.dev/docs/api/consent-tracking)
- Experience with cookie consent management
- Make yourself comfortable with your theme's structure and file system

## Install

In the root file of your theme, add the Partytown snippet and config object. This most likely is the file that contains the `{{ contents_for_header }}` variable.

```html
<script>
  window.partytown = {
    forward: ['dataLayer.push' /**, ... */],
    // you cannot host partytown within Shopify OS 2.0
    // so you need to proxy assets
    resolveUrl: function (url, location, type) {
      if (type === 'script' /** extend as needed */) {
        const proxyUrl = new URL('/apps/partytown/proxy', location.href);
        proxyUrl.searchParams.append('url', url.href);
        return proxyUrl;
      }
      return url;
    };
  };
</script>
<script>
  /* Inlined Partytown Snippet */
</script>
```

It's important to understand that you cannot host Partytown assets on Shopify OS 2.0. So your app [proxy](./proxying-requests) needs to serve them.

Then add the `type="text/partytown"` attribute for each script that should run from the web worker as usual.

## Hooking Into the Web Pixel

Tracking events in Shopify isn't as straight forward as with other integrations. The checkout is fully controlled by Shopify, meaning you cannot fire some important events manually (`purchase`). Additionally some customization to your theme has to be done to find the right places to track `cart` events etc. The easiest way to deal with tracking in Shopify is through Web Pixels, which offer an API to hook into Shopify's own event stream.

You however cannot get Partytown to work inside Web Pixels because it's a sandboxed environment in an iframe without access to the top frame. To install the Tag Manager inside a Pixel you can follow [the official documentation](https://help.shopify.com/en/manual/promoting-marketing/pixels/custom-pixels/gtm-tutorial). The approach should be similar with other vendors.

The only exception is that you don't want to load the tracking scripts directly in the sandbox. Instead we inject the script as `text/partytown` in the regular page and create an event bridge between the Pixel and the main page using the `sessionStorage` that is available in the Pixel. We push events to the storage, pick them up on the main page, and forward them to Partytown.

```js
// inside the Pixel
browser.sessionStorage.setItem(`pt_dl_` + inc++, JSON.stringify(data));

// on the main page
function isSessionStorageAvailable() {
  var test = "test";
  try {
    sessionStorage.setItem(test, test);
    sessionStorage.removeItem(test);
    return true;
  } catch (e) {
    return false;
  }
}

if (isSessionStorageAvailable()) {
  var inc = 0;
  window.setInterval(function () {
    while (sessionStorage.getItem("pt_dl_" + inc) !== null) {
      window.dataLayer.push(JSON.parse(sessionStorage.getItem("pt_dl_" + inc)));
      sessionStorage.removeItem("pt_dl_" + inc);
      inc++;
    }
    // adjust the interval as you see fit
  }, 1000);
}
```

In case sessionStorage is not available, the Pixel should install the tracking scripts conventionally. This also has to be done on checkout pages which don't work with Partytown. You have all the tools inside Pixels to perform these checks and operations.

You can certainly also use `window.postMessage` to build an event bridge between the Web Pixel (iframe) and the top frame. But `sessionStorage` is directly supported by the Web Pixel API.

## Tracking Outside the Web Pixels

You can still implement manual tracking outside Web Pixels. In that case you need to add additional tracking inside `Settings-> Checkout -> Order Status Page Additional Scripts` to track purchases and conversions. Please note that this is deprecated. The current deadline is August 28, 2025. Although Shopify has pushed it back multiple times, you will eventually have to switch to Web Pixels or [Checkout Extensions](https://shopify.dev/docs/api/checkout-extensions).

## Use the Mutation Observer to Move Scripts into the Worker

Unfortunately you don't have full control over all scripts that are injected into the site. Some stuff will get added by Shopify automatically. We can thankfully still manipulate inline scripts using a [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). Changing the type to text/partytown will prevent script execution and the script will instead be processed by Partytown.

This way you can offload Shopify's own `trekkie` tracking and run the standard integrations for [Google Analytics](https://help.shopify.com/en/manual/reports-and-analytics/google-analytics/google-analytics-setup) and [Facebook](https://help.shopify.com/en/manual/promoting-marketing/analyze-marketing/meta-pixel) through Partytown.

---

### Src Routes Solid Index (`docs/src/routes/solid/index.mdx`)

---
title: Solid
---

# Solid

To setup Partytown in an Solid project take the following steps.

## Install

```bash
npm install @qwik.dev/partytown
yarn add @qwik.dev/partytown
pnpm install @qwik.dev/partytown
```

Use your favorite package manager to install `@qwik.dev/partytown` dependency and
copy the Partytown files to the local filesystem using the Vite plugin.
Adopting [this strategy](https://partytown.qwik.dev/copy-library-files#vite) from the Partytown + Vite docs:

```js
// vite.config.js
...
import { join } from 'path';
import { partytownVite } from '@qwik.dev/partytown/utils';

export default defineConfig({
  plugins: [
    ...
    partytownVite({
      dest: join(__dirname, 'dist', '~partytown'),
    }),
  ],
  ...
});
```

## Script Setup

The snippet below shows you how to setup Partytown scripts in your `index.html` file. The first script tag takes the Partytown [configuration](/configuration). The second script tag references the Partytown JS file and the third file takes the third-party scripts to be loaded on the web-worker.

```html
<head>
  
  <script>
    partytown = {
      ...
    };
  </script>

  
  <script src="/~partytown/debug/partytown.js"></script>
  <script type="text/partytown">
    console.log("New Partytown script.");
    console.log("Third-Party script goes here!");
  </script>
</head>
```

---

### Src Routes Sveltekit Index (`docs/src/routes/sveltekit/index.mdx`)

---
title: SvelteKit
---

# SvelteKit

SvelteKit uses Vite to build, so we can use `partytownVite`.

1. Copy the Partytown files to the local filesystem using the Vite plugin
2. Add the Partytown script to `src/routes/+layout.svelte`
3. Then add 3rd party scripts
4. Optional: reverse-proxying scripts

## 1. Copy the Partytown files to the local filesystem using the Vite plugin

Adopting [this strategy](https://partytown.qwik.dev/copy-library-files#vite) from the Partytown + Vite docs:

```js
// vite.config.js
import { join } from "path";
import { sveltekit } from "@sveltejs/kit/vite";
import { partytownVite } from "@qwik.dev/partytown/utils";

/** @type {import('vite').UserConfig} */
const config = {
  plugins: [sveltekit(), partytownVite()],
};

export default config;
```

## 2. Add the Partytown script to `src/routes/+layout.svelte`

Adapting from [the HTML integration guide](https://partytown.qwik.dev/html)

```svelte
// src/routes/+layout.svelte

<script>
  import { partytownSnippet } from '@qwik.dev/partytown/integration'
</script>

<svelte:head>
  {@html '<script>' + partytownSnippet() + '</script>'}
</svelte:head>
```

## 3. Then add 3rd party scripts

This is where we use partytown to add those scripts (note `type="text/partytown"` below). This example shows Google Tag Manager. Putting it together with the previous changes, our `+layout.svelte` looks like:

```svelte
// src/routes/+layout.svelte

<script>
	import { partytownSnippet } from '@qwik.dev/partytown/integration'
</script>

<slot />

<svelte:head>
	<script>
		// Forward the necessary functions to the web worker layer
		partytown = {
			forward: ['dataLayer.push']
		};
	</script>

	{@html '<script>' + partytownSnippet() + '</script>'}

	<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=YOUR-ID-HERE"></script>
	<script type="text/partytown">
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'YOUR-ID-HERE');
	</script>
</svelte:head>
```

## 4. Optional: reverse-proxying scripts

This will only be necessary depending on which scripts you are using. The implementation will vary depending on hosting platform. See [Partytown's recommended guides](https://partytown.qwik.dev/proxying-requests#reverse-proxy).

Acknowledgements: credit belongs to monogram.io for [an earlier version of this guide](https://monogram.io/blog/add-partytown-to-svelte).

---

### Src Routes Tanstack Start Index (`docs/src/routes/tanstack-start/index.mdx`)

---
title: TanStack Start
---

# TanStack Start

[TanStack Start](https://tanstack.com/start) apps are Vite-based, so Partytown integrates with the [snippet](/html) plus the library files served from your origin.

## Copy Library Files

Copy the Partytown library files into the `public` directory so they're served from `/~partytown/`:

```bash
npx @qwik.dev/partytown copylib public/~partytown
```

Run it from a `package.json` script so the files stay up to date:

```json
{
  "scripts": {
    "dev": "partytown copylib public/~partytown && vite dev",
    "build": "partytown copylib public/~partytown && vite build"
  }
}
```

## Add The Snippet

In your root route, inline the snippet with the [config](/configuration) before it, and mark third-party scripts with `type="text/partytown"`:

```tsx
// src/routes/__root.tsx
import { partytownSnippet } from '@qwik.dev/partytown/integration';

export const Route = createRootRoute({
  head: () => ({
    scripts: [
      {
        children: 'partytown = { forward: ["dataLayer.push"] };',
      },
      {
        children: partytownSnippet(),
      },
      {
        type: 'text/partytown',
        src: 'https://example.com/analytics.js',
      },
    ],
  }),
  component: RootComponent,
});
```

Note that the config and snippet scripts must **not** have the `text/partytown` type — they're the small bit of JavaScript that runs on the main thread to initialize everything.

Services like Google Tag Manager also need [forwarding](/forwarding-events) configured, and services without CORS headers need [request proxying](/proxying-requests) — both work the same as any other Partytown setup.

---

### Src Routes Trade Offs Index (`docs/src/routes/trade-offs/index.mdx`)

---
title: Trade-Offs
---

# 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](/how-does-partytown-work#service-worker) 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](https://web.dev/performance-scoring/). Additionally, they can give you an insight into what certain third-party scripts are up to. See the [debugging documentation](/debugging) for more info.

To hide them while debugging, filter them out of the network tab with [`-url:proxytown`](https://developer.chrome.com/docs/devtools/network/reference#invert-filters) 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](#ui-intensive-third-party-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](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), such as `Access-Control-Allow-Origin: *`, not all do. Please see the [Proxying Requests](/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()](https://developer.mozilla.org/en-US/docs/Web/API/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](/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.

---

### Src Routes Wordpress Index (`docs/src/routes/wordpress/index.mdx`)

---
title: WordPress
---

# WordPress

Partytown can be added to any [WordPress](https://wordpress.org) site from a theme (or child theme), without a plugin. The setup is the same as any [HTML integration](/html): host the [library files](/copy-library-files) from your own origin, inline the snippet, and mark the third-party scripts with `type="text/partytown"`.

## Copy Library Files

Copy the Partytown library files into your site's webroot so they're served from `https://your-site.com/~partytown/`:

```bash
npx @qwik.dev/partytown copylib ~partytown
```

Upload the generated `~partytown` directory to the root of your WordPress installation (next to `wp-content`). Any location works as long as it's served from your own origin — if you place it elsewhere, set the [`lib`](/configuration) config to that path.

## Inline The Snippet

In your theme's `functions.php`, print the config and the snippet in the `<head>` before any other scripts:

```php
add_action('wp_head', function () {
  // keep this before the snippet
  echo '<script>partytown = { forward: ["dataLayer.push"] };</script>';
  // partytown.js contents copied to the theme, or printed inline
  echo '<script>' . file_get_contents(ABSPATH . '~partytown/partytown.js') . '</script>';
}, 1);
```

## Mark Scripts For Partytown

Scripts printed directly in your theme just need the `type` attribute:

```html
<script type="text/partytown" src="https://example.com/analytics.js"></script>
```

For scripts registered through `wp_enqueue_script()`, change their type with the `script_loader_tag` filter:

```php
add_filter('script_loader_tag', function ($tag, $handle) {
  $partytown_handles = ['google-analytics', 'my-tracking-script'];
  if (in_array($handle, $partytown_handles)) {
    return str_replace(" src", " type='text/partytown' src", $tag);
  }
  return $tag;
}, 10, 2);
```

## Plugins That Print Their Own Scripts

Analytics plugins that print their own `<script>` tags (e.g. GTM plugins) don't offer a way to change the script type. In that case either configure the plugin to output only a container ID and print the loader yourself with `type="text/partytown"`, or skip Partytown for that plugin.

Note that a `dataLayer.push` [forward](/forwarding-events) config is required for Google Tag Manager, and services without CORS headers need [request proxying](/proxying-requests) — both work the same as any other Partytown setup.

---

### Package.Json (`docs/package.json`)

{
  "name": "my-qwik-empty-starter",
  "description": "Blank project with routing included",
  "engines": {
    "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
  },
  "engines-annotation": "Mostly required by sharp which needs a Node-API v9 compatible runtime",
  "private": true,
  "trustedDependencies": [
    "sharp"
  ],
  "trustedDependencies-annotation": "Needed for bun to allow running install scripts",
  "type": "module",
  "scripts": {
    "build": "qwik build",
    "build.client": "vite build",
    "build.preview": "vite build --ssr src/entry.preview.tsx",
    "build.server": "vite build -c adapters/cloudflare-pages/vite.config.mts",
    "build.types": "tsc --incremental --noEmit",
    "deploy": "wrangler pages deploy ./dist",
    "dev": "vite --mode ssr",
    "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
    "fmt": "prettier --write .",
    "fmt.check": "prettier --check .",
    "lint": "eslint \"src/**/*.ts*\"",
    "preview": "qwik build preview && vite preview --open",
    "serve": "wrangler pages dev ./dist --compatibility-flags=nodejs_als",
    "start": "vite --open --mode ssr",
    "qwik": "qwik"
  },
  "devDependencies": {
    "@qwik.dev/core": "2.0.0-beta.27",
    "@qwik.dev/router": "2.0.0-beta.27",
    "@types/eslint": "8.56.10",
    "@types/node": "^20.19.0",
    "@typescript-eslint/eslint-plugin": "7.16.1",
    "@typescript-eslint/parser": "7.16.1",
    "autoprefixer": "^10.4.19",
    "clsx": "^2.1.1",
    "eslint": "8.57.0",
    "eslint-plugin-qwik": "2.0.0-beta.27",
    "postcss": "^8.4.39",
    "prettier": "3.6.2",
    "rollup": "^4.52.0",
    "prettier-plugin-tailwindcss": "^0.5.4",
    "rehype-pretty-code": "^0.14.0",
    "sass": "^1.83.0",
    "shiki": "^1.24.3",
    "tailwind-merge": "^2.5.5",
    "tailwindcss": "^3.4.6",
    "typescript": "5.4.5",
    "unist-util-visit": "^5.0.0",
    "vite": "^7.3.1",
    "vite-tsconfig-paths": "^4.2.1",
    "wrangler": "^3.0.0"
  }
}

---

### Tsconfig.Json (`docs/tsconfig.json`)

{
  "compilerOptions": {
    "allowJs": true,
    "target": "ES2017",
    "module": "ES2022",
    "lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"],
    "jsx": "react-jsx",
    "jsxImportSource": "@qwik.dev/core",
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "allowImportingTsExtensions": true,
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "incremental": true,
    "isolatedModules": true,
    "outDir": "tmp",
    "noEmit": true,
    "paths": {
      "~/*": ["./src/*"]
    }
  },
  "files": ["./.eslintrc.cjs"],
  "include": ["src", "./*.d.ts", "./*.config.ts"]
}

---

### .Vscode Launch.Json (`docs/.vscode/launch.json`)

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Chrome",
      "request": "launch",
      "type": "chrome",
      "url": "http://localhost:5173",
      "webRoot": "${workspaceFolder}"
    },
    {
      "type": "node",
      "name": "dev.debug",
      "request": "launch",
      "skipFiles": ["<node_internals>/**"],
      "cwd": "${workspaceFolder}",
      "program": "${workspaceFolder}/node_modules/vite/bin/vite.js",
      "args": ["--mode", "ssr", "--force"]
    }
  ]
}

---

### Public Manifest.Json (`docs/public/manifest.json`)

{
  "$schema": "https://json.schemastore.org/web-manifest-combined.json",
  "name": "qwik-project-name",
  "short_name": "Welcome to Qwik",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#fff",
  "description": "A Qwik project app."
}

---

### Src Routes Menu (`docs/src/routes/menu.md`)

# Docs Table Of Contents

## Introduction|/

- [How Does It Work?](/how-does-partytown-work)
- [FAQs](/faq)
- [Trade-Offs](/trade-offs)
- [Browser Support](/browser-support)

## Getting Started|/getting-started

- [Overview](/getting-started)
- [Partytown Scripts](/partytown-scripts)
- [Copy Library Files](/copy-library-files)
- [Atomics](/atomics)
- [Distribution](/distribution)

## Integrations|/integrations

- [Angular](/angular)
- [Astro](/astro)
- [Drupal](/drupal)
- [Gatsby](/gatsby)
- [HTML](/html)
- [Magento 2](/magento2)
- [Next.js](/nextjs)
- [Nuxt](/nuxt)
- [Qwik](https://qwik.dev/docs/integrations/partytown/)
- [React](/react)
- [Remix](/remix)
- [Shopify Hydrogen](/shopify-hydrogen)
- [Shopify OS 2.0](/shopify-os2)
- [Solid](/solid)
- [SvelteKit](/sveltekit)
- [TanStack Start](/tanstack-start)
- [WordPress](/wordpress)

## Configuration|/configuration

- [Overview](/configuration)
- [Proxying Requests](/proxying-requests)
- [Forwarding Events](/forwarding-events)
- [Sandboxing](/sandboxing)
- [Debugging](/debugging)

## Third-Party Services|/common-services

- [Common Services](/common-services)
- [Facebook Pixel](/facebook-pixel)
- [Google Tag Manager](/google-tag-manager)

## Community

- [Discord](https://discord.gg/aHKdpdWv7a)
- [@QwikDev](https://twitter.com/QwikDev)

---

--- METRICS ---
- Files Extracted: 44
- Estimated Token Budget: ~31326 tokens
- Canonical Reference: https://codewiki.google/github.com/QwikDev/partytown
