Using Shopify Customer Events for Analytics

June 2024 Update – You can now use GTM within the Customer Events Sandbox. You can even get the GTM preview working if you’re using a first-party GTM server container, or via a crazy js file override hack (local only) that I should probably write about!. The method below still works, but might not be as useful as before.

I’m an analytics bum. It’s probably what I like to do the most! You can bet I was excited when Shopify announced Customer Events. Finally! I thought. No more DOM scraping and finicky template hacks that need to be tweaked for every theme. I’ll be able to create one script to rule them all, I thought.

Eagerly, I went on the Customer Events page, set-up a GTM script on the “all_events” event just to test things out, plugged everything in excitedly and… nothing. Nothing was firing at all. I was pretty bummed, so I dived in the docs a bit further. Ah, I discovered, those cool events are sandboxed. No luck on getting an easy win there.

Not one to quit, I went deep in the rabbit hole, and tried a million ways to get those sweet sweet events out of their cage, each more hacky than the next. Then I stumbled on the holy grail: postMessage.  It’s built specifically for communicating data between windows, sandboxed iframes being one of those use cases.

While this method is not officially supported by Shopify, it uses a well documented function, so it should be fairly safe to use.

Add this to theme.liquid and checkout additional scripts:

<script> addEventListener('message', (event) => { if (JSON.stringify(event.data).includes("shopify_pixel_event")) { try { let json_data = JSON.parse(event.data.json) } catch (SyntaxError) { let json_data = {} } if (typeof(event.data.event_name) !== 'undefined') { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: event.data.event_name, data: json_data }); } } }); </script>

And create a custom pixel with this:

analytics.subscribe("all_events", async (event) => { parent.postMessage({'message': 'shopify_pixel_event', 'event_name': event.name, 'json': JSON.stringify(event.data) }, event.context.document.location.origin) });

What’s going to happen with this is that the complete event data for every customer event will be sent over as a JSON string, which will trigger a dataLayer.push event on the main window, that you can use however you’d like. You’ll be able to set-up custom out of the customer event names, parse the data coming from customer events, etc.

This is the basic code that you should tweak for your needs. For example, you might need to structure the data according to GA4 schema. In that case, you could structure it within the Customer Events code block, to send a clean JSON object to catch on the main window. Or you could keep the “raw” object coming from Customer Events, and organize it on the main Window using GTM. It’s your choice!