Start a Project
All guides

Pixels

Meta Pixel Setup for South African Shopify Stores.

Meta Pixel on a South African Shopify store has to survive iOS 17 tracking restrictions, POPIA consent, and Shopify's checkout domain split. This guide installs the Pixel via Shopify's native integration, adds the standard events Meta expects (ViewContent, AddToCart, Purchase) with ZAR values, and sets you up to pair with Conversions API so you recover the 30 to 45 percent of iOS signal Apple strips client-side.

Updated 15 April 2026 · 12 min read · Shopify · Joshua Kaplan

Prerequisites

  • A Meta Business Manager account with a Pixel created (ID is a 15 to 16 digit number)
  • Shopify Admin > Settings > Customer events access
  • The Facebook & Instagram (Meta) sales channel app installed, or a custom Pixel install plan
  • A POPIA consent banner wired to emit accept events
  • A test Meta account for Test Events

Step 1. Create the Pixel and grab the ID

In Meta Business Manager > Events Manager > Connect Data Sources > Web > Pixel. Name it after your store (e.g. "yourstore_za_pixel"). Copy the 15 to 16 digit Pixel ID. Add your domain and verify via DNS TXT record. Domain verification is required before you can fire events reliably on iOS.

Step 2. Install via the Meta Sales Channel (easiest)

Install the "Facebook & Instagram" app from the Shopify App Store. Under Settings > Data sharing, pick "Maximum" (client + CAPI). Paste your Pixel ID. Shopify then fires PageView, ViewContent, AddToCart, InitiateCheckout, and Purchase automatically. Note: "Maximum" enables both client-side and server-side — if you plan to add Conversions API separately, use "Enhanced" to avoid deduplication headaches.

Step 3. Manual install via Custom Pixel (more control)

If you want control over consent timing or event names, install via Settings > Customer events > Add custom pixel. Paste this. It mirrors Meta's stock behaviour but lets you gate on POPIA.

shopify-custom-pixel.js
const PIXEL_ID = 'YOUR_PIXEL_ID';

const loadFbq = () => {
  if (window.fbq) return;
  !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
  n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
  n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
  t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
  document,'script','https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', PIXEL_ID);
};

analytics.subscribe('page_viewed', () => { loadFbq(); fbq('track', 'PageView'); });

analytics.subscribe('product_viewed', (event) => {
  const p = event.data.productVariant;
  fbq('track', 'ViewContent', {
    content_ids: [p.sku],
    content_type: 'product',
    value: Number(p.price.amount),
    currency: p.price.currencyCode
  });
});

analytics.subscribe('product_added_to_cart', (event) => {
  const l = event.data.cartLine;
  fbq('track', 'AddToCart', {
    content_ids: [l.merchandise.sku],
    content_type: 'product',
    value: Number(l.cost.totalAmount.amount),
    currency: l.cost.totalAmount.currencyCode
  });
});

analytics.subscribe('checkout_completed', (event) => {
  const c = event.data.checkout;
  fbq('track', 'Purchase', {
    content_ids: c.lineItems.map((li) => li.variant.sku),
    content_type: 'product',
    value: Number(c.totalPrice.amount),
    currency: c.totalPrice.currencyCode,
    num_items: c.lineItems.length
  });
});

Step 4. Gate the Pixel behind POPIA consent

Do not load fbevents.js until the visitor grants marketing consent. Meta's own Consent Mode implementation is thin. The simplest POPIA-safe pattern is to skip loadFbq() until consent lands.

assets/meta-consent-gate.js
window.__metaConsent = false;

document.addEventListener('popia:consent:changed', (e) => {
  window.__metaConsent = e.detail.categories.marketing === true;
  if (window.__metaConsent && !window.fbq) {
    // Call loadFbq() defined above to insert the Pixel
    loadFbq();
    fbq('track', 'PageView');
  }
});

Step 5. Set the ZAR currency and user properties

All value fields must match Shopify's currency code ("ZAR"). If you send value: 1299 without currency, Meta assumes USD, reporting R1,299 as a roughly R24,000 conversion and skewing your ROAS. Always include currency: "ZAR". Also pass fbq user data (hashed email, hashed phone) via Advanced Matching where possible.

advanced matching example
fbq('init', PIXEL_ID, {
  em: hashedEmail,     // SHA-256 lowercase
  ph: hashedPhone,     // SHA-256 E.164 without +
  ct: 'cape town',     // lowercase
  st: 'wc',            // province ISO, e.g. WC for Western Cape
  country: 'za',
  zp: '7441'
});

Step 6. Verify with Meta Pixel Helper and Test Events

Install the Meta Pixel Helper Chrome extension. Walk a R1 test order. Open Events Manager > Test Events and paste your test browser fingerprint. Confirm Purchase fires once, value matches, currency is ZAR. If you see "value: 1" but currency USD, fix before going live.

Step 7. Enable Aggregated Event Measurement and prioritise Purchase

Meta limits verified domains to eight priority events under AEM (iOS ATT workaround). In Events Manager > Aggregated Event Measurement, drag Purchase to position 1, InitiateCheckout to 2, AddToCart to 3, ViewContent to 4. Anything below 8 is ignored on iOS.

Step 8. Plan the CAPI handoff

Client-side Pixel will miss 30 to 45 percent of SA iOS purchases due to ATT and Safari ITP. Pair with the server-side Conversions API (see the CAPI guide) and dedupe via event_id. Without CAPI, you cannot run Advantage+ shopping campaigns profitably.

SA gotchas

  • Shopify checkout on Basic / Shopify / Advanced runs on checkout.shopify.com, a different domain. Meta deduplicates by Pixel ID + event_id + domain, so make sure event_id is the same for client and CAPI.
  • iOS 17 Safari private browsing blocks fbevents.js entirely. Expect up to 30 percent iOS signal loss client-side — CAPI is not optional for SA stores serving iPhone users.
  • Apple Private Relay masks the IP address, so Meta's fuzzy matching by IP breaks. Advanced Matching (hashed email, phone) recovers most of this.
  • Firing Purchase from both the Meta Sales Channel (server-side) and theme.liquid (client-side) without matching event_id doubles reported revenue in Ads Manager.
  • ZAR currency code must be uppercase "ZAR". Lowercase or "R" is rejected silently and values roll up under "unknown currency".

Frequently asked questions

Will Meta Pixel still work after iOS 17?

Yes, but with reduced accuracy. iOS 17 ATT and Safari ITP strip third-party cookies and cap first-party cookies at 7 days. Run Meta Pixel + Conversions API together to recover most of the lost signal.

Is Meta Pixel POPIA compliant?

Only with marketing-category consent. Meta acts as an independent controller and requires you to sign its Business Tools Terms. Disclose the cross-border transfer to the US in your privacy policy.

Why does my Shopify revenue not match Meta Ads Manager revenue?

Three reasons: signal loss from iOS / consent, attribution window differences (Meta uses 7-day click by default), and currency mismatches. Align both to ZAR and check for duplicate purchase events.

Can I install Meta Pixel without the Facebook sales channel app?

Yes. Use Custom Pixels under Settings > Customer events. You lose the Catalog + Shops integration but gain full control over consent ordering.