Full page cache serves stale data
With Varnish or the built-in full page cache, the same HTML is served to many visitors. If cart or customer details are printed into the page, the dataLayer can show someone else's data or nothing at all.
This is for Magento Open Source and Adobe Commerce stores whose ad platforms don't match the orders in the admin. Magento gives you full control, but full page cache, a JavaScript-driven checkout, theme differences and extensions all affect what tracking sees. I build a dataLayer that works with caching, a GTM setup that reads it, and a server-side purchase feed from order data.
Proper Magento tracking means a GA4 ecommerce dataLayer from a maintained extension or a custom module, with customer and cart data loaded outside the cached page. GTM reads it for browser tags, the purchase fires once on the success page, and a server-side purchase from order events goes to Meta CAPI and other platforms with a shared event ID.
The events I set up on Magento, and where each one is sent.
With Varnish or the built-in full page cache, the same HTML is served to many visitors. If cart or customer details are printed into the page, the dataLayer can show someone else's data or nothing at all.
Magento Open Source ships only basic Google integrations. Adobe Commerce includes a Tag Manager module, but most stores still need an extension or custom module for a full GA4 ecommerce dataLayer.
Shipping and payment steps change without a full page load. Page-view triggers miss them, so begin_checkout, add_shipping_info and add_payment_info need events tied to the checkout's own steps.
Tracking extensions written for the Luma theme often don't work on Hyvä or a headless frontend, because the JavaScript they rely on isn't there. Add-to-cart and mini-cart events are usually the first to fail.
Customers who pay through an external payment page don't always return to the success page, so the browser purchase never fires even though the order is in Magento.
| Event | When it fires | Sent to |
|---|---|---|
view_item_list | Category or search results page loads | GA4 |
view_item / ViewContent | Product page loads | GA4, Meta Pixel + CAPI, TikTok |
add_to_cart / AddToCart | Product added, including AJAX add-to-cart | GA4, Meta Pixel + CAPI, TikTok |
begin_checkout / InitiateCheckout | Checkout opens | GA4, Meta Pixel + CAPI, TikTok |
add_shipping_info | Shipping step completed in checkout | GA4 |
add_payment_info | Payment method selected | GA4 |
purchase / Purchase | Checkout success page (first load only) | GA4, Google Ads, Meta Pixel, TikTok |
purchase (server) | Order placed or invoiced in Magento, sent to server-side GTM | Meta CAPI, GA4, TikTok Events API |
I review installed extensions, theme, caching setup and payment methods, and compare platform conversions with Magento orders.
Depending on your theme and team, I recommend a maintained extension or a small custom module, and agree it with your developers.
The dataLayer, GTM container, checkout events and server-side purchase feed are built and deployed to staging first.
I test with full page cache active, through each payment method and store view, and confirm each order is counted once.
After release I compare platform data with Magento for two weeks, then hand over the event map and notes for future upgrades.
Magento caches whole pages so they load fast. That's good for speed and bad for tracking code that prints the cart or logged-in customer into the page, because the cached copy is shared. The fix is to keep page-level data, such as the product on a product page, in the cached HTML, and load anything personal through Magento's private content (customer data sections) or a small AJAX call after the page loads.
I test this with caching switched on. Turning the cache off during testing hides exactly the problems that break tracking in production.
The success page is the only place the browser can report a purchase, and not every customer reaches it. A server-side purchase, sent when the order is placed or invoiced, fills that gap. In Magento this is usually an observer or a queue consumer that sends order data to server-side GTM without slowing checkout.
The server event carries the same event ID the browser would use, so Meta and other platforms keep one copy when both arrive. It also includes hashed email and phone, which improves match quality for Meta CAPI and Google Ads enhanced conversions.
Use GTM with a GA4 ecommerce dataLayer from a maintained extension or a custom module, rather than hard-coded tags. Adobe Commerce has a built-in Tag Manager module, but check that its dataLayer covers the GA4 events you need.
It can, if cart or customer data is printed into cached pages. Personal data should load through customer data sections or after the page loads. I always test tracking with the cache enabled.
Yes, but many Luma-based tracking extensions don't. I check that the extension supports Hyvä, or build the events for Hyvä's JavaScript, especially add-to-cart and the mini-cart.
Either through an extension that supports CAPI, or by sending order events to server-side GTM, which forwards them to Meta. I prefer server-side GTM because the same feed can also go to GA4, Google Ads and TikTok.
Yes. I usually write the dataLayer spec and GTM setup, and your developers deploy any module changes. I then test on staging and production before sign-off.
The step-by-step checklist I use to set up GA4 ecommerce tracking: events, data layer, GTM tags and testing, so product and revenue reports are accurate.
What server-side tracking really is, how server-side GTM works, what it fixes and what it does not, and a checklist to decide if your business needs it.

Meta merges Pixel and server events only when the event name and event ID match. Here is how to set that up correctly and prove it works.
Get a free audit of your tracking and ad account. Usually replies within 1–2 hours.