When a campaign experience is triggered - i.e. the segment matched and all campaign rules matched - a custom event is dispatched to the dataLayer via dataLayer.push() as follows:
{
"event": "iem",
"event_category": "6939ab32d33c187121772953",
"event_action": "6939ab32d33c187121772953 | 6939aa2d42fbd50d5bf6889c | variation",
"event_label": "Campaign Name | Experience Name | variation | matched",
"in_holdout_group": 0,
}
Field Name | Value |
event | iem |
event_category | CAMPAIGN_ID |
event_action | CAMPAIGN_ID | VARIATION_ID | control OR variation |
event_label | CAMPAIGN_NAME | EXPERIENCE NAME | control OR variation |
in_holdout_group | 0 or 1 |
Matching Controls
If you enable a control for your campaign, we often want to compare users who "would have matched an experience" against those that did. We push events to the dataLayer when a user who is bucketed into the control "would have seen the experience" to allow for comparison.
E.g. for a campaign named "My Campaign" running 50/50 Control against a variation named "V1":
50% of users will have this event dispatched:
{
"event": "iem",
"event_label": "My Campaign | V1 | control | matched"
}
i.e. they "would have seen the V1" at the point this event is dispatched; and 50% of users will have this event dispatched:
{
"event": "iem",
"event_label": "My Campaign | V1 | variation | matched"
}
i.e. they "did see V1" at the point at which this event was matched.
Reporting using these events
The pipe-separated events allow for string-based matching when building reports in third party platforms such as Google Analytics. You can match full or partial event label strings, e.g.
event_label CONTAINS "My Campaign | V1 | control"
vs
event_label CONTAINS "My Campaign | V1 | variation"
Setting this up in GTM and GA4
To get these events into GA4, you'll need a Custom Event trigger in GTM listening for iem, with the fields on the pushed object mapped through to Data Layer Variables and GA4 Event Parameters.
GTM
Create a trigger of type Custom Event with event name iem. This fires whenever the dataLayer.push() shown above runs.
Then create a Data Layer Variable for each field you want to pass through:
Field | Data Layer Variable Name |
event_category | event_category |
event_action | event_action |
event_label | event_label |
in_holdout_group | in_holdout_group |
Finally, build a GA4 Event tag using your existing GA4 Configuration tag, firing on the trigger above. Give it an Event Name (e.g. iem, or something more descriptive like mwi_experience_matched), and map each Data Layer Variable to an Event Parameter of the same name.
GA4
By default, GA4 will collect the event but won't expose event_category, event_action, event_label, or in_holdout_group in standard reports. These are custom parameters, so they need registering under Admin > Custom definitions > Create custom dimension (event-scoped), one per field. Once registered, they're queryable.
For reporting, build an Exploration (Free form or Funnel) using event_label as a dimension, filtered with a "contains" match to compare groups, e.g.
event_label CONTAINS "My Campaign | V1 | control"
vs
event_label CONTAINS "My Campaign | V1 | variation"
in_holdout_group can be used as a secondary dimension for holdout analysis, and event_action / event_category give campaign-level rather than experience-level rollups.
A note on GA4 limits
GA4 event names must be 40 characters or fewer, and parameter values 100 characters or fewer. If a campaign or experience name is long, the pipe-separated event_label could get truncated, breaking exploration filtering.