Marketing | Creative | Strategy

Your faithful partner in the discovery of endless digital opportunity.

Take the First Step

Passing Shopify Events to GTM with Custom Web Pixels

For those using Google Analytics 4 (GA4) with Google Tag Manager (GTM), tracking specific user actions on Shopify—especially custom events like viewing a collection page—can be challenging. While Shopify’s default tracking setup captures basic e-commerce events, some interactions, like viewing item lists, require additional customization. This guide will explore how to use Shopify's Custom Pixels to track custom events without cluttering your Liquid files. We’ll also walk through setup steps, tackle debugging limitations, and share best practices for respecting user privacy by leveraging Shopify's Customer Privacy API. Whether you’re a seasoned analytics pro or new to e-commerce tracking, this article will guide you in setting up seamless and privacy-compliant custom tracking on Shopify.

Setting up e-commerce tracking in GA4 with Shopify is straightforward. By installing the Google & YouTube Sales Channel app, you can track several e-commerce events automatically.

Shopify sales channels list with Google & YouTube highlighted.

Once the app is installed, log into the Google account linked to your GA4 property, and your setup is complete:

Google Analytics property with site data sharing highlighted.

Tracking Additional Events with GA4

While standard e-commerce events are now tracked, you might want to track additional user interactions, such as visits to a collection page. In GA4, this is called the “view_item_list” event:

Google Analytics additional events listed

Yet, Shopify does not generate it by default.

Previously, you could set up this event by adding code to the “theme.liquid:”

Adding code in the theme.liquid.

The code checks if the page is a collection and pushes the “view_item_list” custom event along with the required parameters (the “items” array was left out to keep the code sample smaller) to GTM’s “window.dataLayer.” In the GTM, we use a custom event trigger to listen for this push and then fire the GA4 Event Tag. It is a valid approach that we can continue using even today.

That being said– the folks at Shopify decided that there has to be a cleaner way of adding all these tracking pixels. This reminds me of the separation of concerns in web development, where all CSS goes into external CSS files, and all JavaScript goes into their respective external JS files. Keeping all pixel codes in a separate container makes your Liquid easier to read and potentially alleviates performance issues caused by the need to create hooks and event listeners.

Shopify came up with Custom Web Pixels

Introducing Shopify Custom Web Pixels

To simplify tracking, Shopify now offers Custom Web Pixels. These allow you to create a standalone container for pixel codes, making Liquid files cleaner and easier to work with.

Setting Up Custom Web Pixels

Go to Shopify > Settings > Customer Events and open the Custom Pixels tab to view or create custom web pixels. For example, the only custom pixel set up on this store is shown below:

Custom pixel set up showing.

Shopify automatically emits several events, such as the “collection_viewed,” which triggers whenever a user views a collection page. This makes it ideal for setting up the GA4 “view_item_list” event without modifying Liquid files.

Tip: Use clear names for each pixel. For example, "GTM - view_item_list" would describe this pixel’s function more accurately than the name I initially gave it - the “GTM.” Fortunately, renaming pixels is pretty straightforward, as shown in the below screenshot:

Renaming pixels screenshot.

Custom Pixel Code: Permissions and Setup

To see the pixel’s setup and settings, click on it.

Each custom pixel has two main parts:

  1. Customer Privacy: This section has Permission and Date Sale settings. They are primarily used to determine if the pixel should run only with user consent.
  2. Pixel Code: The JavaScript code that handles event subscriptions and dataLayer pushes.
Two main parts of custom pixel: Customer privacy and Code.

Customer Privacy > Permissions:

Here, we tell Shopify if user consent is required to initialize the Pixel code.

  • Required: Fires only when users consent to marketing, analytics, and Preferences cookies.
  • Not Required: Fires regardless of user consent.
Customer privacy settings showing data permissions and sale options.

In most cases, it’s safer to require users to consent; that is, select the “Required” and keep everything checked.

What about the “Data sales?” To be honest, I have no idea. I would leave it as default.

The JavaScript code includes two sections:

  1. JavaScript Library: Sets up the dataLayer array and initializes GTM.
  2. Event Subscription: Uses the “subscribe” method to listen for standard Shopify events and run our code.

Here is the code I used, broken down into three parts (complete code listing is here):

JavaScript code step one: Initialize the JavaScript pixel SDK.

The line comments make the code pretty self-explanatory. First, we ensure that the “window.dataLayer” is an array so that we can eventually push event objects to it. What follows next is a simple GTM container code, though nicely formatted. That was part number one.

Next, within the Custom Pixel, we have access to the “analytics.subscribe” method that allows us to register callback functions to run when a user triggers a specific event on our site. Here is how it looks for the “collection_viewed” Shopify hook:

Java Script code step two: Subscribe to customer events with analytics.subscribe().

When the “colleciton_viewed” event is emitted, Shopify invokes our callback function by passing it the “event” object. Depending on the type of event, the “event” object might have a different set of properties (“event” object of the collection_viewed).

Code showing callback function passing the 'event' object.

GA4’s “view_item_list” event expects the “items” parameter to list the collection’s products. However, the property names supplied by Shopify do not exactly match those GA4 expects, so I had to create the “createItems” helper function to remedy that. 

Configuring the GA4 Tag

With normalized “items” value, we push a new event object to the dataLayer. Within the GTM, we create a custom event trigger and use a GA4 tag to fire the event:

GA4 event setup showing parameters and missing Google tag warning.

Once the custom pixel code is ready, we need to connect it:

Connecting custom pixel.

The pixel listens for the subscribed events only once it has been connected. More so, what happens is that Shopify does not even include it as an iFrame unless it is connected. Each pixel has an ID. You can see it in the page’s URL if you open it to see the pixel’s code:

/settings/customer_events/pixels/119898405

In my case, the ID of the renamed “GTM - view_item_list” pixel is “119898405.” I can go to the Elements tab of the WebDev tools and find it as a substring of an iFrame’s URL:

Elements tab of the WebDev tools screenshot showing pixel's ID.

If I were to disconnect the pixel and then hard refresh the page’s URL, I would no longer be able to find that iFrame in the source code.

Setting the Correct Page Location

Within the dataLayer push, we have this extra parameter:

"page_location": event.context.window.location.href

Shopify’s custom pixel is added to the site through an iFrame. Unless you change the default value of the page location, it will be set to the URL of the iFrame file. With this faulty setup, you could end up seeing something like this within GA4’s page reports:

GA4’s page reports showing total URLs.

Those are not URLs I want associated with my “view_item_list” events. Instead, I want them to be URLs of the Shopify collections I visited. Therefore, we need to override GA4’s automatically set “page_location” property by sending it as the event’s parameter. Here is a screenshot of the GA4 tag setup: 

Screenshot of the GA4 tag setup.

Next, we collect it from within GTM through a data layer variable and use its value to override GA4’s default “page_location:”

Screenshot of overriding GA4’s default 'page_location'.

Debugging custom pixels

Custom pixels make subscribing to Shopify’s events easy and help keep Liquid files uncluttered with tracking codes. With the abovementioned benefit, they also introduce some level of difficulty related to their debugging. 

Shopify’s custom pixels run in a so-called “Lax” sandbox, which introduces some limitations. As a result, you cannot debug custom pixel using:

  • GTM’s Debug & Preview
  • GA4’s DebugView
  • Developer Console’s “window.dataLayer” calls

Whenever you push a new event through custom pixels, you push it into the dataLayer local to Shopify. It is not the same dataLayer object you might be used to, one that resides on the global “window” object. With the above custom pixel in place and running, typing the “window.dataLayer” in the Console won’t show me event objects pushed through the custom pixel. There is simply no way to reference the browser’s “window” object. The “window” object you see me referencing in the above code snippets is a clone created by Shopify, and it only includes a limited set of properties. 

Therefore, to help troubleshoot the implementations, it might be helpful to log this local dataLayer object to the Console directly from the pixel:

Screenshot showing how to log in object to the Console.

Here is a sample Console output:

Console output: view_item_list.

And here is a sample output of the “window.dataLayer” as entered directly in the Console (notice that this array has 19 elements and, therefore, is an entirely different array):

A sample output of the 'window.dataLayer' as entered directly in the Console.

Other tools to help debug custom pixel events are:

  • Adswerve Chrome Extension. It is a free Chrome dataLayer inspection extension that works great and seems to have tons of other useful debugging features. 
  • Deprecated Tag Assistant Legacy. Yes, you read correctly. It has to be a depreciated legacy one. Once you visit the page and know your tags should have fired, open the GTM tab to see your location (Shopify-only) dataLayer object (see screenshot below).
Screenshot of Google Tag Manager.

Testing User Consent with the Customer Privacy API

Each custom pixel has the permissions section, as was mentioned above. What’s shown in the screenshot below are the defaults (require user consent for marketing and analytics cookies to fire the custom pixel):

Permissions section of custom pixel.

A tag set to fire only when the user grants consent must not push event data to the data layer. Shopify’s Customer Privacy API (a browser-based JavaScript API) provides an easy way to verify if the pixel respects the permissions set. We can use it to apply consent decisions to Shopify-managed surfaces, like pixels; more so, we can run it all in the Developer Console. 

Loading the API

Customer Privacy API is loaded in the “window.Shopify.customerPrivacy” and is an object. Most of the time, when you visit a Shopify store, it will load this API automatically for the domain visited. That being said, we can always check if the API has loaded by running the “window.Shopify.customerPrivacy” command in the Developer Console:

Checking if the API has loaded by running the 'window.Shopify.customerPrivacy' command.

The above means that the API has been loaded into the browser and is available for the specific Shopify domain. Should you discover that the API has not been loaded, you can load it manually by running the following:

API loading manually.

It is a Shopify API, so it does not work for non-Shopify sites.

Check current permissions

Once we know that the API is available, we can check the user’s current cookie permissions for the domain by running one of these commands:

  • window.Shopify.customerPrivacy.preferencesProcessingAllowed();
  • window.Shopify.customerPrivacy.analyticsProcessingAllowed();
  • window.Shopify.customerPrivacy.marketingAllowed();
  • window.Shopify.customerPrivacy.saleOfDataAllowed();

Let’s check if the analytics cookies are allowed (the user granted their permission):

Code example showing analytics cookie permission check in Shopify API returning 'true'.

The " true " return value means the user consented to receive analytics cookies, which means our custom pixel has permission to run.

Note: It does not matter which page of the site we run Customer Privacy API calls on since they apply to the whole domain.

It means the user consents to the use of the analytics cookies (used by GA4), and our custom GTM - view_item_list (yes, I renamed it) will run when we visit a collection page:

Screenshot of event 'collection_viewed' triggered with GA4 and custom GTM setup.

We can manually change the consent state using this API using the “window.Shopify.customerPrivacy.setTrackingConsent” method. Let’s say we want to fake user not granted their consent:

Code screenshot showing window.Shopify.customerPrivacy.setTrackingConsent() method to change consent state.

Below that code, we once again use the “analyticsProcessingAllowed” method to see if the analytics cookie consent was granted. The value “false” means it has not.

A visit to any collection page of the still will no longer trigger our Custom Pixel code. Since nothing is pushed to the dataLayer, the GA4 tag within our GTM won’t fire either. 

What is interesting is that setting cookie permissions in the Developer Console using the “window.Shopify.customerPrivacy.setTrackingConsent” method acts as if we were to indeed click on the “Decline” button of the cookie banner. With consent not granted, open the Network tab of the DevTools and see if other GA4 events fire by filtering them with the “/collect?v=2.” They will not. It seems like a quick way to ensure we don't artificially inflate event data while testing. 

GA4 Event Initiator

Interestingly, while the only action performed through the custom web pixel was pushing an event to the dataLayer (with the actual event sent through a GTM tag), examining the "view_item_list" request in the Developer Network shows that its Initiator is the URL of the iFrame used to embed the pixel. Here is the “view_item_list” network request sent to the GA4 API endpoint:

Screenshot of 'view_item_list' network request showing initiator as iFrame URL.

In the Initiator section, I see the following URL:

Showing urls in the initiator section.

This URL matches the ID of the custom web pixel, which was inserted into the page via an iFrame:

Elements tab screenshot showing pixel's ID.

Therefore, by analyzing GA4 requests, we can get insights into the origin source of specific events.

And we are done!

By using Shopify's Custom Pixels to track non-standard events like collection views, you streamline your code and maintain flexibility for future tracking needs. The setup process may introduce some new technical considerations, particularly around debugging and permissions, but the benefits—clearer Liquid files, modular tracking, and greater control over consent—make the investment worthwhile. 

With this guide, you’re well-equipped to capture essential event data on Shopify, giving you the insights needed to optimize both user experience and marketing performance in GA4.

close[x]

Get A Quote

Ready to take the next step? Please fill out the form below. We can't wait to hear from you!

Once submitted, a Slicedbread representative will be back in touch with you as soon as possible.

* Required Fields