Example of Shopify's Dawn theme working with Partytown. Example site is up at https://partydawn.myshopify.com (password: partydawn).
Currently included in this repo are different ways of how to integrate Partytown:
- GTM (through Shopify's Web Pixel)
- Matomo (working without consent)
- Klaviyo (dynamically injected based on consent)
- Trekkie (altered Shopify's own tracking to work with Partytown)
- Official Google Analytics 4 Integration
- Official Facebook Integration
- Clone the repo
- Set up a Shopify development store with an app that manages cookie consent (the example uses Consentmo)
shopify theme dev --store=YOUR_STORE
- Set up a partytown proxy worker and app proxy
- Note: a skeleton app is fine for this because you really only need the proxy settings. Using the CLI is the easiest option
- Create a new Custom Web Pixel with the contents of
backend/pixel/gtm.js
- Add the contents of
backend/checkout/additional.liquid
toSettings-> Checkout -> Order Status Page Additional Scripts
- Connect Google Analytics using the official integration
- Connect Facebook using the official integration
- Go to the
Theme Customizer -> Theme Settings -> Partydawn
and fill out the settings as needed
When using Consentmo and want to test different settings with tracking, you can open your browser's developer console and invoke showPreferences()
. It works differently with other cookie consent apps. I only mention this because adding a button to reopen consent is a premium feature within Consentmo and I was lazy enough not to add a button myself.
snippets/header-partytown-analytics.liquid
snippets/global-partytown.liquid
backend/pixel/gtm.js
Shopify uses Web Pixels to hook into customer events. Although Web Pixels are JavaScript snippets, you can't get Partytown to work because it's a sandboxed environment in an iframe without access to the top frame. To install the Tag Manager inside the Pixel I basically followed the official documentation, with the exception that we don't want to load the GTM script 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 in the storage, pick them up on the main page, and forward them to Partytown:
// 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++;
}
}, 1000);
}
If sessionStorage is not available the Pixel installs the GTM conventionally. This is also done on checkout pages which can't be directly controlled.
Web Pixel play nicely with the integrated consent. They follow the rules defined on Sales Channels -> Online Store -> Preferences -> Customer Privacy
. Whenever it feels appropriate to hook into Shopify's customer events for tracking purposes, this is the way to go.
You can certainly also use window.postMessage
to build an event bridge between the Web Pixel (iframe) and the top frame. But I chose sessionStorage since it's directly supported by the Web Pixel API.
You can test a server implementation by altering the tag manager URL in the theme settings partydawn_gtm_server
. It's impossible to create first-party cookies from the server with a dev store setup though. You cannot solve cross-domain. I tried a app proxies and use https://partydawn.myshopify.com/a/sgtm
as the server url, but routing the request through Shopify's app logic eats all cookies alive. And because you cannot attach a domain to a dev shop you're out of options. So there's unfortunately no way to test whether cookies get correctly set with sgtm working inside partytown.
There's no cookie banner on the test site so be warned...
I've set up a small test site that uses a subdomain for the tagging server. While testing, I noticed that cookies from the tagging server that are served through HTTP Set-Cookie
headers are not set properly. I realized that for whatever reason even when setting withCredentials
, XMLHttpRequest
is unable to send or set cookies inside Web Workers. fetch
doesn't suffer from the same issue.
I've posted the issue here: QwikDev/partytown#501
Since it might be a platform issue, the only real way around this seems to be using a shim that implements the original XMLHttpRequest
API, but uses fetch under the hood. https://github.com/apple502j/xhr-shim/blob/main/src/index.js is a nice starting point, but you also at least need to add onprogress
and onreadystatechange
for most scripts to work. When using SGTM + PT + XHR_REWRITE on the test site, the underlying Cloudflare URL Proxy automatically applies a shim and the cookies are correctly set.
This is a bit of a pain and I'm hoping to be able to provide a fix within Partytown in the future. Again: This is only an issue if working with a tagging server or relying on anything else that sets cookies through the Set-Cookie
HTTP header. All document.cookie
from text/partytown
work just fine.
There's no cookie banner on the test site so be warned...
snippets/global-partytown.liquid
snippets/matomo-tracking.liquid
backend/checkout/additional.liquid
There might be tracking that you can run regardless of the consent. You can just add it as text/partytown
and Partytown will pick it up. Please note that you need to add additional tracking inside Settings-> Checkout -> Order Status Page Additional Scripts
. This enables you to track the checkout as well. Unfortunately we can't use Web Pixels here because they only run when the user consents. There is no way to add Pixels based on the user consent. This also means you unfortunately cannot track any checkout sub steps, just the conversion. But in most cases this should be fine.
snippets/global-partytown.liquid
snippets/klaviyo-tracking.liquid
There's also tracking that works outside Shopify's consumer events, but needs to respect user consent. Klaviyo is such an example. It's already known to work with Partytown and can be integrated easily. You just have to use the Customer Privacy API that Shopify offers.
(async function () {
function waitForCustomerPrivacy() {
return new Promise(function (resolve) {
var interval = setInterval(function () {
if (window.Shopify && window.Shopify.customerPrivacy) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
await waitForCustomerPrivacy();
if (window.Shopify.customerPrivacy.thirdPartyMarketingAllowed()) {
startKl();
} else {
document.addEventListener('visitorConsentCollected', function (event) {
if (event.detail.thirdPartyMarketingAllowed) {
startKl();
}
});
}
})();
Note that the functions expects another script to init the API as described here, but you can also do this yourself. Usually the consent integration / app takes care of it. For Klaviyo you need to follow the official integration guide, but don't use the App Embed.
Also remember to inform Partytown that Klaviyo has been added:
window.dispatchEvent(new CustomEvent('ptupdate'));
snippets/global-partytown.liquid
assets/trekkie-partytown.js
Trekkie is Shopify's own tracking engine and gets loaded as part of the content_for_header
blackbox. We can thankfully still manipulate inline scripts using a MutationObserver. Changing the type to text/partytown
will prevent script execution and the script will instead be processed by Partytown. You need to rewire a couple more inline scripts as shown in assets/trekkie-partytown.js
. Any script containing ShopifyAnalytics
needs to get added to the Partytown instance and remain on the main page. Otherwise the site starts to throw errors.
Using the standard integrations for Google Analytics and Facebook with "partytowned" Trekkie leads to the attached pixels also being loaded within a Web Worker. I haven't fully tested this method, so treat it with caution and confirm that the data is correctly being collected by the third partys vendors.
You can also block trekkie using the partydawn_trekkie_disabled
theme setting to test other Facebook and GA4 implementations (like GTM/SGTM).
With the setup you can easily switch between Partytown and conventional tracking and compare the speed benefits. I installed a lot of app clutter on the shop because admittedly Dawn is pretty fast with and without tracking in its original version. In a usual production environment you will inevitably add apps and fill the store with JavaScript that you often cannot directly control. That's when Partytown might be able to give you a bit relief, because you start to see the usual issues.
Tracking Type | Page | Performance | Link |
---|---|---|---|
Conventional | Index | 86 | Click |
Conventional | Collection | 77 | Click |
Conventional | Product | 77 | Click |
Partytown | Index | 97 | Click |
Partytown | Collection | 97 | Click |
Partytown | Product | 92 | Click |
- https://github.com/malipetek/shopify-partytown
- https://github.com/edlaver/cloudflare-worker-partytown-shopify-app-proxy/tree/main
- https://gist.github.com/montalvomiguelo/3a8da3b6db29091ecb4b04265a58bd3b
Please note that this is not the intended way of tracking in Shopify OS 2.0. Anything used here can break at any time if Shopify decides to change the way Trekkie or Web Pixels work. In a production environment you need to have a dev watching over your site or Partytown might cause more harm than good. Any theme should have a "kill switch" to return to conventional tracking in case something breaks.
Other than that: Have fun offloading your tracking scripts!