Shopify Pixels in Customer Events: Fix Missing Tracking

Quick fix: On Shopify, checkout and Thank you page tracking now runs through Settings > Customer events, as an app pixel or a custom pixel inside a sandbox. If events are missing, confirm the pixel shows Connected and that its customer privacy permission is not blocking it. If events are doubled, remove the old copy of the same pixel from your theme code or the second app sending the same event.
Shopify's checkout used to accept almost any script you pasted into checkout.liquid or the "Additional scripts" box. That world is gone. Pixels now run in a sandbox, they receive data through Shopify's customer events, and many old debugging habits stop working. Browser extensions report "no pixel found," purchase events vanish after an upgrade, or the same purchase shows up twice in Ads Manager.
This guide explains how Shopify's pixel system works today, why it confuses ordinary pixel checkers, and how to fix the most common missing and duplicate event problems.
How Shopify runs pixels after checkout extensibility
All pixels are managed in one place: Settings > Customer events in your Shopify admin. There are two kinds.
| App pixels | Custom pixels | |
|---|---|---|
| Added by | Installing a marketing or data app (for example a sales channel for an ad platform) | You or a developer, pasting JavaScript into the pixel editor |
| Sandbox | Strict: runs in a web worker with no access to the page | Lax: runs in an iframe with the sandbox attribute (allow-scripts and allow-forms) |
| Configured by | The app's settings screen | The code you write, plus the Customer privacy settings on the pixel |
| Supported by Shopify | Through the app developer | No. Shopify states that custom pixels are unsupported and your responsibility |
Both kinds load automatically on the storefront, checkout, Thank you page and Order status page. Neither can render UI such as banners or modals, and neither can scrape the page DOM to detect clicks, scrolls or form contents.
The old methods are retired. According to Shopify's developer documentation, checkout.liquid and additional scripts were sunset for the Thank you and Order status pages on August 28, 2025. Script tags on those pages were sunset for Plus stores on the same date and for non-Plus stores on August 26, 2026. If your purchase tracking lived in any of those places, it has stopped, and it needs to move to Customer events.
Why browser pixel checkers may not see a custom pixel
A custom pixel does not run in your storefront page. It runs inside a sandboxed iframe that cannot access the top frame. That has a few visible side effects.
- The pixel's global is not on the main page. If your custom pixel loads the Meta base code,
fbqexists inside the sandbox iframe, not on the storefront'swindow. A tool that looks forfbqor a script tag in the main document may report that no pixel is installed. - The network requests still happen. The requests to the ad platform leave the browser from the iframe, so they appear in the DevTools Network tab like any other request. This is the most reliable outside view.
- Console logs are scoped to the iframe. In Chrome DevTools, choose the sandbox iframe in the Console's context dropdown to see your pixel's logs and errors. Shopify's testing guide recommends exactly this.
- The page URL can be wrong. In the lax sandbox, properties such as
window.locationreturn the sandbox URL, not the storefront URL. Shopify recommends reading the real URL from the event context, for exampleevent.context.document.location.hrefonpage_viewed.
App pixels are even more isolated. They run in a web worker, so there is nothing in the page to inspect at all. Use the Network tab and the ad platform's own test tools instead. For a full walkthrough of reading those requests, see how to check which pixels a website fires.
Subscribing to Shopify's standard events
Inside a custom pixel, you do not listen for button clicks. You subscribe to customer events that Shopify publishes. The standard events are:
page_viewed,product_viewed,collection_viewed,search_submittedproduct_added_to_cart,product_removed_from_cart,cart_viewedcheckout_started,checkout_contact_info_submitted,checkout_address_info_submitted,checkout_shipping_info_submitted,payment_info_submitted,checkout_completedalert_displayed,ui_extension_errored
You can also subscribe to groups: all_events, all_standard_events, all_custom_events and all_dom_events. Shopify notes that the contents of these groups can change over time.
Here is a minimal custom pixel that maps a Shopify purchase to a Meta Purchase event. It assumes the Meta base code is loaded earlier in the same custom pixel.
analytics.subscribe('checkout_completed', (event) => {
const checkout = event.data.checkout;
fbq('track', 'Purchase', {
value: checkout.totalPrice?.amount,
currency: checkout.totalPrice?.currencyCode
}, { eventID: event.id });
});
Read values from event.data, never from the page. For checkout_completed, checkout.order.id holds the order ID (it is null on every other checkout event) and checkout.totalPrice is a money object with amount and currencyCode.
Missing events: causes from most to least likely
1. The pixel is saved but not connected
Saving a custom pixel does not activate it. In Customer events, open the custom pixels list and check the Status column. Anything under Disconnected pixels sends nothing until you click Connect and confirm.
2. Customer privacy settings are blocking it
Each custom pixel has a Customer privacy section with a Permission setting. If it is set to Required, the pixel only runs for visitors who have given consent for the selected purposes. If your cookie banner never records consent, or you are testing in a region where consent is required and you clicked "reject," the pixel stays silent. Test once with consent accepted before you assume the code is broken.
3. Your code reads the DOM or the top window
Old pixel snippets often scrape the order total from the Thank you page or read document.title of the storefront. In the sandbox those reads return nothing useful, or values from the iframe. Rewrite them to use the event payload.
4. You expect checkout_completed in the wrong place
checkout_completed fires once per checkout, typically on the Thank you page. If the store uses post-purchase upsells, it fires on the first upsell offer page instead and is not triggered again on the Thank you page. If that page fails to load, the event is not triggered at all. A pixel that only expects the event on the Thank you page will look broken on stores with upsells.
5. Tracking still lives in retired locations
If purchases stopped around a checkout upgrade, look for code that still sits in Additional scripts or checkout.liquid. It is not running anymore. Move the logic into a custom pixel or install the platform's app.
6. The test environment is unsupported
Shopify's pixel testing helper is not compatible with headless storefronts, and Shopify recommends turning off private mode on password-protected stores while you test.
Duplicate events: where the second copy comes from
Duplicates on Shopify almost always mean the same platform is installed twice.
- App pixel plus custom pixel. A merchant installs the ad platform's sales channel app, then a developer adds a custom pixel for the same platform. Both send Purchase. Pick one.
- Theme code plus Customer events. Shopify explicitly tells you to remove existing pixel code before adding a custom pixel, and to check
theme.liquid,checkout.liquid(Plus only) and the Additional scripts box. A base code left intheme.liquidwill keep firing PageView and add-to-cart events on the storefront. - Built-in Google integration plus GTM. Shopify warns that adding Google Analytics through Tag Manager on top of its built-in Google integration can result in duplicate tracking.
- Overlapping subscriptions. A pixel that subscribes to
all_eventsand forwards everything, and also subscribes tocheckout_completedseparately, can send the purchase twice. - Browser and server events without a shared ID. If an app sends server events and your custom pixel sends the same browser event without a matching event ID, the platform cannot deduplicate them.
For platform-specific cleanup, see fixing duplicate Meta Pixel events and GA4 purchase event duplicates.
Running Google Tag Manager inside a custom pixel
Shopify's own GTM tutorial loads the GTM container inside a custom pixel and pushes customer events into the data layer:
analytics.subscribe('product_viewed', (event) => {
window.dataLayer.push({
event: 'product_viewed',
product_title: event.data?.productVariant?.title
});
});
Two caveats from that tutorial matter for debugging. First, GTM triggers must listen for these custom events, because GTM's own click and form triggers cannot see the storefront from inside the sandbox. Second, Shopify notes that Google Tag Assistant's Troubleshoot tag feature is not compatible with custom pixels. If you rely on GTM preview, read why GTM preview mode stops working and verify with the Network tab and GA4 DebugView instead.
If your theme pushes its own events with dataLayer.push, Shopify recommends replacing those calls with Shopify.analytics.publish() so your pixel can subscribe to them as custom events.
How to verify the fix
- Go to Settings > Customer events, click your custom pixel and click Test. Shopify opens your store with its testing helper.
- If prompted, accept cookie consent or click Give consent to continue test.
- Browse to trigger events. In Events received, a green dot means your subscription callback ran; a red dot means the callback threw an error.
- Open DevTools, filter the Network tab by the platform's domain and confirm one request per event.
- Place a test order to trigger
checkout_completed, ideally on a development store. - Confirm the event in the platform's test tool, such as Meta's Test Events or GA4 DebugView.
Keep the helper's limits in mind (see Shopify's custom pixel testing guide): you can test only one custom pixel at a time, you cannot edit the pixel while the test runs, and the event log clears each time you navigate to a new page.
FAQ
Should I use an app pixel or a custom pixel?
Use the platform's app when one exists and covers your events. It runs in the stricter sandbox, is maintained by the app developer, and usually handles server events and deduplication for you. Use a custom pixel only for platforms without an app or for events the app does not send.
Why does my custom pixel report the wrong page URL?
In the lax sandbox, window.location points at the sandbox iframe. Read the storefront URL from event.context.document.location.href and pass it to your platform where its API allows a page URL.
Can a custom pixel track button clicks on my theme?
Not by scraping the DOM. Publish a custom event from the theme with Shopify.analytics.publish() and subscribe to it in the pixel, or use the DOM events Shopify provides through all_dom_events.
Do I still need theme.liquid pixel code for storefront pages?
No. Pixels in Customer events load on the storefront as well as checkout. Keeping a second copy in the theme is one of the most common sources of duplicate events.

