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.
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.
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/end | events (event_name: 'page_view') | RT entry criteria, audience segmentation |
| Product view, cart, purchase | events (event_name: 'view_item', 'add_to_cart', etc.) | RT attributes, trigger conditions |
| Message shown / clicked / dismissed | events (event_name: 'td_msg_shown', etc.) — future, automatic | Campaign reporting, frequency capping |
Count page views: SELECT count(*) FROM events WHERE event_name = 'page_view'
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.
| Event name | When to fire | Key properties |
|---|---|---|
view_item | User views a product detail page | item_id, item_name, price, item_category, item_brand |
add_to_cart | User adds a product to the cart | item_id, item_name, price, quantity |
view_cart | User opens the cart | cart_total, item_count, items (JSON string) |
purchase | Order confirmation page | transaction_id, revenue, item_count, item_id, items |
add_to_wishlist | User saves a product | item_id, price |
login | User logs in | method (e.g., "email", "google") |
sign_up | User registers | method |
| Category | Property name | Type | Notes |
|---|---|---|---|
| Product ID | item_id | string | GA4 compatible |
| Product name | item_name | string | |
| Unit price | price | number | |
| Order revenue | revenue | number | |
| Quantity | quantity | number | |
| Category (up to 5 levels) | item_category – item_category5 | string | GA4 compatible |
| Brand | item_brand | string | |
| Order ID | transaction_id | string | GA4 compatible |
| Product array | items | string (JSON) | See array handling below |
td.trackEvent('events', {
item_id: 'SKU-001',
item_name: 'Essential Crew Tee',
price: 29,
item_category: 'tops',
item_brand: 'BASIQ',
event_name: 'view_item',
})// 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 },
]),
})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 },
]),
})Events with multiple products (cart, purchase) require a strategy for the product list:
| Approach | Pros | Cons |
|---|---|---|
JSON-stringify (items: "[{...}]") | Simple to implement; GTM-friendly | TD queries become complex; cannot use directly in RT attributes |
Flat fields (item_id_0, item_id_1, ...) | Easy to query | Field count explodes with cart size |
| Recommended: flat primary + JSON full list | Best of both worlds for triggers + completeness | Slightly 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 },
]),
})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)
})()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>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.
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>Once events are flowing into your TD database, they become available in RT 2.0 for:
| Feature | How events are used |
|---|---|
| RT Attributes | Compute per-user attributes from event history (e.g., most_recent_product, total_spend). These feed into Entry Criteria and audience segmentation. |
| Entry Criteria | Trigger 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 Segments | Build batch segments from event history (e.g., "users who purchased in the last 30 days") for use in campaign targeting. |
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 view | Manual trackEvent('events', { event_name: 'page_view' }) call required on every route change | Automatic on page load and SPA route change |
| Session start / end | Not available | Automatic (30-min timeout, td_session_id attached to all events) |
| First visit | Not available | Automatic on first page load (td_first_visit event) |
| Message impression | Not available | Automatic when SDK renders a popup or inline message (td_msg_shown) |
| Message click | Not available | Automatic on CTA interaction (td_msg_clicked) |
| Message dismiss | Not available | Automatic on close (td_msg_dismissed) |
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.