Blog

>

>

Shopify Tracking Migration: GTM Custom Pixel

All Shopify users must migrate their Google Tag Manager setup before August 26, 2025 to keep analytics and ad tracking working. This guide explains the steps for setting up Google Tag Manager (GTM) with Shopify’s new custom event tracking system.

Deadline Warning: If you do not complete this migration before August 26, 2025, your tracking will stop working. Ad platforms will no longer receive conversion data, and analytics will be incomplete.

Why This Tracking Migration Matters

Shopify is changing how tracking works for store owners. The new model affects anyone using Google Tag Manager (GTM), Google Analytics, or custom event tracking for advertising and performance measurement.

If you rely on tracking for ads, analytics, or conversion measurement, you must update your setup before August 26, 2025. Without the migration, your tracking will break, conversion attribution will be unreliable, and ad platforms will not receive accurate conversion data.

What’s Changing in Shopify Tracking

  • Checkout is now on a new extensible model that limits custom script placement
  • Events are captured through Shopify’s analytics.subscribe() API
  • A custom data layer is needed to push events into GTM

Understanding the New Shopify Tracking Model

Client-Side vs Server-Side Tracking

  • Client-Side Tracking: Sends tracking data directly from the visitor’s browser to analytics tools.
  • Server-Side Tracking: Sends tracking data from your server to analytics platforms. This offers more reliability and better privacy compliance but requires extra setup.
Pro Tip: Start with client-side tracking now to meet the deadline, then consider adding server-side GTM later for better data accuracy.

Impact on GTM Users

You will now need to:

  1. Subscribe to Shopify standard events
  2. Push these events to the GTM data layer
  3. Map these events to your GTM tags

Step-by-Step Guide to Migrating Shopify Tracking

Step 1: Audit Your Current Tracking Setup

  • Review your current tracking events
  • Check where your GTM container is currently installed
  • Identify any scripts added directly into the theme or checkout

Step 2: Prepare Your Google Tag Manager Account

  • Confirm you have admin access to GTM
  • Export a backup of your current GTM container
  • Have your GTM container ID ready (format: GTM-XXXXXXX)

Step 3: Add the Custom Pixel in Shopify

  1. Go to your Shopify Admin
  2. Navigate to Customer events
  3. Click Add custom pixel
  4. Name it Google Tag Manager
  5. Set privacy permissions:
    • Under Permission, select No Permission Required
    • Under Data sale, choose Data collected does not qualify as data sale
  6. Paste the GTM tracking code from the next section
  7. Save and connect the pixel

Insert the GTM Tracking Script

Replace GTM‑YOUR_ID with your Google Tag Manager container ID.


  (function () {
  // --- 0) Utilities ---
  function uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }

  // --- 1) Load GTM ---
  (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‑YOUR_ID');

  // Ensure dataLayer exists
  window.dataLayer = window.dataLayer || [];

  // --- 2) Normalizers (GA4 item format) ---
  function fromVariant(variant, qty) {
    if (!variant) return null;
    const p = variant.product || {};
    const priceAmount = (variant.price && (variant.price.amount ?? variant.price)) || 0;
    const currency = (variant.price && variant.price.currencyCode) || undefined;

    return {
      item_id: variant.sku || variant.id || p.id || 'unknown',
      item_name: p.title || 'unknown',
      item_brand: p.vendor || undefined,
      item_category: p.type || undefined,
      item_variant: variant.title || undefined,
      price: Number(priceAmount),
      quantity: Number(qty || 1),
      currency: currency
    };
  }

  function fromCartLine(line) {
    const v = line?.merchandise;
    return fromVariant(v, line?.quantity || 1);
  }

  function fromCheckoutLine(line) {
    const v = line?.variant;
    const base = fromVariant(v, line?.quantity || 1);
    if (!base) return null;
    const amount = line?.finalLinePrice?.amount ?? v?.price?.amount ?? 0;
    const code = line?.finalLinePrice?.currencyCode ?? v?.price?.currencyCode;
    base.price = Number(amount);
    base.currency = code;
    return base;
  }

  // --- 3) Subscriptions (GA4-style events) ---

  // page_view
  analytics.subscribe('page_viewed', function (e) {
    const shop = e?.data?.shop || {};
    window.dataLayer.push({
      event: 'page_view',
      event_id: uuid(),
      currency: shop.currency
    });
  });

  // view_item
  analytics.subscribe('product_viewed', function (e) {
    const v = e?.data?.productVariant;
    const item = fromVariant(v, 1);
    if (item) {
      window.dataLayer.push({
        event: 'view_item',
        event_id: uuid(),
        ecommerce: {
          currency: item.currency,
          items: [item]
        }
      });
    }
  });

  // add_to_cart
  analytics.subscribe('product_added_to_cart', function (e) {
    const line = e?.data?.cartLine;
    const item = fromCartLine(line);
    if (item) {
      window.dataLayer.push({
        event: 'add_to_cart',
        event_id: uuid(),
        ecommerce: {
          currency: item.currency,
          items: [item]
        }
      });
    }
  });

  // remove_from_cart
  analytics.subscribe('product_removed_from_cart', function (e) {
    const line = e?.data?.cartLine;
    const item = fromCartLine(line);
    if (item) {
      window.dataLayer.push({
        event: 'remove_from_cart',
        event_id: uuid(),
        ecommerce: {
          currency: item.currency,
          items: [item]
        }
      });
    }
  });

  // view_cart
  analytics.subscribe('cart_viewed', function (e) {
    const lines = e?.data?.cart?.lines || [];
    const items = lines.map(fromCartLine).filter(Boolean);
    if (items.length) {
      const currency = items.find(i => i.currency)?.currency;
      window.dataLayer.push({
        event: 'view_cart',
        event_id: uuid(),
        ecommerce: {
          currency: currency,
          items: items
        }
      });
    }
  });

  // begin_checkout
  analytics.subscribe('checkout_started', function (e) {
    const co = e?.data?.checkout;
    const lines = co?.lineItems || [];
    const items = lines.map(fromCheckoutLine).filter(Boolean);
    window.dataLayer.push({
      event: 'begin_checkout',
      event_id: uuid(),
      ecommerce: {
        value: Number(co?.totalPrice?.amount || 0),
        currency: co?.currencyCode,
        items
      }
    });
  });

  // purchase (raw GID transaction_id)
  analytics.subscribe('checkout_completed', function (e) {
    const co = e?.data?.checkout || {};
    const lines = co?.lineItems || [];
    const items = lines.map(fromCheckoutLine).filter(Boolean);

    const rawId = co?.order?.id || 'unknown'; // keep full Shopify GID

    window.dataLayer.push({
      event: 'purchase',
      event_id: uuid(),
      ecommerce: {
        transaction_id: rawId,   // raw GID preserved
        value: Number(co?.totalPrice?.amount || 0),
        currency: co?.currencyCode,
        items
      }
    });
  });

  // view_item_list (collections)
  analytics.subscribe('collection_viewed', function (e) {
    const col = e?.data?.collection;
    const variants = col?.productVariants || [];
    const items = variants.map(v => fromVariant(v, 1)).filter(Boolean);
    if (items.length) {
      window.dataLayer.push({
        event: 'view_item_list',
        event_id: uuid(),
        ecommerce: {
          item_list_id: col?.id,
          item_list_name: col?.title,
          items
        }
      });
    }
  });

  // search + view_search_results
  analytics.subscribe('search_submitted', function (e) {
    const sr = e?.data?.searchResult;
    const q = sr?.query;
    window.dataLayer.push({
      event: 'search',
      event_id: uuid(),
      search_term: q
    });

    const variants = sr?.productVariants || [];
    const items = variants.map(v => fromVariant(v, 1)).filter(Boolean);
    if (items.length) {
      const currency = items.find(i => i.currency)?.currency;
      window.dataLayer.push({
        event: 'view_search_results',
        event_id: uuid(),
        ecommerce: {
          currency: currency,
          items
        }
      });
    }
  });

})();

Step 4: Map Events to GTM Tags

In GTM, create triggers for each event such as begin_checkout, purchase, add_to_cart, and others. Link these triggers to your GA4 events, Google Ads conversions, or Facebook Pixel events.

Step 5: Test and Debug Your Tracking

  • Use GTM Preview mode to see events in real time
  • Check your analytics platform’s real-time reports
  • Confirm events fire with the correct parameters

Step 6: Publish Your Changes

Once you confirm events are tracking correctly, publish your GTM container and continue to monitor in your analytics and ad platforms.

Common Issues and Fixes

GTM container not loading: Check that you replaced GTM‑YOUR_ID with your real container ID.

No events in GTM preview: Verify that the pixel is active under Shopify’s Customer events and that privacy permissions match the recommended settings.

FAQs About Shopify Tracking Migration

1. What happens if I miss the deadline? Your event tracking will break and ad platforms will stop receiving conversion data.

2. Do I need server-side GTM for this? It is optional but provides better tracking accuracy and resilience.

3. Can I still use the Facebook Pixel? Yes, by triggering Facebook Pixel events from GTM using the data layer.

4. How do I check if it works? Test in GTM preview mode and check your analytics platform’s live data.

5. Will my old data be lost? No, existing historical data in analytics tools will remain.

6. Can you set this up for me? Yes. I provide GTM setup, migration, and event tracking services.

Final Thoughts and How I Can Help

Migrating to Shopify’s new tracking model before August 26, 2025 is essential for keeping analytics and advertising performance accurate. With the steps above, you can set up the new system yourself. If you prefer, I can complete the migration for you, ensure events are mapped correctly, and even set up server-side tracking for more reliable data.

📩 Contact me here to get your migration done without the hassle.