Skip to content
Last updated

Event Tracking

This guide covers how to define and send business events from your website to Treasure AI. Well-structured events are the foundation for In-Browser Message targeting — they determine when campaigns are triggered and what personalization attributes are available.

Responsibility boundary

You define: business events (view_item, purchase, etc.) and authenticated user IDs.

The SDK handles automatically: page views, session tracking, device/browser properties, message impression and click tracking (current and future).

Future SDK versions will also auto-track page views and SPA route changes — the manual patterns in this page will become optional.

Event Architecture

All events — page views, business events, and future SDK auto-tracked events — are sent to a single table. Use event_name to distinguish event types in queries.

What happened Table Used for
Page view, session start/endevents (event_name: 'page_view')RT entry criteria, audience segmentation
Product view, cart, purchaseevents (event_name: 'view_item', 'add_to_cart', etc.)RT attributes, trigger conditions
Message shown / clicked / dismissedevents (event_name: 'td_msg_shown', etc.) — future, automaticCampaign reporting, frequency capping

Count page views: SELECT count(*) FROM events WHERE event_name = 'page_view'

GA4-Compatible Event Naming

We recommend adopting GA4 standard event names for business events. This minimizes implementation cost for teams already using GA4, allows GTM dataLayer reuse, and provides a consistent schema for RT 2.0 targeting.

Standard e-commerce events

Event name When to fire Key properties
view_itemUser views a product detail pageitem_id, item_name, price, item_category, item_brand
add_to_cartUser adds a product to the cartitem_id, item_name, price, quantity
view_cartUser opens the cartcart_total, item_count, items (JSON string)
purchaseOrder confirmation pagetransaction_id, revenue, item_count, item_id, items
add_to_wishlistUser saves a productitem_id, price
loginUser logs inmethod (e.g., "email", "google")
sign_upUser registersmethod

Property naming conventions

Category Property name Type Notes
Product IDitem_idstringGA4 compatible
Product nameitem_namestring
Unit pricepricenumber
Order revenuerevenuenumber
Quantityquantitynumber
Category (up to 5 levels)item_categoryitem_category5stringGA4 compatible
Branditem_brandstring
Order IDtransaction_idstringGA4 compatible
Product arrayitemsstring (JSON)See array handling below

Sending Events

Basic event

td.trackEvent('events', {
  item_id: 'SKU-001',
  item_name: 'Essential Crew Tee',
  price: 29,
  item_category: 'tops',
  item_brand: 'BASIQ',
  event_name: 'view_item',
})

Cart event

// Add to cart
td.trackEvent('events', {
  event_name: 'add_to_cart',
  item_id: 'SKU-001',
  item_name: 'Essential Crew Tee',
  price: 29,
  quantity: 1,
  item_category: 'tops',
})

// Cart view (aggregate)
td.trackEvent('events', {
  event_name: 'view_cart',
  cart_total: 87,
  item_count: 3,
  items: JSON.stringify([
    { item_id: 'SKU-001', price: 29, quantity: 1 },
    { item_id: 'SKU-014', price: 58, quantity: 2 },
  ]),
})

Purchase event

td.trackEvent('events', {
  event_name: 'purchase',
  transaction_id: 'ORDER-10432',
  revenue: 87,
  item_count: 3,
  // Flat fields from the primary item — easy to use in RT triggers and attributes
  item_id: 'SKU-001',
  item_category: 'tops',
  // Full product array as JSON string for completeness
  items: JSON.stringify([
    { item_id: 'SKU-001', item_name: 'Essential Crew Tee', price: 29, quantity: 1 },
    { item_id: 'SKU-014', item_name: 'Wide-leg Pants', price: 58, quantity: 2 },
  ]),
})

Handling array data (items)

Events with multiple products (cart, purchase) require a strategy for the product list:

Approach Pros Cons
JSON-stringify (items: "[{...}]")Simple to implement; GTM-friendlyTD queries become complex; cannot use directly in RT attributes
Flat fields (item_id_0, item_id_1, ...)Easy to queryField count explodes with cart size
Recommended: flat primary + JSON full listBest of both worlds for triggers + completenessSlightly more implementation

Use the recommended pattern: send the properties most useful for trigger conditions as flat fields (e.g., item_category, price), and include the complete list as a JSON string for reporting.

td.trackEvent('events', {
  event_name: 'purchase',
  transaction_id: 'ORDER-001',
  revenue: 8760,
  item_count: 2,
  // Flat: primary item fields (easy for RT attribute conditions)
  item_id: 'SKU-123',
  item_category: 'electronics',
  price: 4380,
  // Full list as JSON string (for reporting)
  items: JSON.stringify([
    { item_id: 'SKU-123', item_name: 'Headphones', price: 4380, quantity: 1 },
    { item_id: 'SKU-456', item_name: 'Case', price: 4380, quantity: 1 },
  ]),
})

Firing Events Before the SDK Loads

On pages where the SDK script loads asynchronously, events fired before the SDK is ready could be dropped. Use the command queue pattern to safely fire events at any time — they are replayed once the SDK is ready.

// Safe to call at any time — queued if SDK not yet loaded
;(window.__tdEventQueue = window.__tdEventQueue || []).push([
  'trackEvent', 'events', { event_name: 'view_item', item_id: 'SKU-001', price: 29 }
])

// In your SDK initialization (sdk-loader.js or equivalent):
;(function drainQueue() {
  var queue = window.__tdEventQueue || []
  window.__tdEventQueue = { push: function(entry) {
    if (!entry || !entry.length) return
    var method = entry[0]
    if (window.td && typeof window.td[method] === 'function') {
      window.td[method].apply(window.td, entry.slice(1))
    }
  }}
  queue.forEach(window.__tdEventQueue.push)
})()

GTM Integration

Using the GA4 dataLayer

If your site already sends GA4 events via GTM, you can intercept the dataLayer and forward events to TD with minimal additional code.

// GTM Custom HTML Tag — fires on All Pages
<script>
;(function () {
  var _push = window.dataLayer.push.bind(window.dataLayer)
  window.dataLayer.push = function (event) {
    _push(event)
    // Forward GA4-style events to TD
    if (event && event.event && window.td) {
      var GA4_EVENTS = [
        'view_item', 'add_to_cart', 'view_cart',
        'purchase', 'add_to_wishlist', 'login', 'sign_up'
      ]
      if (GA4_EVENTS.indexOf(event.event) !== -1) {
        var props = Object.assign({}, event)
        props.event_name = props.event   // preserve as event_name field
        delete props.event
        delete props.gtm  // remove GTM internals
        window.td.trackEvent('events', props)
      }
    }
  }
})()
</script>
GTM global variable

The TD Web SDK exposes window.td (or window.Treasure) as a global, so GTM Custom HTML tags can call window.td.trackEvent(...) directly without needing additional setup.

Separate GTM tag per event

Alternatively, create a GTM Custom HTML tag for each event type, triggered by the corresponding GA4 event or custom GTM trigger:

<!-- GTM tag: fires on GA4 "view_item" event -->
<script>
  if (window.td && {{ecommerce.items}}) {
    var item = {{ecommerce.items}}[0] || {}
    window.td.trackEvent('events', {
      event_name: 'view_item',
      item_id: item.item_id,
      item_name: item.item_name,
      price: item.price,
      item_category: item.item_category,
    })
  }
</script>

Using Events in RT 2.0

Once events are flowing into your TD database, they become available in RT 2.0 for:

Feature How events are used
RT AttributesCompute per-user attributes from event history (e.g., most_recent_product, total_spend). These feed into Entry Criteria and audience segmentation.
Entry CriteriaTrigger a personalization section when specific event conditions are met (e.g., item_category == "electronics"). Currently supports event name matching (L1); property-based filtering (L2) is planned.
Audience SegmentsBuild batch segments from event history (e.g., "users who purchased in the last 30 days") for use in campaign targeting.

What the SDK Will Auto-Track in the Future

The following events currently require manual implementation. Future SDK versions will capture them automatically — the table and field names are defined in the SDK Event Requirements specification.

Event Current Future (SDK auto)
Page viewManual trackEvent('events', { event_name: 'page_view' }) call required on every route changeAutomatic on page load and SPA route change
Session start / endNot availableAutomatic (30-min timeout, td_session_id attached to all events)
First visitNot availableAutomatic on first page load (td_first_visit event)
Message impressionNot availableAutomatic when SDK renders a popup or inline message (td_msg_shown)
Message clickNot availableAutomatic on CTA interaction (td_msg_clicked)
Message dismissNot availableAutomatic on close (td_msg_dismissed)
Future-proof your implementation

Using GA4-compatible event names and the flat-field pattern described in this guide means your custom business events will work with future RT 2.0 trigger condition features (L2 property matching) without schema changes.