GTM tracking bridge
When checkout and side-cart events don’t reach Dialog automatically (anything that’s not Shopify or Prestashop), you wire them via the window.DialogTracking bridge. This is the most common path because almost everyone already has GTM tagging their cart and checkout events.
What the bridge does
Section titled “What the bridge does”When the Dialog widget is loaded on a page, it exposes:
window.DialogTracking.track(eventName, payload)You call this from GTM tags to forward an add_to_cart or purchase event to Dialog. Anything else is ignored — only those two events are accepted.
Prerequisites
Section titled “Prerequisites”- The Dialog widget script must be loaded on the page where you call
window.DialogTracking.track(...). Most importantly, make sure the widget script tag fires on your purchase confirmation page — that’s the most common reasonwindow.DialogTrackingis undefined when your purchase tag fires. - You have edit access to your GTM container.
- The events you want to forward already live in GTM (typically via existing dataLayer pushes from your site or a GA4 / Ecommerce setup).
Supported events
Section titled “Supported events”Only these two:
add_to_cartpurchase
Payload spec
Section titled “Payload spec”Common fields
Section titled “Common fields”| Field | Type | Description |
|---|---|---|
value | number | Total event value (cart subtotal for add_to_cart, order total for purchase). |
currency | string | ISO currency code, e.g. "EUR", "USD". |
items | array (optional) | Items affected — see whitelist below. |
purchase adds
Section titled “purchase adds”| Field | Type | Description |
|---|---|---|
transaction_id | string | Unique transaction or order ID. |
Allowed item fields
Section titled “Allowed item fields”Whitelist (other fields are dropped):
item_iditem_namepricequantityitem_branditem_categoryitem_variantindexcoupondiscount
GTM implementation
Section titled “GTM implementation”Tag 1: forward purchase
Section titled “Tag 1: forward purchase”In GTM, create a Custom HTML tag named Dialog: forward purchase.
Trigger: your existing purchase trigger (typically on the order confirmation page).
<script> if (window.DialogTracking && typeof window.DialogTracking.track === 'function') { window.DialogTracking.track('purchase', { transaction_id: 'TRANSACTION_ID', value: VALUE, currency: 'CURRENCY', items: ITEMS }); }</script>Replace TRANSACTION_ID, VALUE, CURRENCY, ITEMS with your GTM variables. items is optional.
Tag 2: forward add_to_cart
Section titled “Tag 2: forward add_to_cart”<script> if (window.DialogTracking && typeof window.DialogTracking.track === 'function') { window.DialogTracking.track('add_to_cart', { value: VALUE, currency: 'CURRENCY', items: ITEMS }); }</script>The if (window.DialogTracking) guard is mandatory — see the race condition note below.
Avoid double-counting assistant add-to-cart
Section titled “Avoid double-counting assistant add-to-cart”If you forward add_to_cart with this bridge and the Dialog widget is installed via GTM, an add-to-cart triggered from inside the assistant is counted twice in user_added_to_cart: once by Dialog itself (it knows the assistant added the item) and once by your forwarded GA event. The assistant-specific user_added_to_cart_from_assistant event is unaffected.
To keep a single user_added_to_cart per assistant add-to-cart, tell the widget you already forward GA add_to_cart by adding bridgesGaAddToCart=true to the install script:
<script src="https://cdn.askdialog.com/assets/dialog-instant.js?productId={{Dialog Product ID}}&apiKey=YOUR_API_KEY&target=YOUR_CSS_SELECTOR&position=afterend&bridgesGaAddToCart=true"></script>Dialog then stops emitting its own user_added_to_cart for assistant actions, leaving your forwarded GA event as the single source.
Race condition: the most common gotcha
Section titled “Race condition: the most common gotcha”window.DialogTracking is set by the Dialog widget script after it has loaded and initialised. If your GTM tag fires before the widget script has run, window.DialogTracking is undefined and the call does nothing — the event is silently dropped.
The two safe patterns:
- Keep the
if (window.DialogTracking)guard (always). At worst, an event is missed; at best, your tag never throws. - Sequence your triggers. On a confirmation page, fire your purchase tag after the widget script has loaded — e.g. trigger on
DOMContentLoadedor a custom event you push to the dataLayer once the widget says it’s ready.
Concretely: if your purchase tag fires on Page View - DOM Ready and the widget loads asynchronously, you’ll lose purchases. Switch to Window Loaded or wrap the call in a small retry loop:
<script> (function tryTrack(attempts) { if (window.DialogTracking && typeof window.DialogTracking.track === 'function') { window.DialogTracking.track('purchase', { transaction_id: 'TRANSACTION_ID', value: VALUE, currency: 'CURRENCY', items: ITEMS }); return; } if (attempts <= 0) return; setTimeout(function () { tryTrack(attempts - 1); }, 200); })(20); // up to 4 seconds of polling</script>This is the pattern we recommend on confirmation pages where you can’t afford to lose the purchase event.
What you must have on the page
Section titled “What you must have on the page”For the bridge to exist, the Dialog widget script must run on the page where you call window.DialogTracking.track(...). The exact tag depends on your install:
- GTM install → the same
<script src="https://cdn.askdialog.com/assets/dialog-instant.js?..."></script>tag you set up in Install via Google Tag Manager. Make sure its trigger fires on your confirmation page as well, not just product pages. - SDK / React / Vue install → the SDK is bundled with your frontend, so the bridge is exposed wherever your storefront code runs. Just make sure your confirmation page is rendered by the same frontend (typical SPA) — server-rendered confirmation pages outside your SPA won’t have the SDK loaded.
QA checklist
Section titled “QA checklist”- Open your site with the Dialog widget loaded.
- In the browser console, type
window.DialogTracking. It must be defined. - Trigger an add-to-cart. Confirm in the Dialog dashboard that the side-cart event fires.
- Trigger a purchase. Confirm the checkout event fires.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
window.DialogTracking is undefined | Widget script not loaded on that page, or it hasn’t finished initialising | Verify the widget script tag is present and fires on this page; use the retry pattern above |
| Purchase tag fires on confirmation page but Dialog reports nothing | Race condition — the tag fires before the widget script finishes loading | Move the trigger to Window Loaded, or wrap the call in the retry loop above |
Wrong value or currency | GTM variables resolve too late | Move the tag to a later trigger or read from a stable dataLayer push |
Syncing the selected PDP variant
Section titled “Syncing the selected PDP variant”On product pages where the user can switch variants without a full reload (color/size swatches, AJAX variant pickers), Dialog can’t tell which variant is currently selected unless you tell it. The widget exposes a public method for that:
window.dialog?.setVariant('variant-id');Call it from the GTM tag that listens to your variant-change dataLayer event, or from any storefront listener you already have on the variant selector. The ?. guard handles the case where the widget hasn’t loaded yet — same race condition as the bridge.
When the user picks a variant from inside the assistant, Dialog emits a dialog:variant-changed event on window. Listen for it if you want to mirror that selection back into your storefront UI or analytics layer:
window.addEventListener('dialog:variant-changed', (event) => { console.log('Dialog selected variant:', event.detail.variantId);});Wiring both directions keeps recommendations, suggestions, and side-cart attribution pinned to the variant the user is actually looking at.
Next steps
Section titled “Next steps”- Tracking overview — what’s automatic vs manual per install path.
- SDK custom tracking — the alternative when you’d rather call SDK methods directly from your frontend code.