How to set up triggers for visitor, device, customer and cart data
Part of the data GTM4WP puts into the data layer no longer arrives in the first data layer push. It is delivered a moment after the page has loaded, in a data layer event of its own. A tag that reads one of these variables needs a Custom Event trigger, because a Page View trigger fires before the values are there and the tag would send nothing.
Four groups of data work this way: device data, visitor data, WooCommerce customer data and WooCommerce cart data.
This page describes GTM4WP 2.0.0 and newer. Where the legacy 1.x versions of the plugin behaved differently, the older behavior is marked with a bold GTM4WP 1.x: lead-in.
The four events
| Event name | Variables it carries | When it is available |
|---|---|---|
gtm4wp.deviceData | browserName, browserVersion, osName, osVersion, deviceType, deviceModel | On every 2.0.0 site, whenever at least one of the three device options is on |
gtm4wp.visitorData | siteSearchTerm, siteSearchFrom, visitorIP, geoCloudflareCountryCode, visitorLoginState, visitorType, visitorEmail, visitorEmailHash, visitorRegistrationDate, visitorUsername, visitorId | Only while the Cache-safe data layer option is on |
gtm4wp.customerData | The customer variables: customerTotalOrders, customerTotalOrderValue, customerFirstName, customerLastName and the customerBilling and customerShipping families | Only while the Cache-safe data layer option is on |
gtm4wp.cartData | cartContent | Only while the Cache-safe data layer option is on |
Device data works this way on every 2.0.0 site. The other three events only exist while the Cache-safe data layer option is switched on, and that option is off by default.
How the data flows with the cache-safe data layer off
This is the default, and on most sites it is what you have. The plugin renders the visitor, customer and cart values straight into the data layer of the page HTML, so they are already there in the very first data layer push. A Page View trigger reads them and nothing in your container has to change. gtm4wp.deviceData is the one exception, because the browser is the only place that data exists at all.
Three details of this mode are worth knowing, because each of them is different once you switch the option on:
- An anonymous visitor receives the logged out values rather than no variable at all.
visitorLoginStateholdslogged-out,visitorTypeholdsvisitor-logged-out, andvisitorUsername,visitorEmail,visitorEmailHashandvisitorRegistrationDateare sent with an empty value.visitorIdis the only one left out. cartContentand the customer variables are a snapshot of the moment the page was rendered. The plugin does not refresh them when the cart changes without a page load, so a quantity change on the cart page leaves them as they were until the next page view. Theadd_to_cartandremove_from_cartecommerce events still fire as usual.- All of these values are part of the page HTML. If your site serves that HTML to other visitors from a full page cache, they receive the values that were rendered for whoever filled the cache. That is the problem the cache-safe data layer exists to solve.
Why the data moved out of the page
Device data and the other three groups moved for different reasons.
Version 2.0.0 dropped the bundled WhichBrowser library and detects the browser, the operating system and the device from User-Agent Client Hints instead. Only the browser has those, so the plugin can push the values only once the page is running.
The other three groups moved because of caching. On a site with full page caching, such as LiteSpeed, WP Rocket, Varnish or Cloudflare APO, the HTML built for one visitor is stored and served to the next one. Anything visitor specific written into that HTML reaches everybody who receives the cached copy. The classic case is a page cached while an editor was logged in, which then carries that editor’s email address, user name and role to every anonymous visitor afterwards. The Cache-safe data layer option keeps those values out of the HTML and lets the browser collect them instead.
gtm4wp.deviceData
This event carries browserName, browserVersion, osName, osVersion, deviceType and deviceModel. The variables themselves are described on the browser attributes, operating system attributes and device attributes pages.
They come from the Browser data, OS data and Device data options in the Browser, OS & device data section of the settings screen. Each option controls its own group of variables, so with only Device data switched on the event carries deviceType and deviceModel and nothing else.
When the browser cannot determine a value, the plugin leaves that variable out of the event instead of sending it empty. Safari and Firefox do not support User-Agent Client Hints, so the plugin falls back to reading the user agent string there, and osVersion and deviceModel are usually missing.
The event fires once per page view, shortly after the page loads. It does not depend on the cache-safe data layer.
GTM4WP 1.x: browser, OS and device data was detected on the server and was part of the first data layer push, so a Page View trigger could read it. Tags built that way have to be moved onto a gtm4wp.deviceData trigger.
Turning the cache-safe data layer on
The Cache-safe data layer option has a panel of its own on the settings screen. It is off by default and it is marked experimental. While it is off, everything works as described in the section above.
Turn it on if your site serves cached HTML to anonymous visitors and you use any of the visitor, customer or cart variables. The browser then collects the values:
- The search term and the referring page come from the browser itself, without any request.
- The visitor IP and the Cloudflare country code come from a first party endpoint on your own site. The browser requests them once per browsing session and keeps them for the rest of it.
- The logged in user data comes from the same endpoint, requested only when the login state changes. An anonymous visitor never makes that request and never receives user data.
- The WooCommerce customer and cart data rides on the cart refresh request WooCommerce already makes whenever the cart changes, so the plugin issues no request of its own for it. This also means the cart variables now follow a cart change without a page load, which they did not do before.
That last point has a side effect worth knowing about. WooCommerce loads its cart refresh script only when a classic Cart widget is present, so on most stores the script is missing and the customer and cart data would never arrive. GTM4WP loads it itself while this mode is on. On a store that did not have it before, this means one extra WooCommerce request per browser tab.
gtm4wp.visitorData
This event carries siteSearchTerm, siteSearchFrom, visitorIP, geoCloudflareCountryCode, visitorLoginState, visitorType, visitorEmail, visitorEmailHash, visitorRegistrationDate, visitorUsername and visitorId. They are described on the user and visitor data, site search and geo data pages.
Each of these variables still has its own option in the Visitor data group of the Page variables section, except the two site search variables, which come from the Search data option. All of them are off by default, so if one is missing, check its option first.
The event fires only when at least one of these variables has a value on the current page view. On a page that is not a search results page, viewed by an anonymous visitor whose IP cannot be determined, the plugin pushes nothing at all. Do not write a tag that assumes the event always fires.
The content differs from the server rendered mode in one way. For an anonymous visitor the plugin leaves the logged in user variables out completely rather than sending them with their logged out values. In this mode there is no visitorLoginState with the value logged-out, no visitorType with the value visitor-logged-out and no empty visitorUsername, visitorEmail, visitorEmailHash or visitorRegistrationDate. A trigger condition written against one of those logged out values never matches. Test for the presence of the variable instead.
The third site search variable, siteSearchResults, describes the search results page and not the visitor, so it stays in the first data layer push and keeps working with a Page View trigger.
gtm4wp.customerData
This event carries the customer variables: customerTotalOrders, customerTotalOrderValue, customerFirstName, customerLastName, the nine customerBilling variables with the email hash among them, and the nine customerShipping variables.
They come from the Customer data in data layer option, in the Data layer content group of the WooCommerce section.
The event fires when the values are first read and again whenever they change, for example when the visitor fills in a billing field on the checkout page. It does not fire on a cart change, because the customer values did not change then.
A visitor who is not logged in still receives the customer variables with empty values, exactly as the server rendered mode sends them.
gtm4wp.cartData
This event carries cartContent. It comes from the Cart content in data layer option, in the same group of the WooCommerce section.
The event fires when the cart is first read and again on every cart change, so on an add, a removal or a quantity change.
An empty cart is sent too, as a cartContent with an empty item list, because that is how a tag sees the cart being emptied. A missing gtm4wp.cartData therefore does not mean that the cart is empty. It means that the option is off or that the cart has not been read yet.
Building the trigger in Google Tag Manager
- Open your container, go to Triggers and create a new trigger.
- Choose Custom Event as the trigger type.
- Enter the event name, for example
gtm4wp.visitorData, and leave This trigger fires on set to All Custom Events. - Save the trigger and assign it to the tags that read those variables.
To react to more than one of the three cache-safe events with a single trigger, tick Use regex matching and enter the following event name:
gtm4wp\.(visitor|customer|cart)Data
You read the variables themselves with a Data Layer Variable in Google Tag Manager, named exactly like the data layer key. Nothing changes there. Only the trigger changes.
Reading a variable from a different event
Google Tag Manager keeps the keys of earlier pushes in its data model, so a tag that fires on gtm4wp.cartData can also read visitorId, as long as gtm4wp.visitorData has already fired on that page view. On a page where it fires, it always comes first.
As described above, the plugin skips gtm4wp.visitorData on a page where none of its variables apply, so a tag firing on one of the two WooCommerce events must not take a visitor variable for granted.
What did not change
The ecommerce events are unaffected in both modes. view_item, view_item_list, select_item, add_to_cart, remove_from_cart, view_cart, begin_checkout, add_shipping_info, add_payment_info and purchase keep the event names and the triggers they have always had.
The page and post variables, so pagePostType, pageCategory, pagePostAuthor and the rest, describe the content and not the visitor. They stay in the first data layer push in both modes and keep working with a Page View trigger.
The browser delivers two WooCommerce events while the cache-safe mode is on, but they keep their own event names and need no trigger change: the add_to_cart fired when a product is restored to the cart with the Undo link, and the purchase recovered by the Reliable purchase tracking option when the order received page was missed.
If a variable does not arrive
- Check the option that produces the variable. All of them are off by default.
- Check whether the Cache-safe data layer option is on, because that decides whether the value is in the first data layer push or in one of the events above.
- With the option on, check that the tag is on a Custom Event trigger and not on a Page View trigger.
- In Preview mode, look at the row of the event itself. The values are not on the Container Loaded or DOM Ready rows.
- For a visitor variable, remember that with the option on an anonymous visitor receives no logged in user variables at all.
- When the browser blocks session storage, the plugin does not request the visitor data at all. A visitor in a hardened privacy mode receives only the values the browser computes on its own.
Related pages
See also user and visitor data, site search, browser attributes, operating system attributes, device attributes and geo data for the variables themselves, and the GA4 ecommerce tracking guide for the WooCommerce events.

