dataLayer and GA4 events
The events Benson pushes to window.dataLayer and GA4, their fields, when they fire, and how to use them in Google Tag Manager.
Jump to a section
Benson pushes its events to window.dataLayer, so Google Tag Manager and your own analytics can see when a coupon extension turns up, when Benson hides its pop-up, and what your discount widget does. It's on for every site by default. You don't need to add any code.
Turning it on and off#
Go to Site settings → Tracking → Integrations. There are two switches:
- dataLayer events (on by default) pushes each event to
window.dataLayer. Benson creates the array if your page doesn't have one. - GA4 events (off by default) sends the same events straight to Google Analytics 4 with
gtag("event", ...), ifgtagis on the page.
On Shopify, the dataLayer switch is also in the Benson app's settings. Neither switch needs a reinstall.
Use one route into GA4, not both. If GA4 events are on and a GTM tag also forwards the dataLayer events to GA4, every event is counted twice.
The events#
| Event | When it fires |
|---|---|
benson_ext_detected | Benson detects a coupon extension, AI shopping agent or automation in the session. |
benson_ext_blocked | A blocking rule matches an extension's pop-up. benson_mode says whether Benson hid it. |
benson_widget_shown | Your discount widget opens on its own for the first time (not when a shopper clicks the launcher). |
benson_code_applied | A code from your widget is applied to the cart. |
benson_ext_detected#
window.dataLayer.push({
event: "benson_ext_detected",
benson_actor_class: "extension",
benson_actor_id: "honey",
benson_confidence: 0.96,
});
| Field | Value |
|---|---|
benson_actor_class | extension, ai_agent or automation |
benson_actor_id | Which one, as a lowercase slug, such as honey, capital_one_shopping or rakuten |
benson_confidence | How sure the detection is, from 0 to 1 |
benson_ext_blocked#
window.dataLayer.push({
event: "benson_ext_blocked",
benson_actor_class: "extension",
benson_actor_id: "honey",
benson_confidence: 0.96,
benson_mode: "block",
});
It has the same fields as benson_ext_detected, plus:
| Field | Value |
|---|---|
benson_mode | block if Benson hid the pop-up. observe if the rule only watches, or the session is in a holdout, so the shopper still saw it. |
To count pop-ups actually hidden, filter on benson_mode equals block.
benson_widget_shown#
window.dataLayer.push({
event: "benson_widget_shown",
benson_campaign: "cmp_8f2k1",
benson_trigger: "exit_intent",
});
| Field | Value |
|---|---|
benson_campaign | The campaign's id |
benson_trigger | What opened it: immediate, delay, scroll, exit_intent, mobile_exit or tab_return |
benson_code_applied#
window.dataLayer.push({
event: "benson_code_applied",
benson_campaign: "cmp_8f2k1",
benson_method: "cart_api",
});
| Field | Value |
|---|---|
benson_campaign | The campaign's id |
benson_method | How the code went on: cart_api (the store's cart), handler (your registerApplyHandler function) or promo_input (typed into the store's discount field) |
The code itself is never included.
When events fire#
- Once per session. Each event fires once per Benson session for each extension, campaign or code. A shopper who browses ten pages with Honey installed gives you one
benson_ext_detected, not ten. - Every session. Events fire whether or not Benson is measuring the session for your reports (see sampling in Site settings → Tracking).
- Positive detections only. Borderline matches that Benson isn't confident about never reach the dataLayer.
- After the page loads. Benson waits for the page to finish loading before it starts, so it never slows down your page. Anything it detected before then is pushed as soon as it starts.
- Consent. Under strict mode, nothing is pushed while the shopper hasn't agreed.
- No personal data. Events never carry discount codes, session ids, visitor ids or anything that identifies a shopper.
If you need every occurrence, including low-confidence matches, subscribe with Benson.on() instead. It fires each time, without the once-per-session rule.
Using the events in Google Tag Manager#
- Add a trigger. Create a Custom Event trigger with the event name
benson_ext_detected. To catch all four with one trigger, use^benson_and tick Use regex matching. - Add variables. Create a Data Layer Variable for each field you need, such as
benson_actor_idandbenson_mode. - Send them on. Add a Google Analytics: GA4 Event tag on that trigger, with your variables as event parameters, for example
actor_idset to{{benson_actor_id}}. - Register the parameters in GA4 as custom dimensions so you can use them in reports and explorations.
- Publish the container.
Measure extension impact yourself shows how to use these events to compare extension sessions with everyone else.
GA4 without Tag Manager#
With GA4 events on, Benson calls gtag directly. It uses the same event names with the benson_ prefix dropped from the fields:
gtag("event", "benson_ext_detected", {
actor_class: "extension",
actor_id: "honey",
confidence: 0.96,
});
Nothing is sent if gtag isn't on the page.
Checking it works#
Open your store in a browser with a coupon extension installed, such as PayPal Honey, then run this in the console:
window.dataLayer.filter((e) => String(e.event).startsWith("benson_"));
GTM's Preview mode also lists each Benson event as it arrives. Because events fire once per session, open a new private window to see them again.
Test links don't push dataLayer or GA4 events, so a test never shows up in your analytics.
Stuck? Email [email protected].

