How AxiTrace reads the GA4 ecommerce dataLayer your shop already publishes, what the AI shop check looks for, the Workspace setting that controls it, and the rules that keep every order counted once.

GA4 dataLayer Auto-Tracking

If your shop already sends GA4 ecommerce events, it already writes every product view, add to cart and order into a list called the dataLayer. AxiTrace can read that same list and turn it into AxiTrace events, so you do not have to add tracking calls by hand. This page explains exactly what is read, how the automatic shop check decides whether to switch it on, and how double counting is prevented.

1. What a dataLayer is

A dataLayer is a plain JavaScript list, usually window.dataLayer, where your shop writes what a visitor does: a product was viewed, something was added to the cart, an order was placed. Google Tag Manager and GA4 read from it. Each entry is called a push.

If GA4 ecommerce is implemented properly on your shop, you already have one. A GA4 purchase push looks like this:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });  // clears the previous ecommerce object
window.dataLayer.push({
  event: 'purchase',
  ecommerce: {
    transaction_id: 'ORD-1041',
    value: 129.90,
    tax: 24.29,
    shipping: 9.90,
    currency: 'EUR',
    coupon: 'SPRING10',
    items: [
      { item_id: 'SKU-17', item_name: 'Oak Side Table', price: 59.95, quantity: 2 },
      { item_id: 'SKU-42', item_name: 'Linen Cushion', price: 10.00, quantity: 1 }
    ]
  }
});

Not sure whether your shop has one? The dataLayer check on the Google Tag Manager page prints it in your browser console in 30 seconds, and the shop check below looks for it automatically.

2. How AxiTrace reads it

When dataLayer auto-tracking is on, the AxiTrace SDK on your pages observes the dataLayer. It first reads every entry that is already in the list, then watches every new push. A push made before the SDK loaded is therefore not lost. These eleven GA4 events are translated:

GA4 dataLayer event AxiTrace event What is taken from the push
view_item_listview_item_listitem_list_id, item_list_name, items
select_itemselect_itemitem_list_id, item_list_name, the selected item
view_itemproduct.viewThe first item: id, name, category, brand, price, quantity, currency
add_to_cartproduct.addToCartThe first item, as for view_item
remove_from_cartremove_from_cartItems and value (derived from the items when missing)
begin_checkoutbegin_checkoutItems, value, currency, coupon
add_shipping_infoadd_shipping_infoItems, shipping_tier, coupon
add_payment_infoadd_payment_infoItems, payment_type, coupon
purchasepurchaseSee Purchases
searchsearchsearch_term
generate_leadform.submitValue, currency, and the items as the lead's products (see Leads)

Every event made this way carries the marker source: "ga4_datalayer", so AxiTrace can always tell an event read from your dataLayer apart from one your shop sent in another way.

Shapes that are understood

  • Google Tag Manager pushes: dataLayer.push({ event: 'add_to_cart', ecommerce: {...} }).
  • gtag() calls: gtag('event', 'add_to_cart', {...}), with the fields at the top level.
  • Split pushes: an ecommerce object pushed on its own, followed within 2 seconds by an event push without one. The stored object is used for that event. { ecommerce: null } clears it.
  • Universal Analytics enhanced ecommerce: the older ecommerce.purchase (actionField + products), ecommerce.checkout, ecommerce.add and ecommerce.detail blocks are translated to purchase, begin_checkout, add_to_cart and view_item.
  • Universal Analytics classic ecommerce: the flat transactionId, transactionTotal, transactionTax, transactionShipping and transactionProducts keys Google Tag Manager's original Google Analytics tag read on the order confirmation page, with or without an event. They are read as a purchase; see Classic ecommerce transactions.
  • Products without an id: when an item has no item_id, its item_name (or item_variant) is used as the SKU, so the product event is not rejected.

Customer details from user_data

Ad platforms match a conversion to a person more often when it carries the buyer's email, phone and address. If your pushes include GA4 user_data, AxiTrace reads it from three places: the top level of the push, inside the ecommerce object, and a gtag('set', 'user_data', {...}) call, which is remembered and applied to every later event on the page.

window.dataLayer.push({
  event: 'purchase',
  user_data: {
    email: 'buyer@example.com',
    phone_number: '+48600100200',
    address: {
      first_name: 'Anna',
      last_name: 'Nowak',
      city: 'Krakow',
      region: 'Lesser Poland',
      postal_code: '30-001',
      country: 'PL'
    }
  },
  ecommerce: { transaction_id: 'ORD-1041', value: 129.90, currency: 'EUR', items: [ /* ... */ ] }
});
GA4 user_data key Used by AxiTrace as
email or email_addressEmail, and the visitor is identified by it when no user id is known yet
phone_numberPhone
address.first_name, address.last_nameFirst name, last name
address.city, address.regionCity, state or region
address.postal_code, address.countryPostcode, country

address may be an object or a list; for a list the first entry is used. AxiTrace needs the plain values and hashes them itself before anything is sent to an ad platform. That is why an email or phone that is already a 64-character hash is dropped, and every sha256_* key (sha256_email_address, sha256_phone_number and so on) is ignored: hashing a hash would make it match no one.

What is not read

  • view_cart and refund. They are ignored in silence, because AxiTrace has no endpoint for them yet.
  • Any other event name, including GTM's own entries (gtm.js, gtm.dom, gtm.load) and Universal Analytics actions other than the four above (impressions, click, remove, refund, promoView).
  • A gtag event whose send_to names only Google Ads (AW-) or Floodlight (DC-) targets. That is a conversion ping for another Google product, not a GA4 event. When send_to also names a GA4 property (G-), it is read.
  • sha256_* keys and already hashed email or phone values, as explained above.
  • A dataLayer that is not a list. If window.dataLayer is some other kind of object, the SDK leaves it untouched, logs one warning in the console and auto-tracking stays off on that page.
  • A dataLayer replaced late. If the page throws away its dataLayer and creates a new list, the SDK follows the new list for 20 seconds after it started. A list created by a script that runs later than that is never seen.
  • Pages the SDK is not on. A hosted checkout on another domain (a payment provider, a marketplace checkout) and content inside iframes are invisible to it.

If the dataLayer does not exist yet when the SDK starts, the SDK creates an empty one, exactly as the Google Tag Manager snippet does, so pushes made afterwards are still read.

3. Purchases

The purchase is the event that matters most, so it has the most rules.

Field How it is used
transaction_id Becomes the AxiTrace order id and the key for deduplication. Always send your real order number.
value The order value. GA4 has no separate revenue field, so value is also stored as the order revenue. An explicit revenue (Universal Analytics carries one) wins.
currency Stored in upper case, for example EUR. When a push carries a value but no currency, the default currency of your workspace (Workspace settings) is used, never an assumed US dollar.
tax, shipping, coupon Stored as sent.
items The products of the order. The product count is the number of units: two of one product and three of another count as five, and an item without a quantity counts as one.

A reloaded confirmation page is not a second sale

Purchases are deduplicated on transaction_id, per workspace, within 30 days. A buyer who reloads the order confirmation page, opens it again from the browser history a week later, or a tag that fires twice, produces one order in AxiTrace, not two. Two different shops that both happen to have an order number 1041 never affect each other.

Missing and placeholder order ids

A purchase without a transaction_id is still recorded, because it is still revenue, but it cannot be deduplicated: a reload counts it twice. The SDK says so in the browser console. The same applies when the id is a value a tag manager writes when a variable did not resolve. These are treated exactly like a missing id (compared without case and surrounding spaces):

undefined, null, (not set), nan, false, -, and an empty value.

Treating them as real ids would be worse than having none: every order of the shop would share the same id and all of them after the first would be dropped as repeats.

Classic ecommerce transactions

Many custom shops set up Google Tag Manager years ago with the original Google Analytics "standard ecommerce" format and still point their GA4, Google Ads, Meta and Microsoft purchase tags at it. The order is a flat object on the confirmation page, usually placed above the Google Tag Manager snippet:

window.dataLayer = [{
  transactionId: '100234',
  transactionAffiliation: 'My Shop',
  transactionTotal: '1,234.56',
  transactionTax: '205.76',
  transactionShipping: '0.00',
  transactionProducts: [
    { sku: 'FOX-10', name: 'Battery system', category: 'Batteries', price: '1,228.56', quantity: '1' },
    { sku: 'CR-1', name: 'Ceiling rose', category: 'Accessories', price: '3.00', quantity: '2' }
  ]
}];

AxiTrace reads it as it is, with no Google Tag Manager variables to create:

Classic key Read as
transactionIdThe order id (transaction_id), with the same deduplication as a GA4 purchase
transactionTotalThe order value and revenue. When it is missing, the sum of price times quantity of the products
transactionTax, transactionShippingTax and shipping
transactionProductsThe items: sku as the item id, name, category, price, quantity
transactionAffiliationNot used
  • Currency. The classic format has no currency field, so the default currency of your workspace is used. Make sure it is set correctly in Workspace settings. If your object does carry one as transactionCurrency, currencyCode or currency, that one wins.
  • Numbers written as text are understood: "38.26", "1,234.56", "£1,234.50" and "1.234,56" are all read correctly. A value that cannot be read is left out rather than guessed.
  • An entry is a transaction when it has a transactionId or a transactionTotal, and a total or at least one product. A transactionId on its own is ignored.
  • Later Google Tag Manager events (gtm.dom, gtm.load, a consent banner event) do not repeat the purchase: each dataLayer entry is read once.

One order per confirmation page

A shop that added GA4 later sometimes describes the same order twice on one page: once in the classic keys and once in a GA4 or Universal Analytics enhanced purchase push, sometimes even with different ids. AxiTrace counts the first one it reads and skips the other on that page. When a single push carries both an ecommerce purchase block and the classic keys, the block is read. A reload of the page is still deduplicated on the order id, because both formats use the same key.

4. The shop check

On the Manual connection page of the AxiTrace admin panel, an AI shop check looks for a GA4 ecommerce dataLayer on your shop and sets auto-tracking for you. It starts by itself the first time you open that page, when your workspace already knows your shop address. Otherwise you enter the address and click Check my shop. It usually takes under a minute, and you can leave the page while it runs.

What is fetched

  • Your home page.
  • Your /sitemap.xml, to find product pages.
  • Up to two product pages and one cart or checkout page, chosen from links on your home page and your sitemap.
  • Your public Google Tag Manager container (the same gtm.js file every visitor's browser downloads), when your pages load one.

Only pages on your shop's own domain and its subdomains are read. The check reads the HTML of those pages and the dataLayer pushes written in them; it does not run your scripts and does not download other script files. It sends an honest user agent, AxiTraceShopCheck/1.0, with a link back to this page.

What the check never does

It never logs in, never fills in forms, never places an order and never clicks through a cookie banner. If bot protection stops it, it reports that and stops. It does not try to get around it.

How the result is decided

A program first extracts evidence from what was fetched: dataLayer pushes and gtag calls with GA4 ecommerce event names, GA4 event tags in your tag container, the shop platform, a cookie banner that holds back Google Tag Manager, and any existing AxiTrace tracking. An AI model then judges that evidence (it receives the extracted evidence, never your raw pages), and a fixed set of rules checks the answer. The rules can only make the answer more careful: auto-tracking is switched on only when there is hard evidence, meaning a GA4 ecommerce push or gtag call in your pages, a GA4 ecommerce event tag in your tag container, or classic ecommerce transaction keys: in your page code, or as Data Layer Variables (transactionId with transactionTotal or transactionProducts) in your tag container. The container is what finds a classic setup, because the order itself only appears on the confirmation page, which the check never reaches.

Results

Result What it means Auto-tracking
GA4 ecommerce dataLayer found Your shop publishes GA4 ecommerce events. The card lists the events found, the product page used and the reasons. Switched on, with the dataLayer name found
No GA4 ecommerce dataLayer found No hard evidence was found. Send events with AxiTrace tracking calls (see the JavaScript SDK), or switch auto-tracking on yourself if you know the dataLayer is there. Switched off
Already tracked Your pages already send events to AxiTrace (AxiTrace tracking calls or an AxiTrace plugin), so reading the dataLayer as well would count everything twice. On a Shopify store the result points you to the AxiTrace Shopify app instead, because scripts in a Shopify theme do not run on Shopify's checkout. Switched off
Blocked Your shop's bot protection stopped the check. Tracking itself is not affected. Unchanged
Address problems The address could not be resolved, points to a private network, did not answer within 10 seconds, did not return a web page, or redirects to a different domain. Unchanged
Failed on our side Something went wrong at AxiTrace. We are notified automatically, and the attempt does not count against your limit. Unchanged

When a cookie banner holds back your Google Tag Manager until consent, the check still reads your pages and says so in the reasons.

Limit

The shop check is free on every plan. Each workspace can run it 3 times in any 24 hours; the card shows when the next check is available.

5. The Workspace setting

Auto-tracking is controlled by the GA4 dataLayer auto-tracking card in Workspace settings, in the Data collection section. It has a switch, an optional dataLayer name, and a line that says who set it last and when: the shop check, or you. The SDK receives the setting together with the rest of your workspace settings when it starts, so there is nothing to copy into your pages and no extra request. A change reaches your visitors within about 5 minutes, the time a browser may keep the settings it already loaded.

  • The shop check writes the setting each time it finishes with a result. You can change it afterwards; your change stands until you run a new check.
  • Turning it on asks you to confirm, because a site that also sends events with AxiTrace tracking calls or runs an AxiTrace plugin would count purchases and leads twice.
  • The installation snippet on the Manual connection page shows the current state as a comment line, for example // dataLayer auto-tracking: ON (dataLayer) - managed in Workspace settings. The snippet never switches it on or off itself.

The page option

The SDK also accepts autoTrackDataLayer and dataLayerName as options in Axitrace.init(). They combine with the Workspace setting like this:

Page code Workspace setting Result
No option, or autoTrackDataLayer: falseOnOn
No option, or autoTrackDataLayer: falseOffOff
autoTrackDataLayer: trueOn or offOn

A page can switch auto-tracking on, but never off. If your page code passes autoTrackDataLayer: true, auto-tracking stays on even when the Workspace switch is off. To manage it from the admin panel only, remove that option from your page.

A custom dataLayer name

Google Tag Manager can be installed with a renamed dataLayer (the fourth argument of the GTM snippet). Put that name into the Workspace card, or leave it empty for the default dataLayer. A name set in the page code wins over the Workspace name, unless the page names the default dataLayer. A name must be a plain JavaScript identifier of at most 64 characters: letters, digits, _ and $, not starting with a digit.

When the settings cannot be loaded

The SDK starts only after it has received your workspace settings, because those settings also decide consent and Do Not Track behaviour. It waits up to 2 seconds per attempt and retries three times, after 5, 15 and 45 seconds. Pushes made in the meantime stay in the dataLayer and are read as soon as the settings arrive. If all attempts fail, the SDK stays off for that page view: nothing is tracked, dataLayer or not.

6. Rules against double counting

Auto-tracking adds a second way for the same action to reach AxiTrace. These rules keep one order one order.

Use one source per event

Never switch on auto-tracking on a site that also sends the same events with AxiTrace tracking calls (Axitrace._instance.track(...)) or runs an AxiTrace plugin for WooCommerce, Shopify, Magento or Shopware. The plugins already send those events, and more reliably, because they capture the order on the server. The shop check detects both and answers "Already tracked".

One overlap is handled for you: when the SDK's own form tracking records a form submission and the dataLayer pushes generate_lead for the same submission, a second lead within 3 seconds of the first is skipped.

GA4 connections

If you forward events to GA4 through AxiTrace, remember that your shop's own GA4 tag already sends the events AxiTrace just read from the same dataLayer, and GA4 does not deduplicate. Each GA4 connection therefore has a switch, Forward browser-bridged dataLayer events. Turn it on only if your own GA4 tag does not already send these events; otherwise GA4 counts them twice. It is off for GA4 connections created from now on, and on for connections that already existed, so their behaviour does not change.

Every dataLayer event that is forwarded to GA4 carries the event parameter axitrace_source with the value datalayer_bridge, so you can find or exclude these events in your GA4 reports.

One order, one conversion on every ad platform

The same order can reach AxiTrace from more than one place: the dataLayer on the confirmation page, a plugin, a webhook, your backend. AxiTrace keeps every copy for reporting, but it forwards only the first purchase with a given order id to your ad platforms. Any other purchase event with the same order id in the same workspace within 30 days is not forwarded, whatever its source. Order ids are compared without case, surrounding spaces or a leading #, so #1041 and 1041 are the same order.

Meta, TikTok, Pinterest and Microsoft Ads also pair the browser and server copy of each event by a shared event id. GA4 and Google Ads do not, which is why the order rule above matters.

7. Troubleshooting

The shop check found nothing, but I know my shop has a dataLayer

The check reads the pushes written into your pages and the tags in your public tag container. Pushes made by a separate script file, by a theme app, or only after a click are invisible to it. If the console check shows GA4 ecommerce pushes, switch auto-tracking on yourself in Workspace settings → Data collection. The check never overrides your change until you run it again.

Auto-tracking is on, but no ecommerce events arrive

Open a product page with the browser console open. A warning that the dataLayer "is not an array" means the page stores something else under that name. Otherwise check that the dataLayer name in Workspace settings matches the fourth argument of your GTM snippet, and that the pushes use the GA4 event names in the table above. If your workspace requires cookie consent, nothing is sent until the visitor grants it.

I switched auto-tracking off, but events still arrive from the dataLayer

Your page code probably passes autoTrackDataLayer: true to Axitrace.init(). A page can switch auto-tracking on but never off. Remove the option from the page. Also allow a few minutes: a browser may keep the workspace settings it already loaded for up to 5 minutes.

Orders appear twice in AxiTrace

Look at the source of the two rows in the Orders list (Orders & journeys). Two sources for one order (the dataLayer and a plugin, or the dataLayer and AxiTrace tracking calls) means auto-tracking should be off, see rules against double counting. Your ad platforms still receive the order once. Two rows from the dataLayer usually means the purchase push has no transaction_id, or a placeholder such as (not set); the browser console says which.

Purchases arrive without the buyer's email or address

A typical GA4 purchase push carries only the order. Add plain-text user_data to the push, as shown in section 2. Hashed values and sha256_* keys cannot be used. For the best match rates, send the purchase from your server as well, see HTTP API.

The shop check says it was blocked

Your shop's bot protection stopped the check, and the check does not try to get around it. Tracking itself is not affected, because the SDK runs in your visitors' browsers. If your shop has a GA4 ecommerce dataLayer, switch auto-tracking on in Workspace settings → Data collection.

GA4 shows every ecommerce event twice

Turn off Forward browser-bridged dataLayer events on your GA4 connection. Your own GA4 tag already sends these events. The duplicates in GA4 carry axitrace_source = datalayer_bridge.

Need Help?

If you have any questions or need assistance: