Shopify GTM Custom Pixel Generator

Push a clean, GA4-style data layer from Shopify's checkout events for Google Tag Manager to read.

Describe the result you need. AI will set up the tool and ask for any missing details.

Configure with AI

Enter to submit · Shift + Enter for a new line

Sent to AI. Leave out passwords and private customer data.

Your details

Paste into Settings > Customer events > Add custom pixel

gtm-custom-pixel.js
// Pushes a clean GA4-style data layer from Shopify's Web Pixels API, for Google Tag Manager.
// Paste into Settings > Customer events > Add custom pixel, save, then click Connect.
window.dataLayer = window.dataLayer || [];

const plainId = (id) => (id == null ? undefined : String(id).split('/').pop());
const money = (m) => (m && m.amount != null ? Number(m.amount) : 0);
const round = (x) => Math.round(x * 100) / 100;
function itemOf(variant, quantity) {
  variant = variant || {};
  const product = variant.product || {};
  const variantTitle = variant.untranslatedTitle || variant.title;
  return {
    id: variant.sku || plainId(variant.id),
    name: product.untranslatedTitle || product.title || variant.title,
    variant: variantTitle && variantTitle !== 'Default Title' ? variantTitle : undefined,
    price: money(variant.price),
    quantity: quantity || 1,
  };
}
function checkoutItems(checkout) {
  return (checkout.lineItems || []).map((line) => {
    const quantity = line.quantity || 1;
    const unit = money(line.variant && line.variant.price);
    const allocated = (line.discountAllocations || []).reduce((sum, d) => sum + money(d.amount), 0);
    const price = round(Math.max(0, unit * quantity - allocated) / quantity);
    return Object.assign(itemOf(line.variant, quantity), { price });
  });
}
const itemsValue = (items) => round(items.reduce((sum, item) => sum + item.price * item.quantity, 0));

/* ---------- Events ---------- */
analytics.subscribe('product_viewed', (event) => {
  const variant = event.data.productVariant;
  const payload = { event: 'view_item', ecommerce: { currency: variant.price.currencyCode, value: money(variant.price), items: [itemOf(variant, 1)] } };
  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push(payload);
});

analytics.subscribe('product_added_to_cart', (event) => {
  const line = event.data.cartLine;
  if (!line) return;
  const payload = { event: 'add_to_cart', ecommerce: { currency: line.cost.totalAmount.currencyCode, value: money(line.cost.totalAmount), items: [itemOf(line.merchandise, line.quantity)] } };
  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push(payload);
});

analytics.subscribe('checkout_started', (event) => {
  const checkout = event.data.checkout;
  const items = checkoutItems(checkout);
  const payload = { event: 'begin_checkout', ecommerce: { currency: checkout.currencyCode, value: itemsValue(items), items } };
  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push(payload);
});

analytics.subscribe('checkout_completed', (event) => {
  const checkout = event.data.checkout;
  const order = checkout.order || {};
  const items = checkoutItems(checkout);
  const payload = {
    event: 'purchase',
    ecommerce: {
      transaction_id: plainId(order.id) || checkout.token,
      currency: checkout.currencyCode,
      value: itemsValue(items),
      tax: money(checkout.totalTax),
      shipping: money(checkout.shippingLine && checkout.shippingLine.price),
      coupon: (checkout.discountApplications || []).map((d) => d.title).filter(Boolean).join(',') || undefined,
      items,
    },
  };
  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push(payload);
});

To add it: Shopify admin > Settings > Customer events > Add custom pixel. Name it "GTM Data Layer", paste the code, Save, then click Connect. Shopify only runs custom pixels after the shopper accepts Marketing/Analytics where consent is required; check that under Customer privacy > Permission.

Wire it up in GTM: 1. In GTM: Variables > New > Data Layer Variable, one each for ecommerce.value, ecommerce.currency, ecommerce.items, ecommerce.transaction_id (and any others you need). 2. In GTM: Triggers > New > Custom Event, one per event name used above (view_item, add_to_cart, begin_checkout, purchase). 3. In GTM: Tags > your ad or analytics tag > fire on the matching trigger, and map the fields to the variables from step 1. 4. Preview mode in GTM won't see this pixel directly (custom pixels run in a separate sandbox). Use GTM's own debug console after publishing, or turn on "Log each push" above and check the storefront's browser console.

This isn't an importable GTM container file: Shopify's custom pixel sandbox can't run Google Tag Manager itself, so there's nothing to "install" GTM into here. This script pushes plain objects to window.dataLayer; GTM (loaded normally in your theme, or through the Google & YouTube app) reads them the same way it reads any other data layer push.

Why this needs a custom pixel

Shopify's checkout runs in a locked-down environment: apps and theme code can't inject scripts into checkout pages directly. Instead, Shopify runs custom pixels in a separate sandbox that subscribes to standard events (product_viewed, checkout_completed, and so on) through the Web Pixels API.

This generator turns those events into the data layer shape Google's own GTM ecommerce guide recommends: an event name plus an ecommerce object with currency, value and items, cleared with ecommerce: null before each push so old values don't leak into the next event.

Wiring it up in GTM

  1. 01

    Install the pixel

    Shopify admin: Settings > Customer events > Add custom pixel. Paste the generated code, save, then Connect.

  2. 02

    Add Data Layer Variables in GTM

    One each for ecommerce.value, ecommerce.currency, ecommerce.items, ecommerce.transaction_id.

  3. 03

    Add Custom Event triggers

    One per event name used: view_item, add_to_cart, begin_checkout, purchase.

  4. 04

    Point your tags at the triggers

    Your ad platform or analytics tags fire on the matching trigger and read the variables from step 2.

GTM's own Preview mode can't see inside the pixel sandbox. Turn on the debug option in this tool to log every push to the storefront's browser console while you test.

Questions people ask

Does this replace Google Tag Manager itself?

No. GTM still runs normally in your theme or through the Google & YouTube app. This pixel only pushes checkout and product event data to window.dataLayer for GTM to read.

Can I get an importable GTM container file?

Not from this tool: the custom pixel sandbox can't run GTM, so there's nothing to import a container into. Set up the triggers and variables directly in GTM using the steps in the guide; it's a one-time, few-minute setup.

Will this double-count if I already have GA4 tracking?

It can, if another pixel or theme script already sends the same GA4 events. Keep only one source of ecommerce events per platform.

Does it work with Shopify Markets / multiple currencies?

Yes. Currency and value come from the checkout's own currencyCode and line item prices, whatever currency the shopper is checking out in.

Want this builtinto your store?

I'm Emmanuel, a Shopify and WooCommerce developer. If this tool pointed at something you'd rather have fixed for you (a faster store, cleaner product data, a migration, a custom feature), send me a note.

Emmanuel Asika

Emmanuel Asika

Shopify & WooCommerce developer, Dublin

I build and fix online stores: new builds, migrations, speed, SEO and the custom bits apps can't do.

hello@emmanuelasika.com