How To Install GA4 On Shopify Using Customer Events, Pixels, and GTM

To add Google Analytics 4 to the Shopify checkout process using customer events with a custom pixel, use the code snippet further down the page. To get started, go to “Settings > Customer events > Add custom pixel”.

Shopify custom pixel for GA4 using customer events

However, before you add the pixel code snippet, there are a few caveats I noticed with GA4 when applied using Shopify customer events and a custom pixel:

  1. Event tracking is not 100% reliable. Maybe not even 90%. I run many tests, but some events only work some of the time. These events were primarily checkout_started, payment_info_submitted, and checkout_completed. I suspect this is an implementation feature on the Shopify end more than a bug. But, still, I can not reason with the behavior.
  2. You may need to “Connect” a custom pixel and then “Disconnect” and “Connect” again to flush your custom pixel code.
  3. Eventually, Google may add a Shopify App pixel. If and when they do, you should switch to their App pixel instead of this custom setup.
  4. I recommend setting up a separate GTM Container ID and GA4 property just for the Shopify customer event pixels. Until it’s more clear how Shopify will improve the customer events and custom pixels, I don’t see how they can be used for production reliably.

Now, for the code, ensure you replace the XXXXXXXXXX in the snippet with your Google Tag Manager ID (Container ID). XXXXXXXXXX is in two places in the code.

const script = document.createElement('script');
script.setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id=XXXXXXXXXX');
script.setAttribute('async', '');
document.head.appendChild(script);

window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'XXXXXXXXXX');

analytics.subscribe("search_submitted", (event) => {
  gtag("event", "search", {search_term: event.data.searchResult.query});
  gtag("event", "view_search_results", {
    search_term: event.data.searchResult.query,
    items: []
  })
});

analytics.subscribe("collection_viewed", (event) => {
  gtag("event", "view_item_list", {
    item_list_id: event.data.collection.id,
    item_list_name: event.data.collection.title,
    items: []
  });
});

analytics.subscribe("product_added_to_cart", (event) => {

  let totalPrice = event.data.cartLine.merchandise.price.amount * event.data.cartLine.quantity;
  
  gtag("event", "add_to_cart", {
    currency: event.data.cartLine.merchandise.price.currencyCode,
    value: totalPrice.toFixed(2),
    items: [
      {
        item_name: event.data.cartLine.merchandise.product.title,
        item_id: event.data.cartLine.merchandise.sku,
        item_variant: event.data.cartLine.merchandise.title,
        currency: event.data.cartLine.merchandise.price.currencyCode,
        item_brand: event.data.cartLine.merchandise.product.vendor,
        price: event.data.cartLine.merchandise.price.amount,
        quantity: event.data.cartLine.quantity
      }
    ]
  });
});

function ga4CheckoutEvents(event) {
  let checkout = event.data.checkout;
  let lineItems = [];

  for (const checkoutLineItem of event.data.checkout.lineItems){
    lineItems.push({
      item_id: checkoutLineItem.variant.sku,
      item_name: checkoutLineItem.title,
      item_variant: checkoutLineItem?.variant.title,
      currency: checkoutLineItem.variant.price.currencyCode,
      item_brand: checkoutLineItem.variant.product.vendor,
      price: checkoutLineItem.variant.price.amount,
      quantity: checkoutLineItem.quantity
    });
  }

  payload = {
    currency: checkout.totalPrice.currencyCode,
    value: checkout.totalPrice.amount,
    items: lineItems
  };
  
  return payload;
}

analytics.subscribe("product_viewed", (event) => {
  gtag("event", "view_item", {
    currency: event.data.productVariant.price.currencyCode,
    value: event.data.productVariant.price.amount,
    items: [
      {
        item_id: event.data.productVariant.sku,
        item_name: event.data.productVariant.product.title,
        item_variant: event.data.productVariant.title,
        currency: event.data.productVariant.price.currencyCode,
        item_brand: event.data.productVariant.product.vendor,
        price: event.data.productVariant.price.amount,
      }
    ]
  });
});

analytics.subscribe("checkout_started", (event) => {
  gtag("event", "begin_checkout", ga4CheckoutEvents(event));
});

analytics.subscribe("payment_info_submitted", (event) => {
  gtag("event", "add_payment_info", ga4CheckoutEvents(event));
});

analytics.subscribe("checkout_completed", (event) => {
  
  let payload = ga4CheckoutEvents(event);
  let checkout = event.data.checkout;

  payload.transaction_id = checkout.order?.id || checkout.token;
  payload.shipping = checkout.shippingLine?.price.amount || checkout.shipping_line?.price.amount || 0;
  payload.tax = checkout.totalTax?.amount || 0;
  
  gtag("event", "purchase", payload);
});

Closing Thoughts

If you wish to dive deeper into the Shopify customer events API, see their documentation on customer events. Also, see a full list of Google Analytics 4 gtag events. When you see the list of gtag events and Shopify events, you will notice that Shopify has a very limited list of events compared to GA4. The above JavaScript code snippet accounts for all the events Shopify provides to date.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.