Shopify Server Side Tracking: Complete Setup Guide (2026)

Ishant

Ishant

Published : June 30, 2026 at 7:53 am

Updated : June 10, 2026 at 8:24 am

Shopify server side tracking is the single biggest accuracy upgrade you can make on a Shopify store in 2026, especially since iOS 14.5 and the wave of browser-level tracking restrictions cut client-side data by 30 to 60% across most ecommerce verticals. Our 9+ ROAS work with Drought Secret (eczema skincare) wouldn’t have been possible without a properly configured server-side setup feeding clean conversion data back to Google Ads and Meta. This guide gives you the complete production-ready setup including the Shopify Custom Pixel JavaScript, the GTM Server Container configuration, the GA4 and Meta CAPI tag setup, and the test commands that prove it’s working. Copy-paste the code, follow the steps, and you’ll have a working server-side stack inside two hours.

What is Shopify server side tracking?

Shopify server side tracking is a conversion tracking setup where event data (purchases, add-to-carts, page views) is sent from your Shopify store to ad platforms through a server you control, instead of directly from the visitor’s browser. The browser sends data to your server, your server enriches and forwards it to Google Ads, Meta, GA4, and other vendors using their respective APIs.

How it differs from client-side tracking

In contrast to server-side, client-side tracking puts a pixel directly in the visitor’s browser. That pixel fires when an event happens (page view, add to cart, purchase) and sends data straight to Google, Meta, TikTok, or wherever else. The visitor’s browser is the messenger. This was the standard for over a decade.

Server-side tracking, on the other hand, puts a server (usually a Google Tag Manager server container hosted on Stape or Google Cloud Run) between the visitor’s browser and the ad platforms. The browser sends a minimal first-party request to your server. Your server enriches the data with user details, hashes personal information, deduplicates events, and forwards everything to ad platforms via their server-to-server APIs (Meta’s Conversions API, GA4’s Measurement Protocol, Google Ads Enhanced Conversions API).

Why this matters in 2026

Three forces have made client-side tracking unreliable on Shopify: iOS 14.5+ ATT blocking the Meta pixel for opt-out users, browser-level cookie restrictions (Safari ITP, Firefox ETP, Brave’s default blocking), and ad blockers that strip out pixel scripts entirely. As a result, conversion under-reporting ranges from 18% in the best-case (desktop-heavy B2B accounts) to 60%+ in mobile-first DTC ecommerce. Server-side tracking recovers most of that data because the server-to-server connection isn’t subject to browser restrictions.

Why do Shopify stores need server side tracking?

Shopify stores need server side tracking because Shopify’s 2024 architecture changes restricted what client-side scripts can do on checkout pages, making it impossible to fire reliable purchase events without a server-side relay. On top of that, Shopify server side tracking restores 30-60% of lost conversion data that browser-side pixels miss due to iOS 14.5, Safari ITP, and ad blockers.

The Shopify checkout extensibility constraint

For example, Shopify deprecated checkout.liquid for Shopify Plus stores in August 2024 and removed third-party script injection from standard checkout pages for non-Plus stores around the same time. The replacement is “Checkout Extensibility” + “Custom Pixels,” a sandboxed environment where you can register event listeners but can’t run arbitrary code or modify the page. This means the old “drop a Meta Pixel snippet into theme.liquid” workflow doesn’t reach the conversion event anymore. A Shopify server side tracking setup using Custom Pixels is now the only reliable path for accurate purchase tracking on Shopify checkout pages.

Conversion lift you can expect

In general, properly implemented Shopify server side tracking typically recovers 25 to 45% additional conversions in Meta Ads Manager and 15 to 30% in Google Ads. The actual lift depends on your mobile traffic mix (more mobile = more recovery), your iOS share (iOS users were hit hardest by ATT), and how many of your customers use ad blockers. For our Drought Secret skincare brand, the post-setup lift in Meta-reported conversions was 38% within 14 days, which let us scale spend confidently because the ROAS signal was no longer corrupted by missing data.

How does Shopify server side tracking work?

Shopify server side tracking works in five steps: (1) the visitor triggers an event on your store, (2) a Shopify Custom Pixel listens for the event, (3) the pixel sends event data via fetch() to your GTM server container, (4) the server container enriches and hashes the data, (5) the server fires server-to-server API calls to GA4, Meta CAPI, Google Ads, and TikTok in parallel.

Shopify Server-Side Tracking Architecture

 Visitor                Your Store               Your sGTM                    Ad Platforms
 (browser)              (Shopify)                (Stape / Cloud Run)
   |                       |                          |                            |
   |  1. Action            |                          |                            |
   |---------------------->|                          |                            |
   |  (purchase, etc)      |                          |                            |
   |                       |                          |                            |
   |                       |  2. Custom Pixel fires   |                            |
   |                       |---  POST /data    ------>|                            |
   |                       |     {payload}            |                            |
   |                       |                          |                            |
   |                       |                          | 3. Client parses payload   |
   |                       |                          | 4. Tags fire in parallel:  |
   |                       |                          |---  GA4 Measurement   ---->| GA4
   |                       |                          |---  Meta CAPI         ---->| Meta
   |                       |                          |---  Google Ads EC     ---->| Google Ads
   |                       |                          |---  TikTok CAPI       ---->| TikTok
   |                       |                          |                            |
   |                       |                          | 5. Returns 200 OK          |
   |                       |<------------------------ |                            |

Server-to-server calls (step 4) aren’t subject to browser cookie restrictions, ad blockers, or iOS 14.5 ATT, which is why server-side recovers conversions client-side pixels miss.

The data flow in detail

First, when a customer completes checkout, Shopify’s Custom Pixel framework emits a checkout_completed event with order details. Your Custom Pixel code subscribes to that event, formats a JSON payload (including transaction ID, order value, line items, customer email, IP-derived data, and user agent), and POSTs it to a custom subdomain like sgtm.yourdomain.com that points to your GTM server container.

Next, the server container receives the request, parses it through a Client (typically the GA4 client or a custom client), and passes the parsed event to one or more Tags. Each tag handles forwarding to a different ad platform: a GA4 tag sends a Measurement Protocol POST to GA4, a Meta Conversions API tag hashes the email and phone and POSTs to the CAPI endpoint, a Google Ads Enhanced Conversions tag POSTs to the Google Ads conversion endpoint. All of this happens server-side in milliseconds.

Why a custom subdomain matters

The Shopify server side tracking endpoint should live on a subdomain of your store’s domain (sgtm.yourdomain.com, not sgtm.gtm-server.com). This makes the request first-party from the browser’s perspective, which preserves cookie context and bypasses most tracking prevention browsers like Safari and Firefox would otherwise apply to a cross-origin request. Stape and Google Cloud Run both support custom domain mapping in their server GTM hosting.

What are the best Shopify server side tracking tools?

The best Shopify server side tracking tools in 2026 are Stape (most flexible, custom GTM container hosting), Elevar (Shopify-specific, fully managed), Taggrs (good middle option), and Conversios (cheapest entry point). For most $20K+/month Shopify stores, Stape with a custom GTM server container gives you the highest accuracy and lowest long-term cost.

Stape vs Elevar vs Taggrs vs Conversios

Each tool occupies a different point on the cost-vs-control tradeoff. In particular:

Stape ($20-200+/month depending on traffic) hosts a GTM server container you fully control, with optional Power-Ups for things like Meta CAPI Gateway, user data enrichment, and event filtering. However, the trade-off is that you’re configuring GTM tags yourself, which means you need someone on your team or agency who knows server-side GTM. This is what we deploy for clients like the UK Shopify hair brand we scaled to 15.25x ROAS because the configuration flexibility justifies the learning curve.

Elevar ($50-500+/month) is Shopify-specific and fully managed. You install the app, connect your destinations (Meta, Google, TikTok, Klaviyo), and they handle the rest. In contrast, Elevar is less flexible than Stape but faster to deploy if you don’t have technical resources.

Taggrs ($30-150/month) sits between Stape and Elevar. Similarly, Taggrs hosts the server container for you but exposes enough configuration that you can customize the setup without being a GTM expert.

Conversios ($10-50/month) is the cheapest option and works well for stores under $10K/month in ad spend. Conversely, Conversios is less accurate than the others because the data layer enrichment is more limited, but the price-to-value ratio is strong for smaller stores.

Which one we recommend by store size

Under $5K/month ad spend on Shopify, Conversios or Elevar’s lower tier. $5K-25K/month, Taggrs or Stape with the cheapest tier. $25K+/month, Stape with the bigger tier plus custom configuration (this is where you start needing the flexibility to add custom tags for TikTok, Klaviyo, Pinterest, and any other vendor outside the standard four). For most of our managed ecommerce clients spending in the $25K-150K/month range, Stape is the default. We cover the full tool comparison including Stape vs Google Cloud Run vs Taggrs in our server-side tagging hosting comparison guide.

How do you set up server side tracking on Shopify with Stape?

Setting up Shopify server side tracking with Stape takes four steps: (1) create a Stape account and provision a GTM server container, (2) configure your custom subdomain to point at the Stape container, (3) install the Shopify Custom Pixel with your endpoint URL, (4) configure tags inside the GTM server container for GA4, Meta CAPI, and Google Ads. Total setup time is 60-90 minutes for someone who’s done it before.

01

Provision Stape container
Sign up at stape.io, create a server-side GTM container, copy config to Stape.

02

Map custom subdomain
Add sgtm.yourdomain.com in Stape, point DNS via CNAME, wait for SSL.

03

Install Custom Pixel
Paste the JavaScript into Shopify Admin → Customer events → Add custom pixel.

04

Configure GTM tags
Add GA4, Meta CAPI, and Google Ads Enhanced Conversions tags, map variables.

Step 1: Provision the Stape container

First, sign up at stape.io and create a new container. You’ll need a server-side Google Tag Manager container ID (looks like GTM-XXXXXXX with a server-side suffix) before this step. Create the GTM container in tagmanager.google.com first, choose “Server” as the container type, and copy the container config to Stape during the setup wizard. Stape will provision a hosting environment and give you a default URL like xyz123.gtm-server.com.

Step 2: Map a custom subdomain

Next, inside Stape, navigate to your container’s settings and add a custom domain like sgtm.yourdomain.com. Stape will give you DNS records (typically a CNAME) to add to your domain registrar. Add them, wait 5-30 minutes for propagation, and Stape will auto-provision an SSL certificate via Let’s Encrypt. Verify the subdomain resolves by visiting https://sgtm.yourdomain.com/healthz, which should return a 200 OK status.

Step 3: Install the Shopify Custom Pixel

Now the code matters. Inside your Shopify admin, navigate to Settings → Customer events → Add custom pixel. Name it “Server Side Tracking – SGTM” and paste the JavaScript shown in the next section. Set the permission level to “Not required” (since you’re sending first-party data through your own infrastructure, not a third-party processor). Save and connect.

Step 4: Configure GTM tags

Finally, open your server-side GTM container and add three core tags: GA4 (for analytics), Meta Conversions API (for Facebook/Instagram ad attribution), and Google Ads Conversion Tracking (for Google Ads attribution). Configure each tag to fire on the relevant events from your Custom Pixel (purchase, add_to_cart, begin_checkout, view_item). Detailed tag configurations follow in the GTM Server Container Configuration section below.

How do you set up the Shopify Custom Pixel for server side tracking?

You set up the Shopify Custom Pixel by going to Shopify admin → Settings → Customer events → Add custom pixel, then pasting JavaScript that subscribes to checkout events and sends them to your GTM server container endpoint. The full production code is below. Replace YOUR-SUBDOMAIN with your actual sgtm.yourdomain.com URL.

The production-ready Custom Pixel code

For best results, copy this entire block into your Shopify Custom Pixel. It handles the four most important ecommerce events (page view, view item, add to cart, checkout completed) and sends a normalized payload to your server container:

// ============================================================
// SHOPIFY CUSTOM PIXEL: Server-Side Tracking
// ============================================================
// WHERE TO PASTE: Shopify Admin → Settings → Customer events → Add custom pixel
//
// CUSTOMIZE BEFORE DEPLOYING:
//   1. Line 16: Replace 'YOUR-SUBDOMAIN' with your actual sGTM custom domain
//      Example: const SGTM_ENDPOINT = 'https://sgtm.curlyhair.com/data';
//
// SANDBOX-SAFE NOTES (critical for first-try success):
//   - Uses browser.cookie.get() because document.cookie returns undefined
//     in the Shopify Custom Pixel Lax sandbox.
//   - event.timestamp is ISO 8601 string; we convert to Unix seconds.
//   - All navigator/document/window access goes through event.context.*
// ============================================================

const SGTM_ENDPOINT = 'https://YOUR-SUBDOMAIN/data';

// Send event payload to server container with keepalive for reliable delivery
async function sendToSGTM(payload) {
  try {
    await fetch(SGTM_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
      keepalive: true
    });
  } catch (err) {
    console.error('SGTM send failed:', err);
  }
}

// Build common payload fields shared across all events
async function buildCommonPayload(eventName, event) {
  // Read cookies through the sandbox-safe browser API (returns Promise)
  const [gaCookie, fbpCookie, fbcCookie, gaSessionCookie] = await Promise.all([
    browser.cookie.get('_ga'),
    browser.cookie.get('_fbp'),
    browser.cookie.get('_fbc'),
    browser.cookie.get('_ga_session')
  ]);

  // Extract GA client ID (last two segments of _ga) or fall back to Shopify clientId
  const clientId = gaCookie
    ? gaCookie.split('.').slice(-2).join('.')
    : event.clientId;

  // event.timestamp is ISO 8601 ("2026-06-10T12:34:56.000Z"); convert to Unix seconds
  const eventTimeSeconds = Math.floor(new Date(event.timestamp).getTime() / 1000);

  return {
    event_name: eventName,
    event_id: event.id,
    event_time: eventTimeSeconds,
    client_id: clientId,
    page_location: event.context.window.location.href,
    page_title: event.context.document.title,
    page_referrer: event.context.document.referrer,
    user_agent: event.context.navigator.userAgent,
    screen_resolution: event.context.window.screen.width + 'x' + event.context.window.screen.height,
    language: event.context.navigator.language,
    fbp: fbpCookie || null,
    fbc: fbcCookie || null,
    ga_session_id: gaSessionCookie || null
  };
}

// This handler captures page view events whenever a visitor lands on any store page.
analytics.subscribe('page_viewed', async (event) => {
  const payload = await buildCommonPayload('page_view', event);
  sendToSGTM(payload);
});

// Product detail page visits fire the next handler with full product context.
analytics.subscribe('product_viewed', async (event) => {
  const product = event.data.productVariant;
  const common = await buildCommonPayload('view_item', event);
  sendToSGTM({
    ...common,
    currency: product.price.currencyCode,
    value: parseFloat(product.price.amount),
    items: [{
      item_id: product.product.id,
      item_name: product.product.title,
      item_brand: product.product.vendor,
      item_category: product.product.type,
      item_variant: product.title,
      price: parseFloat(product.price.amount),
      quantity: 1
    }]
  });
});

// Cart additions trigger this handler whenever a visitor adds any item to cart.
analytics.subscribe('product_added_to_cart', async (event) => {
  const cartLine = event.data.cartLine;
  const common = await buildCommonPayload('add_to_cart', event);
  sendToSGTM({
    ...common,
    currency: cartLine.merchandise.price.currencyCode,
    value: parseFloat(cartLine.cost.totalAmount.amount),
    items: [{
      item_id: cartLine.merchandise.product.id,
      item_name: cartLine.merchandise.product.title,
      item_brand: cartLine.merchandise.product.vendor,
      item_category: cartLine.merchandise.product.type,
      item_variant: cartLine.merchandise.title,
      price: parseFloat(cartLine.merchandise.price.amount),
      quantity: cartLine.quantity
    }]
  });
});

// Beginning the checkout signals strong purchase intent and fires the next subscriber.
analytics.subscribe('checkout_started', async (event) => {
  const checkout = event.data.checkout;
  const common = await buildCommonPayload('begin_checkout', event);
  sendToSGTM({
    ...common,
    currency: checkout.currencyCode,
    value: parseFloat(checkout.totalPrice.amount),
    items: checkout.lineItems.map(item => ({
      item_id: item.variant.product.id,
      item_name: item.title,
      price: parseFloat(item.variant.price.amount),
      quantity: item.quantity
    }))
  });
});

// Successful purchases are the most critical event to capture accurately for ROAS reporting.
analytics.subscribe('checkout_completed', async (event) => {
  const checkout = event.data.checkout;
  const shipping = checkout.shippingAddress || {};
  const billing = checkout.billingAddress || {};
  const common = await buildCommonPayload('purchase', event);

  sendToSGTM({
    ...common,
    transaction_id: checkout.order.id,
    currency: checkout.currencyCode,
    value: parseFloat(checkout.totalPrice.amount),
    tax: parseFloat(checkout.totalTax ? checkout.totalTax.amount : 0),
    shipping: parseFloat(checkout.shippingLine && checkout.shippingLine.price ? checkout.shippingLine.price.amount : 0),
    coupon: (checkout.discountApplications || []).map(d => d.title).join(',') || null,

    // User data sent unhashed; server container hashes before Meta CAPI / Google EC
    email: checkout.email,
    phone: checkout.phone,
    first_name: shipping.firstName || billing.firstName,
    last_name: shipping.lastName || billing.lastName,
    city: shipping.city || billing.city,
    state: shipping.provinceCode || billing.provinceCode,
    country: shipping.countryCode || billing.countryCode,
    zip: shipping.zip || billing.zip,

    items: checkout.lineItems.map(item => ({
      item_id: item.variant.product.id,
      item_name: item.title,
      item_brand: item.variant.product.vendor,
      item_category: item.variant.product.type,
      item_variant: item.variant.title,
      price: parseFloat(item.variant.price.amount),
      quantity: item.quantity
    }))
  });
});

What each helper function does

The buildCommonPayload function pulls together browser context (URL, user agent, screen resolution, language) and the Meta tracking cookies (_fbp and _fbc) that Meta CAPI needs for deduplication with the browser-side Meta Pixel if you still run one. The browser.cookie.get() helper is the only sandbox-safe way to read cookies inside a Shopify Custom Pixel because document.cookie returns undefined in the Lax sandbox. The sendToSGTM function uses fetch with keepalive: true so the request completes even if the visitor navigates away during the transaction.

⚠ Critical sandbox constraints
The Shopify Custom Pixel runs in a Lax iframe sandbox that blocks several common JavaScript patterns. Three things will break your tracking on first try if you don’t account for them: (1) document.cookie returns undefined, use browser.cookie.get() instead; (2) event.timestamp is an ISO 8601 string, not Unix milliseconds, so always convert with new Date(event.timestamp).getTime(); (3) direct document, window, and navigator access is blocked, always go through event.context.document, event.context.window, and event.context.navigator. The code above handles all three.

Why we send user data unhashed

In short, the Custom Pixel sends email, phone, and address fields in plain text to your server container. Instead, hashing happens in the server container before forwarding to Meta CAPI and Google Enhanced Conversions. This is intentional: GTM Server has built-in SHA-256 hashing optimized for each ad platform’s requirements (Meta expects lowercase trimmed before hash, Google expects different normalization), so doing it at the server avoids double-hashing or format mismatches.

How do you configure Google Tag Manager Server Container for Shopify?

You configure the Google Tag Manager Server Container for Shopify by creating a custom client to receive incoming JSON requests, then mapping incoming event data to tags for GA4, Meta CAPI, and Google Ads. The setup uses GTM’s native templates plus one custom client to parse the Shopify Custom Pixel payload format.

Create a custom client for Shopify events

The default GA4 client in GTM Server expects requests in GA4 Measurement Protocol format. Your Custom Pixel sends a simpler JSON shape, so you need a custom client to parse it. In your server-side GTM container:

  1. Navigate to Templates → Client Templates → New
  2. Name it “Shopify Custom Pixel Client”
  3. In the Code tab, paste the client template below
  4. In the Permissions tab, grant: Read request body, Run container, Return response, Log to console
  5. Save the template, then go to Clients → New and create a client using your new template
  6. Set the client to claim requests where the request path equals /data

The client template code:

// ============================================================
// GTM SERVER CONTAINER - Custom Client Template
// ============================================================
// WHERE TO PASTE: GTM Server container → Templates → Client Templates → New
//
// NO CUSTOMIZATION NEEDED for standard deployments.
// Paste this template as-is.
//
// OPTIONAL: If you want a different endpoint path than /data,
// update both path checks below AND the SGTM_ENDPOINT URL in your Custom Pixel.
// ============================================================
// Parses Shopify Custom Pixel payloads from POST /data
// Handles CORS preflight (OPTIONS) requests so browsers can POST cross-origin

const claimRequest = require('claimRequest');
const getRequestPath = require('getRequestPath');
const getRequestMethod = require('getRequestMethod');
const getRequestBody = require('getRequestBody');
const JSON = require('JSON');
const runContainer = require('runContainer');
const returnResponse = require('returnResponse');
const setResponseStatus = require('setResponseStatus');
const setResponseBody = require('setResponseBody');
const setResponseHeader = require('setResponseHeader');
const logToConsole = require('logToConsole');

const path = getRequestPath();
const method = getRequestMethod();

// Only handle requests to /data
if (path !== '/data') {
  return;
}

// Handle CORS preflight request from the browser
if (method === 'OPTIONS') {
  claimRequest();
  setResponseStatus(204);
  setResponseHeader('Access-Control-Allow-Origin', '*');
  setResponseHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
  setResponseHeader('Access-Control-Allow-Headers', 'Content-Type');
  setResponseHeader('Access-Control-Max-Age', '86400');
  returnResponse();
  return;
}

// Only process POST from here on
if (method !== 'POST') {
  return;
}

claimRequest();

const bodyText = getRequestBody();
let event;

try {
  event = JSON.parse(bodyText);
} catch (e) {
  logToConsole('Failed to parse JSON body:', e);
  setResponseStatus(400);
  setResponseHeader('Access-Control-Allow-Origin', '*');
  setResponseBody('Invalid JSON');
  returnResponse();
  return;
}

// Pass the parsed event to all container tags
runContainer(event, () => {
  setResponseStatus(200);
  setResponseHeader('Content-Type', 'application/json');
  setResponseHeader('Access-Control-Allow-Origin', '*');
  setResponseBody('{"success":true}');
  returnResponse();
});

The client template code above handles CORS preflight (OPTIONS) requests in addition to the actual POST. Without that preflight handler, the browser’s first request would fail because Shopify’s iframe sandbox is on a different origin than your sGTM endpoint. The template also returns the Access-Control-Allow-Origin header on every response so the browser doesn’t reject the response.

⚡ Required GTM Server template permissions
When you paste the client template code, the GTM Server template editor will refuse to save until you grant the right permissions. In the template’s Permissions tab, enable: Read request body, Read request data (path, method, headers), Set response status, Set response body, Set response headers, Run container, Return response, Log to console. Missing any one of these throws a runtime error on the first request.

Create event-data variables

For each field in your Custom Pixel payload (transaction_id, value, currency, email, items, etc.), create a corresponding Event Data variable in GTM Server. Variables → New → Event Data, then enter the key path like “value” or “items.0.item_name”. You’ll reference these variables in your tag configurations.

The minimum variable set you need: event_name, event_id, transaction_id, value, currency, tax, shipping, email, phone, first_name, last_name, city, state, country, zip, items, page_location, user_agent, client_id, fbp, fbc.

Create triggers for each event type

Create one trigger per event name. Triggers → New → Custom Event, fire on “Event Name equals purchase” for the purchase trigger. Repeat for view_item, add_to_cart, begin_checkout, and page_view. These triggers will fire the corresponding tags.

How do you set up GA4 server side tracking on Shopify?

In particular, GA4 server side tracking on Shopify works by adding a Google Analytics: GA4 tag in your server container that fires on incoming events from the custom client. Set the Measurement ID to your GA4 stream ID, map the event name and parameters, and the tag forwards each event to GA4 via Measurement Protocol.

GA4 tag configuration

In your server-side GTM container, add a new tag with these settings:

Tag type: Google Analytics: GA4

Measurement ID: Your GA4 measurement ID (format G-XXXXXXX). Find this in GA4 → Admin → Data Streams → your web stream → Measurement ID.

Event Name: {{Event Name}} (the event_name field from your Custom Pixel)

Event Parameters:

  • currency = {{currency}}
  • value = {{value}}
  • transaction_id = {{transaction_id}}
  • tax = {{tax}}
  • shipping = {{shipping}}
  • coupon = {{coupon}}
  • items = {{items}}
  • page_location = {{page_location}}

User Properties: Leave the email/phone fields blank in this tag. GA4 doesn’t accept user PII directly; instead, GA4 uses the client_id and session_id for stitching.

Triggers: Fire on the purchase, view_item, add_to_cart, begin_checkout, and page_view triggers you created.

Verify GA4 server-side data

To verify GA4 is firing, open GA4 → Reports → Realtime. Then make a test purchase on your store in incognito mode. Within 30-60 seconds, you should see the purchase event appear in realtime reporting in the realtime report with the correct revenue value. If the event shows up but revenue is null, check the value variable mapping in your tag. If the event doesn’t appear at all, use GTM Server’s Preview mode to inspect the incoming request.

How do you set up Meta CAPI server side tracking on Shopify?

Meta CAPI server side tracking on Shopify uses the Meta Conversions API tag in your GTM server container to send hashed customer data to Meta’s CAPI endpoint. The tag handles SHA-256 hashing automatically, deduplicates against any client-side Meta Pixel events using event_id, and supports all standard Meta events.

Meta CAPI tag configuration

To configure GA4, add a new tag in your server-side GTM container:

Tag type: Meta Conversions API (install from GTM Server template gallery if not present; search “Conversions API” in the gallery and use Facebook’s official template, currently labeled “Conversion API Tag by Facebook”).

Pixel ID: Your Meta Pixel ID (find in Meta Events Manager → Data Sources → your pixel → ID).

API Access Token: Generate this in Events Manager → Settings → Conversions API → Generate access token. Store the token in your GTM server container as an Environment Variable, then reference it in the tag as {{CAPI_TOKEN}}.

Event Name: Map from your Custom Pixel event_name to Meta’s standard event names:

  • purchase → Purchase
  • add_to_cart → AddToCart
  • view_item → ViewContent
  • begin_checkout → InitiateCheckout
  • page_view → PageView

Above all, use a Lookup Table variable to do this mapping cleanly.

Event ID: {{event_id}} (this enables deduplication with browser-side Meta Pixel if you run one. Critical for accuracy.)

Customer Information Parameters:

  • Email: {{email}}
  • Phone: {{phone}}
  • First Name: {{first_name}}
  • Last Name: {{last_name}}
  • City: {{city}}
  • State: {{state}}
  • Country: {{country}}
  • Zip: {{zip}}
  • FBP: {{fbp}}
  • FBC: {{fbc}}
  • Client IP Address: {{Client IP Address}} (use the built-in GTM Server variable)
  • Client User Agent: {{user_agent}}

Notably, the Meta CAPI tag template handles SHA-256 hashing of email, phone, first_name, last_name, city, state, country, and zip before sending. You don’t need to hash anything manually.

Custom Data:

  • currency: {{currency}}
  • value: {{value}}
  • content_ids: items[*].item_id (array of product IDs)
  • content_type: product
  • contents: {{items}} (the full items array)
  • num_items: items.length

Test Event Code: During setup, generate a test code in Events Manager → Test Events. Add it to the tag temporarily so test purchases show up in the Test Events tab. Remove it before going live.

Event deduplication with browser-side Meta Pixel

If you still run a client-side Meta Pixel (recommended for cross-validation during the migration period), In addition, Meta deduplicates events that have the same event_name and event_id arriving from both sources. Your Shopify Custom Pixel must use the same event_id format as your browser Pixel. Our Custom Pixel code above uses Shopify’s native event.id, which is unique per event and shared across both tracking paths if you’ve configured the browser Pixel correctly. Finally, after 30 days of clean dedup data, you can safely remove the browser Pixel and rely on server-side only.

How do you set up Google Ads Enhanced Conversions through server side tracking?

Google Ads Enhanced Conversions through server side tracking uses the Google Ads Conversion Tracking tag in GTM Server, configured with your conversion ID and label, plus user-provided data fields. Specifically, Enhanced Conversions hashes the email and phone server-side and matches against Google’s logged-in user graph, typically recovering 5-15% of conversions that client-side tracking misses.

Google Ads conversion tag setup

Add a tag in your server GTM container:

Tag type: Google Ads Conversion Tracking

Conversion ID: Your Google Ads conversion ID (format AW-XXXXXXXXX, find it in Google Ads → Tools → Conversions → your conversion → Tag setup).

Conversion Label: The label for the purchase conversion (find it next to the conversion ID).

Conversion Value: {{value}}

Currency Code: {{currency}}

Order ID: {{transaction_id}} (Google Ads uses this for deduplication if you also run client-side conversion tracking)

Enhanced Conversions: Enable. Map:

  • Email: {{email}}
  • Phone Number: {{phone}}
  • First Name: {{first_name}}
  • Last Name: {{last_name}}
  • Street Address: leave blank unless you have it
  • City: {{city}}
  • Region: {{state}}
  • Postal Code: {{zip}}
  • Country: {{country}}

Triggers: Fire on the purchase trigger only (don’t send view_item or add_to_cart to Google Ads as conversions unless you’ve configured those as separate conversion goals).

What needs to be customized in this code before deploying?

Before pasting the code into your store, you need to replace one URL across the Shopify Custom Pixel and the curl test, then configure six values inside the GTM Server container UI. The Custom Pixel JavaScript and the GTM Server Client Template are otherwise paste-and-deploy. Total customization surface for a standard Shopify server side tracking setup: 2 placeholder values in code, 6 dashboard field values.

Prerequisites to gather before pasting any code

Before you touch the code, have these ready in a notes file:

Value neededWhere to find it
sGTM custom domainProvisioned in Stape or Cloud Run with DNS pointed (e.g. sgtm.yourdomain.com)
GTM Server Container IDtagmanager.google.com → create container, choose “Server”
GA4 Measurement IDGA4 → Admin → Data Streams → your web stream (format G-XXXXXXXXXX)
Meta Pixel IDEvents Manager → Data Sources → your pixel (15-16 digit number)
Meta CAPI Access TokenEvents Manager → Settings → Conversions API → Generate token
Google Ads Conversion ID + LabelGoogle Ads → Tools → Conversions → your purchase → Tag setup
Shopify admin accessOwner or staff account with Customer Events permission

Customizable values in the Shopify Custom Pixel code

The Custom Pixel JavaScript needs one mandatory edit:

Line 15 (the SGTM_ENDPOINT constant). Replace YOUR-SUBDOMAIN with your actual sGTM custom domain. For example, if your sGTM lives at sgtm.curlyhair.com, change it to:

const SGTM_ENDPOINT = 'https://sgtm.curlyhair.com/data';

That’s the only required edit. The rest of the script (event subscriptions, payload structure, cookie helpers, fetch logic) works out of the box for any standard Shopify store.

Optional customizations in the Custom Pixel code

Most stores never touch these, but here are the optional edits for non-standard setups:

Cookie names (lines reading _ga, _fbp, _fbc, _ga_session). If your store uses a custom consent management platform that renames cookies, update the cookie names to match. If you’ve never installed a custom CMP, leave these as-is.

Additional event subscriptions. The script covers the five most important events (page_viewed, product_viewed, product_added_to_cart, checkout_started, checkout_completed). If you want to track additional Shopify events like search_submitted, product_removed_from_cart, or payment_info_submitted, copy any existing analytics.subscribe block, change the event name, and adjust the payload fields. The Shopify Custom Pixel API reference lists every available event.

Custom dimensions. Add any field you want to the payload object inside any event handler. The GTM Server container will expose anything you send as an Event Data variable, ready to be mapped to GA4 custom dimensions or Meta CAPI custom data.

Customizable values in the GTM Server Client Template

The Custom Client Template has no mandatory edits. Paste it as-is. The only optional edit is the request path on line 19, where the template claims POST requests to /data. If you want a different endpoint path (for example, you’re already using /data for something else and want /shopify instead), change both the template’s path check AND the SGTM_ENDPOINT URL in your Custom Pixel to match.

Customizable values in the curl test command

Replace sgtm.yourdomain.com with your actual sGTM custom domain on the first line of the curl command. The payload values are sample test data; you can leave them as-is for the initial endpoint verification, or replace email/phone with a real test address if you want to validate the full Meta CAPI match quality.

Configuration values needed in the GTM Server tag UI

Once the Custom Pixel is sending data and the Client is parsing it, you configure each ad platform tag inside the GTM Server container web interface. These are dashboard fields, not code edits:

GA4 tag:

  • Measurement ID: paste your G-XXXXXXXXXX
  • Event parameters: map from Event Data variables you create (value, currency, transaction_id, items, etc.)

Meta Conversions API tag:

  • Pixel ID: paste your Meta Pixel ID
  • API Access Token: reference as a GTM environment variable (don’t paste raw)
  • Test Event Code: paste during initial setup, remove before going live
  • Customer Information Parameters: map email, phone, name, address, fbp, fbc
  • Custom Data: map currency, value, content_ids, content_type, contents

Google Ads Enhanced Conversions tag:

  • Conversion ID: paste your AW-XXXXXXXXX
  • Conversion Label: paste the label string for your purchase conversion
  • Enhanced Conversions: toggle ON, map email/phone/name/address fields
  • Order ID: map to the transaction_id Event Data variable for deduplication

That’s the complete customization surface. Two code edits and three tag configurations stand between you and a fully working Shopify server side tracking setup.

How do you test Shopify server side tracking?

Test Shopify server side tracking by running test purchases in incognito mode and checking three places: the GTM Server Preview mode for incoming requests, GA4 Realtime for the purchase event, and Meta Events Manager Test Events for the CAPI event. Each platform should show the test purchase within 60 seconds with correct value, currency, and customer data.

The full test sequence

Before going live, run this sequence:

1. GTM Server Preview mode. In your server GTM container, click Preview. This opens a debug session that captures incoming requests. Open your Shopify store in incognito, complete a test purchase (use a real test order with Bogus Gateway or a discount code that drops the price to $0.01). Within seconds, Preview mode should show the purchase event with all variables populated. If any variable shows undefined, the Custom Pixel payload is missing that field.

2. GA4 DebugView. Open GA4 → Configure → DebugView. The test purchase should appear with the purchase event, your transaction ID, and the correct value. Items array should expand to show each line item. If DebugView is empty, your GA4 Measurement ID is wrong or the event_name parameter isn’t mapped.

3. Meta Events Manager Test Events. Open Events Manager → your pixel → Test Events. Enter the test event code you configured in the CAPI tag. Make a test purchase. The Purchase event should appear with the correct value, currency, and the contents array. Check the “Server” badge next to the event to confirm it came through CAPI rather than the browser Pixel.

4. Google Ads conversion diagnostics. Open Google Ads → Tools → Conversions → your purchase conversion. The “Recent Conversions” status should switch from “No recent conversions” to “Recording conversions” within 24 hours. For Enhanced Conversions specifically, check the “Diagnostics” tab, which should show a non-zero match rate after 48-72 hours.

The curl test for quick endpoint verification

Before fully testing the Shopify integration, you can verify your server container endpoint is reachable with a curl command:

# ============================================================
# CURL TEST: Verify your sGTM endpoint before testing Shopify
# ============================================================
# CUSTOMIZE BEFORE RUNNING:
#   Replace 'sgtm.yourdomain.com' with your actual sGTM custom domain.
#   The payload values below are sample test data; replace if needed.
# Expected response: HTTP 200 with body {"success":true}
# ============================================================

curl -X POST https://sgtm.yourdomain.com/data \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "purchase",
    "event_id": "test_001",
    "transaction_id": "TEST-001",
    "value": 99.99,
    "currency": "USD",
    "email": "test@example.com",
    "phone": "+15555551234",
    "first_name": "Test",
    "last_name": "User",
    "items": [{
      "item_id": "SKU-001",
      "item_name": "Test Product",
      "price": 99.99,
      "quantity": 1
    }]
  }'

You should get back a 200 response with {“success”:true}. If you get a 404, the path /data isn’t being claimed by your custom client. If you get a 500, the client template has a runtime error, so check the GTM Server logs.

What are common Shopify server side tracking mistakes?

The most common Shopify server side tracking mistakes are: missing the Custom Pixel event_id (breaks Meta CAPI deduplication), forgetting to map the items array (kills product-level reporting), using a non-first-party subdomain (Safari blocks the cookies), and sending hashed data from the Custom Pixel instead of the server (causes double-hashing).

Mistake 1: No event_id for deduplication

If you don’t send event_id with your Meta CAPI events, Meta can’t deduplicate them against your browser Pixel events. The result is double-counted conversions in Meta Ads Manager, inflated ROAS metrics, and an algorithm trained on bad data. Always include event_id, and use the same value across browser Pixel and server CAPI for any given event.

Mistake 2: Forgetting the items array

Many setups send the purchase event with value and transaction_id but skip the items array. This breaks product-level reporting in Google Ads (you can’t see which SKUs drove conversions), Meta dynamic ads (no product-level signal for retargeting), and any vendor-specific dashboard you might add later. Always include items with item_id, item_name, price, and quantity at minimum.

Mistake 3: Using gtm-server.com instead of a custom subdomain

If your server container endpoint is xyz123.gtm-server.com, Safari and Firefox treat it as a third-party origin and block the cookies that the Meta Pixel and GA4 need for session continuity. Always use a subdomain of your store’s primary domain (sgtm.yourdomain.com). This makes the requests first-party and preserves cookie context.

Mistake 4: Double-hashing user data

Some tutorials tell you to hash email and phone in the Custom Pixel before sending to the server. Don’t. The GTM Server tags for Meta CAPI and Google Enhanced Conversions expect raw data and handle hashing themselves with platform-specific normalization. If you hash in the pixel, the server will hash again, breaking the match against Meta’s and Google’s user databases.

Mistake 5: Not enabling Enhanced Conversions

Google Ads server-side tracking without Enhanced Conversions enabled is missing 5-15% of recoverable conversions. The Enhanced Conversions toggle in the Google Ads tag is buried in the advanced settings. Always turn it on, always map the email/phone/address fields, and always check the Diagnostics tab for the match rate after 72 hours.

How much does Shopify server side tracking cost?

Shopify server side tracking costs $20-200 per month for the hosting (Stape) plus $0-500 per month for managed setup if you outsource the configuration. For a typical Shopify store doing $50K-300K in monthly revenue, expect total monthly cost of $50-250 once configured, with one-time setup time of 4-8 hours of expert work.

Stape pricing breakdown

Stape charges by container request volume:

  • Free tier: 10,000 requests/month (good for testing, not for production)
  • Basic: $20/month for 100,000 requests (suits stores under $20K/month revenue)
  • Pro: $50/month for 500,000 requests (most $20K-100K/month stores)
  • Business: $200/month for 5M requests (high-traffic stores)

Each Custom Pixel event (page view, view item, add to cart, begin checkout, purchase) counts as one request. A store doing 30,000 sessions/month with 5 events per session will use roughly 150,000 requests, putting it in the Pro tier.

Google Cloud Run alternative

If you’d rather self-host the GTM server container on Google Cloud Run, you’ll pay $10-80/month in Cloud Run compute depending on traffic, plus $0-15/month for the load balancer and SSL. Setup is more complex (you’re provisioning the Cloud Run service yourself), but the long-term cost is lower for high-traffic stores and you get more control. For most clients we manage with $50K+/month ad spend, Cloud Run is the better economic choice once monthly request volume crosses 2M.

Managed setup cost

If you outsource the setup to an agency, expect $500-2,500 one-time depending on complexity. The variance comes from how many destinations you need (Google Ads + Meta only is cheaper than Google + Meta + TikTok + Pinterest + Klaviyo + Snapchat), whether you need custom event types beyond the standard five, and whether you need a privacy/consent layer built in (Usercentrics, Cookiebot, or custom consent mode). Our standard Shopify server side tracking setup for managed PPC clients runs $1,200 one-time when bundled with monthly campaign management, or $2,400 standalone.

Why choose Hustle Marketers for Shopify server side tracking setup?

We’ve configured Shopify server side tracking across Shopify, Shopify Plus, BigCommerce, Magento, and WooCommerce stores since the iOS 14.5 disruption began in 2021. Founded by Ishant Sharma in 2013, Hustle Marketers has driven over $780M in trackable client revenue across 2500+ brands, with Google Partner and Meta Business Partner status, 591+ Upwork reviews at 99% job success, and 6x Clutch Global Awards in 2026.

Our Shopify server-side work includes the conversion data infrastructure behind Drought Secret’s 9+ ROAS skincare campaign, a UK hair brand at 15.25x ROAS, a pet accessories brand at $346K revenue and 5.12x ROAS, ArmorGarage’s 15x ROAS PMax account, and P-REX Hobby’s 9x ROAS hobby store. If you’re running Shopify Ads without server-side tracking or you’ve installed an app-based solution and are still seeing under-reporting, we offer a free 30-minute tracking audit. Send us your Shopify admin access and we’ll come back with a prioritized fix list within 5 business days.

Conclusion

Shopify server side tracking is the most important data infrastructure decision you’ll make for your store in 2026, and the setup is no longer a black art. The Custom Pixel code above, paired with a Stape-hosted GTM server container and the tag configurations in this guide, gives you Meta CAPI, GA4, and Google Ads Enhanced Conversions all firing accurately from a single source of truth. The recovery on Meta-reported conversions typically lands between 25 and 45% within two weeks, which is enough to make every ROAS-targeted campaign meaningfully more efficient. Pair the server-side stack with a properly structured Performance Max asset group setup and clean break-even ROAS targeting, and the compounding effect on profit is meaningful. Copy the code, follow the four-step setup, run the test sequence, and you’ll have a working server-side stack by end of day.

Frequently Asked Questions

Is Shopify server side tracking the same as server-side tagging?

Yes. The terms are used interchangeably. Both refer to sending event data through a server you control (typically a GTM server container) instead of directly from the browser.

Do I need Shopify Plus to set up server side tracking?

No. Both standard Shopify and Shopify Plus support Custom Pixels, which is the integration point for server-side tracking. Plus stores get additional checkout customization options but the tracking setup is the same.

Will server side tracking break my existing Meta Pixel?

No, as long as you use event_id for deduplication. You can run browser Pixel and server CAPI in parallel; Meta deduplicates events with matching event_name and event_id automatically.

How long does Shopify server side tracking take to set up?

60-90 minutes for an experienced GTM Server practitioner. First-time setup typically takes 4-8 hours including testing across GA4, Meta CAPI, and Google Ads Enhanced Conversions.

Does Shopify server side tracking work with the Shopify Google & YouTube app?

It can, but only if you disable the app’s automatic Google Ads conversion firing to avoid double-counting. We typically remove the app and rely entirely on server-side tracking for cleaner attribution.

What happens to my old conversion tracking when I switch to server side?

Run both in parallel for 14 days, use event_id deduplication, then disable the client-side pixels. This validates the server-side data before you cut over completely.

Can I do Shopify server side tracking without GTM?

Yes, using direct Measurement Protocol calls and CAPI API calls. Less flexible than GTM Server, but feasible for technical teams who want full control without GTM as a middleware layer.

Does Shopify server side tracking help with iOS 14.5 attribution?

Yes. Server side tracking recovers 25-45% of iOS conversions that the browser-side Meta Pixel misses due to ATT opt-outs, because the server-to-server CAPI connection isn’t subject to browser ATT restrictions.

Do I need to hash customer data before sending to my server container?

No. Send raw email, phone, name, and address from the Shopify Custom Pixel to the server. GTM Server tags for Meta CAPI and Google Enhanced Conversions hash with platform-specific normalization.

Will Shopify server side tracking work with the new Checkout Extensibility?

Yes. Custom Pixels are part of Checkout Extensibility, so they continue working through Shopify’s 2024-2025 checkout migration without any breaking changes.

Why does my Shopify Custom Pixel return undefined for cookies?

The Shopify Custom Pixel runs in a Lax iframe sandbox where document.cookie is blocked. Use browser.cookie.get(name) instead, which is the sandbox-safe async API Shopify provides. The code in this guide uses it correctly.

How do I monitor Shopify server side tracking after launch?

Check Meta Events Manager event match quality (should be above 7.0), Google Ads Enhanced Conversions diagnostic match rate (should be above 60%), and GTM Server container logs weekly for any 4xx or 5xx errors.

What do I need to customize in the code before deploying?

Replace YOUR-SUBDOMAIN with your sGTM custom domain in the Shopify Custom Pixel (one line edit), then configure six dashboard values in your GTM Server tags: GA4 Measurement ID, Meta Pixel ID, Meta CAPI token, Google Ads Conversion ID, Conversion Label, and Test Event Code.

Can I copy this code without using Stape?

Yes. The Custom Pixel JavaScript and the GTM Server Client Template work with any server-side GTM hosting including Google Cloud Run, AWS, or self-hosted Docker. Only the sGTM endpoint URL changes; the code itself is hosting-agnostic.

Ishant

Ishant Sharma is the Founder and CEO of Hustle Marketers, a Google Partner digital marketing agency. With 12+ years of experience in Google Ads, Meta Ads, SEO, and e-commerce PPC, he has helped 2500+ brands generate $780M+ in trackable revenue. Upwork Top Rated Plus with 99% Job Success Score. Ishant Sharma is the digital marketing specialist, not the Indian cricketer of the same name.

I hope you enjoy reading this blog post. If you want my team to just do your marketing for you, click here.
Scroll to Top