GTM Kit Premium 1.5: identify the customer on server-side events, and measure what the webhook rescues
GTM Kit Premium 1.5.0 is about making the server side a place you can measure from, rather than a safety net bolted onto the browser. Server-side events can now carry the customer’s hashed email and phone number, so ad platforms match them as well as they match a browser event. The purchase webhook can be told to fire only when the browser did not report, so you can count what it rescues instead of guessing. And a purchase recovered by the webhook can keep the traffic source of the visit it belongs to, which until now it could not.
Server-side events can identify the customer
An event sent from the browser has always carried the customer’s hashed email and phone number. An event sent from your server never did. It arrived with cookies and an IP address and nothing else, which is a materially worse match for every ad platform, and it is the single reason “just send everything server-side” has been the wrong advice.
The new Send hashed customer identifiers setting closes that gap. With it on, order events carry the customer’s email address and phone number, hashed so they never leave your shop in readable form, in the standard GA4 user_data shape that platform tags already know how to read. The values match the ones your browser events send, so a platform recognises both copies of the same purchase as the same person.
It is off by default. Updating changes nothing about what your shop sends until you switch it on. When you do, the values are added only for customers whose consent covers advertising, and they are worked out fresh each time an event is sent rather than stored anywhere, so nothing new is kept about your customers. Every server-side order event is covered, including refunds and subscription events, and you can inspect the payload with a test send before enabling it for real orders.
Send the server-side purchase only when the browser did not
Most shops should keep sending the purchase from both sides and let their container sort it out. That is the fail-safe setup and it stays the default.
But it cannot answer a question some shops genuinely need answered: how many sales would have been lost without the webhook? When both sides always send, a container that keeps the first arrival cannot tell a rescued conversion from one where the server simply won the race, so the recovery rate you thought you were measuring is not a real number.
The purchase webhook trigger now has a third option for exactly that. Choose it and the shop sends nothing from the server when the browser confirms the purchase reached Google Tag Manager. When the browser does not confirm, for any reason at all, a blocked container, a script error, a payment provider that never returns the customer to your shop, the event is sent. What lands in your container becomes a straight count of the conversions that would otherwise have been lost, readable under WooCommerce, Status, Logs.
A wait of five minutes, adjustable between one and sixty, gives the browser time to report before the shop decides.
This is a specialist auditing mode, third in the list on purpose. If you are not measuring recovery, keep one of the two existing options. And read the caveats below before selecting it.
Recovered purchases keep their traffic source
When a shop runs its tagging through its own subdomain, the analytics session and visitor cookies are commonly set so that JavaScript cannot read them at all. The capture running in the visitor’s browser had nothing to record, so a purchase recovered by the webhook reached Google Analytics with no session attached and its source and medium read “(not set)”. The better your server-side setup, the more reliably this happened.
Those identifiers are now also read from the order request itself, where the cookies are visible whatever they are set to. Anything the browser did capture is kept exactly as it was. Two related fixes ship alongside it: server-side events are once again recorded as the same visitor who was browsing the shop rather than as a brand new person each time, and the analytics session details are read correctly again after Google changed that cookie’s format.
Your server container also needs the updated template to read the session details it now receives. Re-import it from the Template Assistant after updating, otherwise the payload carries the session and the container still ignores it.
Update, 2 September 2026. There is a second reason to re-import, and it affects the same conversions. Server containers generated by the Template Assistant before this date set up the Google Analytics client to manage its own cookies without migrating the browser’s client ID. On those containers a recovered purchase is recorded against a visitor Google Analytics has never seen, so it arrives with no session and its traffic source shows as (not set) even though the payload was correct. Containers generated from 2 September onwards are already right.
This is not only about Google Analytics setups: the same client ships with server containers built for Google advertising products too, so check yours even if you selected Google Ads rather than Google Analytics.
You can fix an existing container in either of two ways. Re-import the server container template from the Template Assistant, which settles this and the session details together in one go. Or, if you would rather not re-import, open the Google Analytics client in your server container, expand More Settings, and tick Migrate from JavaScript Managed Client ID. The server-side purchase webhook explains what to check afterwards.
One honest limit. This works when the visit itself reached Google Analytics and only the purchase went missing, which is the common case after a payment gateway fails to return the customer. A visitor whose browser never reached Google Analytics at all has no session to join, and those conversions still arrive without a source.
Smaller fixes worth knowing about
- A slow tagging server no longer inflates revenue. Queued events used to give up after five seconds, less time than a container needs when starting up. The event had usually arrived anyway, so sending it again counted the same purchase twice.
- Orders a customer did not place in their own browser no longer pick up somebody else’s tracking data. An order created by hand in the admin, or a subscription renewal charged in the background, could take the identifiers of whoever’s page request happened to be running.
- The Preview test-send message stops overstating itself. After a successful test send it now tells you that real orders will not appear in Preview until you switch on the option that attaches the preview header to live traffic.
- The Template Assistant shows configuration fields for premium services such as TikTok instead of appearing to need no configuration and generating a container with unfilled values.
Developer notes
- Hashed identifiers are produced behind the advertising-consent gate at the point the value is created, not filtered out later, so a customer who declined is never hashed regardless of how your webhook consent setting is configured. Phone numbers are normalised exactly as the browser events normalise them, so both copies match.
- The server-side identifier read is consent-gated on the merge itself, which means it covers what is recorded against the order as well as what is sent. On a site with no consent plugin the gate stays open, matching the browser behaviour.
- The fallback mode confirms that Google Tag Manager loaded and was processing the data layer with the purchase event present. It does not prove that a specific purchase tag fired, which is a container problem rather than a delivery one.
Upgrade notes
- Hashed customer identifiers are off by default and have to be switched on deliberately. Nothing about your outgoing events changes on update.
- The purchase webhook keeps whichever trigger you have set. The new third option has to be chosen.
- If you run a custom snippet or mu-plugin that already implements browser-confirmed fallback behaviour, remove it before selecting the new mode. The two do not compose: the snippet unhooks the plugin’s own dispatch and does not recognise the new setting, so neither side sends the purchase and nothing is recorded at all.
- Two more things that turn the fallback mode into an always-send mode rather than breaking loudly. Selecting it while the frontend purchase event is disabled means nothing ever confirms, so every order waits out the timer and then sends. And a caching plugin that delays JavaScript until the visitor interacts will hold the confirmation script long enough to have the same effect. The recovery-rate log needs WooCommerce logging enabled.
- Session details in the payload need the updated server container template to be useful, and server containers generated before 2 September 2026 also record recovered purchases against the wrong visitor. One re-import from the Template Assistant settles both.
- GTM Kit Premium 1.5.0 requires GTM Kit 2.18.1 or later.