Installation
Requirements and install
Magento 2.4.x (Open Source or Adobe Commerce), PHP 8.1 to 8.5, Hyvä or Luma. A Google Tag Manager container, which is free.
composer require codingrow/module-gtmdl
bin/magento module:enable Codingrow_Gtmdl
bin/magento setup:upgrade
In production mode also setup:di:compile, setup:static-content:deploy and cache:flush. The Composer credentials arrive by email when you request the free module or buy the shopping events.
Everything is configured in Stores → Configuration → Codingrow Extensions → Google Tag Manager Data Layer, and every setting can be different per store view: change the Scope selector at the top left.
Container
| Field | What it does |
|---|---|
| Enable | With this off the store renders no container and no data layer at all. |
| Container ID | Your container, in the form GTM-XXXXXXX. Anything else is ignored. Leave it empty to push the data layer without loading any container — which is what you want when the container is already installed by something else. |
| Load the container only after cookie consent | Uses the Cookie Restriction Mode of Magento. The data layer is pushed either way, so nothing is lost once consent arrives. With Google consent active, below, this no longer applies. |
Using it
Google consent
Google Consent Mode v2. The default state has to be declared before the container starts, so only whoever loads the container can do it. The switch has three positions.
Declare the default state only is the right one when consent is already handled by a dedicated extension: the module declares everything denied, and your extension sends the update by calling
window.codingrowGtmdl.consent({
ad_storage: 'granted',
ad_user_data: 'granted',
ad_personalization: 'granted',
analytics_storage: 'granted'
});
Declare the default state and update it lets the module grant consent from Magento's own cookie notice. That option needs the Cookie Restriction Mode of Magento switched on (Stores → Configuration → General → Web → Default Cookie Settings): with it off, no customer can ever accept and consent would stay denied forever. A line under the fields says which of the two is really happening, and turns red in that case.
google-analytics.com/g/collect carry a parameter gcs: it reads G100 while consent is denied and G111 once it is granted. If it changes when you accept the cookies, Consent Mode is working.Two more settings: Redact advertising data without consent (Google sends no identifiers in its advertising calls while advertising consent is denied) and Pass the click id through the URL (without cookies, the click identifier travels in the address from page to page). Both are recommended.
The fourteen events
One switch per event. The four core ones are free; the other ten need the shopping events key.
| Event | When | Level |
|---|---|---|
view_item | product page | free |
view_cart | cart page | free |
begin_checkout | checkout page | free |
purchase | success page, from the real order | free |
view_item_list | category and search results | shopping |
select_item | a click on a product in a list | shopping |
add_to_cart | from the real cart line | shopping |
remove_from_cart | from the real cart line | shopping |
search | the term and how many results it gave | shopping |
add_to_wishlist | the product added | shopping |
add_shipping_info | the shipping method saved | shopping |
add_payment_info | the payment method saved | shopping |
login | customer sign-in | shopping |
sign_up | customer registration | shopping |
Two more settings sit in this group: Count orders created in the admin (orders typed in by hand have no visit behind them, and counting them distorts the cost per conversion) and Only these order statuses, which restricts the purchase to the statuses that really count as a sale.
The shipping and payment events do not depend on the checkout: they are raised from inside Magento when the method is saved, so they work on the standard checkout, on Hyvä, on Luma and on checkouts that answer on their own route. The other four are page events: the module ships a small layout file per route, and support can add one for a checkout that lives elsewhere.
Container to import
Until the container has a tag that reads the data layer, nothing reaches Analytics. Fill in the GA4 Measurement ID (the G-XXXXXXXXXX from Analytics, under Admin → Data streams) and, if you want the Google Ads conversion too, the conversion ID (the digits after AW-) and the conversion label of your purchase conversion action. Then press Download the container.
The file contains the GA4 configuration tag, the tag that forwards the ecommerce events, the conversion linker, the variables they need and — when the two Google Ads fields are filled — the purchase conversion carrying the real revenue and the order number.
In Google Tag Manager: Admin → Import Container, choose the file, pick Merge and Rename conflicting tags, look at the preview, then publish. Nothing you already have is overwritten.
Lost purchases
Roughly one purchase in five never reaches Analytics: an ad blocker, a script that failed, a customer who closes the page too early. With this on, the store sends the purchase itself when the browser did not, carrying the identifier that customer had at the time.
It needs the GA4 Measurement ID from the group above and a Measurement Protocol API secret, which you create in Analytics under Admin → Data streams → your stream → Measurement Protocol API secrets. It is stored encrypted. Wait before sending is the margin given to the customer browser: fifteen minutes is enough even on a slow connection.
Also recover purchases with no Analytics identifier covers the customers who block Analytics from the first page: there is nothing to read, so the purchase can only be sent as a new, direct visit. You get the revenue back in the reports and lose the attribution for those orders, which is why it starts off.
Under the fields a panel counts the last thirty days: orders recorded, the ones the browser confirmed, the ones the store recovered, the ones still waiting. A button asks Google to check the content of a test purchase without recording it.
What goes into the items
| Field | What it does |
|---|---|
| Prices include tax | Must match the basis your Google reports use. |
| Purchase value includes shipping | Changes only the value of the purchase. |
| Product attribute used as item_id | Use the same identifier as your product feed, or Google will not match the items. |
| Product attribute used as item_brand | Any product attribute. |
| Add the product categories | Adds the category to each item. |
| Maximum items in view_item_list | Keeps a long category page from sending a huge event. |
| Also send the classic remarketing keys | For containers that still read the old keys. |
| Ignored IP addresses | Comma separated. No event is sent from those addresses — the office, for instance. |
| Custom dimensions | Pairs of product attribute and GA4 parameter name. The parameter travels inside every item of every event. Declare it in GA4 as an item-scoped custom dimension, otherwise it arrives but does not show up in the reports. |
| Extra name for the unique event id | For containers whose triggers read that id under another name. The same value travels under both names, so on switchover day you touch nothing in the container. |
Troubleshooting
I set the container ID but nothing shows up in Google Tag Manager. Check that Enable is Yes in the scope you are looking at, that the ID has the form GTM-XXXXXXX, and in production mode that you ran the compile, the static deploy and a cache flush. In Google Tag Manager's Preview you see the events arrive; if they arrive and the reports stay empty, the problem is in the tags inside the container.
One event never fires. Ten of the fourteen belong to the shopping events: the key goes in the licence group. Without it the store keeps sending the four core ones.
The checkout events all arrive together on the thank-you page. Normal on a single-page checkout: the event is recorded the moment the customer chooses, and delivered on the next page load, which there is the thank-you page. In Analytics they stay in the same visit and in the right order, before the purchase.
The numbers do not match Analytics or Google Ads. Check the tax basis, whether shipping belongs in the purchase value, and that the attribute used as item_id is the identifier your product feed uses.
The purchase arrived twice. Not from the module: reloading the thank-you page does not repeat the event. Look for a second tag sending the same purchase — for instance an old Google Ads conversion still configured in Magento under Sales → Google API.