GA4 e-commerce end to end through your server container
Once GA4 runs through your server container, e-commerce is mostly a web container job. Your site pushes each shop action to the dataLayer, one GA4 event tag sends it to https://sgtm.example.com, and the server-side GA4 tag you already have forwards it with all the products inside. In this lesson you set up the events, the tag and the trigger, protect the purchase from being counted twice and check the data on the way.
Intermediate 13 min read
What you will learn
- Know which recommended e-commerce events GA4 expects and which parameters each one needs.
- Push clean e-commerce data to the dataLayer, clearing the previous object first.
- Send every e-commerce event with one GA4 event tag and one Custom Event trigger.
- Fire
purchaseonce per order and verify it in server preview, DebugView and the Monetization reports.
01 The recommended e-commerce events
GA4 fills its e-commerce reports only from events with the recommended names. Custom names such as productView or checkout_step_2 are stored, but they never show up as product views or revenue. Use these names exactly, in lowercase:
-
view_item_listandselect_item: a visitor sees a product list (category page, search results) and clicks a product in it. -
view_item: a product detail page. -
add_to_cart,remove_from_cartandview_cart: cart actions. -
begin_checkout,add_shipping_infoandadd_payment_info: the checkout steps. -
purchase: the completed order. -
refund: a full or partial refund, usually sent from your backend rather than the browser.
Every event carries an items array, and each item needs at least item_id or item_name. When an event has a value, it also needs currency (for example EUR), otherwise GA4 cannot turn it into revenue. purchase and refund also need a transaction_id.
02 Push the data to the dataLayer
Each push has two parts: first ecommerce: null, then the event with a fresh ecommerce object. The dataLayer merges objects, so without the reset the items from the previous event can leak into the next one, for example a product from view_item ending up in add_to_cart.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'EUR',
value: 129.90,
items: [{ item_id: 'SKU-1', item_name: 'Shoes', item_brand: 'Acme', item_category: 'Footwear', price: 129.90, quantity: 1 }]
}
});window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'add_to_cart',
ecommerce: {
currency: 'EUR',
value: 129.90,
items: [{ item_id: 'SKU-1', item_name: 'Shoes', price: 129.90, quantity: 1 }]
}
});The purchase push adds transaction_id and the full order value. Render it on the thank-you page with the real order data from your shop.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'T-10293',
value: 129.90,
currency: 'EUR',
items: [{ item_id: 'SKU-1', item_name: 'Shoes', price: 129.90, quantity: 1 }]
}
});03 One GA4 event tag for all e-commerce events
In the web container you do not need a tag per event. One Google Analytics: GA4 Event tag can read the event name and the e-commerce data from the dataLayer and send whichever event was pushed.
- 1 Create a trigger of type Custom Event. As the event name enter
^(view_item_list|select_item|view_item|add_to_cart|remove_from_cart|view_cart|begin_checkout|add_shipping_info|add_payment_info|purchase)$and tick Use regex matching. - 2 Create a tag of type Google Analytics: GA4 Event. Enter your measurement ID
G-XXXXXXXXXX(or select your Google tag) and set Event Name to the built-in variable{{Event}}. - 3 Under More Settings open Ecommerce, tick Send Ecommerce data and choose Data Layer as the data source.
- 4 Attach the Custom Event trigger, name the tag (for example
GA4 - ecommerce) and save.
The tag goes out through the same Google tag that already has server_container_url set to https://sgtm.example.com from lesson 3, so every e-commerce event reaches your server container first.
04 What changes in the server container
Nothing. The GA4 client claims the e-commerce hits like any other GA4 event, and the items travel inside the hit. The GA4 tag from lesson 4, triggered on Client Name equals GA4, forwards them to Google Analytics together with value, currency and transaction_id.
The server container is still the right place for extra destinations. A Meta Conversions API tag can read the same purchase event, so the order is sent to Meta from the same data (lesson 7 shows how to share an event_id for deduplication). The Google Ads conversion tag in the next lesson reads it too.
05 Count every purchase once
Google Analytics deduplicates purchase events with the same transaction_id for data from web streams. Treat that as a safety net, not as the fix. The common source of duplicates is the thank-you page: a visitor refreshes it, comes back through the browser history or opens the confirmation link from the email, and the purchase push runs again.
- Render the purchase push only on the first view of the thank-you page. Keep a flag on the order in your shop (for example
tracked_at) and skip the push when it is set. - Always send a real, unique
transaction_id. Never an empty string: GA4 treats all purchases withtransaction_idset to an empty string as one transaction. - Do not put personal data such as the email address in
transaction_id. Use the order number. - Send refunds with the
transaction_idof the original order, so GA4 can match them.
06 Verify the data end to end
Test in three places, from the server outwards. Open Preview in both containers and go through the shop: view a product, add it to the cart, check out and place a test order.
- Web preview: the
GA4 - ecommercetag fires on each e-commerce event and not on others. - Server preview: the request goes to
sgtm.example.com, and in the event data you seeitemswithitem_id,priceandquantity, plusvalueandcurrency. - Server preview: the GA4 tag is listed under Tags Fired for
purchase. - GA4 DebugView: the events arrive with their parameters and items.
- GA4 Monetization reports: purchases and revenue appear. These reports can take 24 to 48 hours to fill, so do not judge them on the same day.
Frequently asked questions
Do I need a separate server tag for e-commerce events?
No. The GA4 tag in the server container forwards every event the GA4 client claims, including the items. E-commerce only needs work in the dataLayer and the web container.
Why do I see purchases but no revenue in GA4?
Usually currency is missing, or value is sent as a string. Check the event data in server preview: value must be a number and currency a three-letter code such as EUR.
Does GA4 remove duplicate purchases on its own?
For web streams it deduplicates purchase events with the same transaction_id. It still pays to fire the purchase once, because other tools that read the same event, such as ad platforms, may count a repeat as a second conversion.
Ready to put it into practice?
Deploy a server GTM container on your own domain in a few minutes. The Free plan needs no card.
Create a free account