GTM schema documentation


This is the documentation you will need if you wish to do custom set ups on your 3rd party analytics.

# Consent API & Event Documentation

Technical Reference for Developers & Agencies

This document provides detailed technical information about the events we track and the Consent API implementation. For general merchant information, see the [Analytics & Tracking Documentation](merchant-analytics-documentation.md).

---

## Table of Contents

1. [GTM Template Download](#gtm-template-download)

2. [Event Reference](#event-reference)

3. [Consent API](#consent-api)

4. [Testing & Debugging](#testing--debugging)

5. [Multi-Currency Support](#multi-currency-support)

---

## GTM Template Download

For Store-Only Mode users: Download our pre-configured GTM container template with all tracking tags, triggers, and variables.

Download: [enjovia-platform-gtm-template.json](https://res.cloudinary.com/enjovia/raw/upload/v1760990872/GTM/enjovia-platform-gtm-template.json)

What's included:

- ✅ 6 Tags (GA4 Config, GA4 Events, Meta Base, Meta Events, TikTok Base, TikTok Events)

- ✅ 6 Triggers (conditional on pixel IDs)

- ✅ 11 Variables (all read from dataLayer)

- ✅ Zero hardcoded dependencies - fully portable

Import instructions: Use Admin → Import Container in Google Tag Manager. [Learn more](https://support.google.com/tagmanager/answer/6106997)

---

## Event Reference

All events are pushed to window.dataLayer and follow GA4 ecommerce event standards.

### Event: analytics_config

When: Page load (first event, fires once per session)

Purpose: Initialize tracking pixels with store configuration

```javascript

{

event: 'analytics_config',

store_analytics: {

ga4_measurement_id: 'G-XXXXXXXXXX', // null if not configured

meta_pixel_id: '1234567890', // null if not configured

tiktok_pixel_id: 'ABCDEFG1234567', // null if not configured

consent_required: true // boolean

},

store_context: {

store_id: 'store_abc123',

store_name: 'Your Store Name',

store_domain: 'yourstore.com',

store_locale: 'en_GB',

is_live: true, // False for test orders

}

}

```

Use in GTM: Trigger pixel initialization tags (GA4 Config, Meta Base Code, TikTok Base Code)

---

### Event: view_item_list

When: Homepage or category page load

Purpose: Track product discovery and browsing behavior

```javascript

{

event: 'view_item_list',

ecommerce: {

currency: 'GBP', // Event-level currency

item_list_id: 'homepage', // or category ID (e.g., 'cat_123')

item_list_name: 'All Products', // or category name

items: [

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

item_category: 'Experience', // Present if from category page

price: 50.00,

discount: 10.00, // If on sale (optional)

index: 0, // Position in list (0-indexed)

quantity: 1

},

{

item_id: 'prod_456',

item_name: 'Afternoon Tea',

item_category: 'Experience',

price: 35.00,

index: 1,

quantity: 1

}

// ... more products

]

}

}

```

GA4 Mapping: view_item_list

Meta/TikTok: Not sent (use view_item for individual product views)

---

### Event: view_item

When: Product detail page view

Purpose: Track product interest

```javascript

{

event: 'view_item',

ecommerce: {

currency: 'GBP',

value: 50.00, // Base product price

items: [

// Main product only

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

affiliation: 'Your Store Name', // Store name

item_brand: 'Your Store Name', // Store name

item_category: 'Experience', // If from category (optional)

item_list_id: 'cat_456', // If from category (optional)

item_list_name: 'Experiences', // If from category (optional)

price: 50.00,

quantity: 1,

discount: 10.00 // If on sale (optional)

}

]

}

}

```

Note: Available enhancements are tracked separately via a view_item_list event with item_list_name = "Product Name - Available Enhancements"

GA4 Mapping: view_item (main product only)

Meta Mapping: ViewContent

TikTok Mapping: ViewContent

---

### Event: add_to_cart

When: Product successfully added to basket (after shipping selected)

Purpose: Track conversion funnel entry

```javascript

{

event: 'add_to_cart',

ecommerce: {

currency: 'GBP',

value: 115.99, // Product + selected enhancements + shipping

items: [

// Main product

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

item_category: 'Experience', // If from category (optional)

item_variant: 'Deluxe', // If variant product (optional)

price: 50.00,

quantity: 1

},

// Selected enhancement - multiple quantity

{

item_id: 'addon_456',

item_name: 'Champagne Upgrade',

item_category: 'Enhancement',

price: 25.00,

quantity: 2, // Customer selected 2

item_list_id: 'prod_123',

item_list_name: 'Spa Day Experience'

},

// Selected enhancement - single quantity

{

item_id: 'addon_789',

item_name: 'Lunch Included',

item_category: 'Enhancement',

price: 30.00,

quantity: 1, // Customer selected 1

item_list_id: 'prod_123',

item_list_name: 'Spa Day Experience'

},

// Shipping method

{

item_id: 'del_123',

item_name: 'Royal Mail 1st Class',

item_category: 'Shipping',

price: 10.99,

quantity: 1

}

]

}

}

```

GA4 Mapping: add_to_cart (all items: product, enhancements, shipping)

Meta Mapping: AddToCart (product only, value includes total)

TikTok Mapping: AddToCart (product only, value includes total)

Note: Monetary products append value to name (e.g., "Gift Card - £50.00")

---

### Event: remove_from_cart

When: Item removed from checkout page

Purpose: Track cart abandonment signals

```javascript

{

event: 'remove_from_cart',

ecommerce: {

currency: 'GBP',

value: 75.99, // Value of removed items

items: [

// Main product

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

affiliation: 'Your Store Name',

item_brand: 'Your Store Name',

item_category: 'Experience', // If from category (optional)

item_variant: 'Deluxe', // If variant product (optional)

price: 50.00,

quantity: 1,

discount: 5.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

// Enhancements

{

item_id: 'addon_456',

item_name: 'Champagne Upgrade',

affiliation: 'Your Store Name',

item_brand: 'Your Store Name',

item_category: 'Enhancement',

price: 15.00,

quantity: 1,

item_list_id: 'prod_123',

item_list_name: 'Spa Day Experience',

discount: 2.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

// Shipping

{

item_id: 'del_123',

item_name: 'Royal Mail 1st Class',

affiliation: 'Your Store Name',

item_brand: 'Your Store Name',

item_category: 'Shipping',

price: 10.99,

quantity: 1,

discount: 0.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

}

]

}

}

```

GA4 Mapping: remove_from_cart

Meta Mapping: RemoveFromCart (custom event)

TikTok Mapping: CustomEvent: RemoveFromCart

---

### Event: view_cart

When: Checkout page load

Purpose: Track cart analysis and abandonment funnel entry

```javascript

{

event: 'view_cart',

ecommerce: {

currency: 'GBP',

value: 150.98, // Total cart value

coupon: 'SUMMER10', // If promotion active (optional)

items: [

// All basket items (products + enhancements + shipping)

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

item_category: 'Experience', // If from category (optional)

item_variant: 'Deluxe', // If variant product (optional)

price: 50.00,

quantity: 1,

discount: 5.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

{

item_id: 'addon_456',

item_name: 'Champagne Upgrade',

item_category: 'Enhancement',

price: 15.00,

quantity: 1,

item_list_id: 'prod_123',

item_list_name: 'Spa Day Experience',

discount: 2.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

// ... more items

]

}

}

```

Smart Reload Protection: Only fires once per session to prevent duplicate tracking on browser back/forward navigation

GA4 Mapping: view_cart

Meta Mapping: ViewCart (custom event)

TikTok Mapping: CustomEvent: ViewCart

---

### Event: begin_checkout

When: "Proceed to Payment" button clicked

Purpose: Track high-intent purchase signals

```javascript

{

event: 'begin_checkout',

ecommerce: {

currency: 'GBP',

value: 140.98, // After discount applied

coupon: 'SUMMER10', // If discount code applied (optional)

items: [

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

item_category: 'Experience', // If from category (optional)

item_variant: 'Deluxe', // If variant product (optional)

price: 50.00, // Discounted price (what customer pays)

quantity: 1,

discount: 5.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

{

item_id: 'addon_456',

item_name: 'Champagne Upgrade',

item_category: 'Enhancement',

price: 15.00,

quantity: 1,

item_list_id: 'prod_123',

item_list_name: 'Spa Day Experience',

discount: 2.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

// ... shipping, etc.

]

}

}

```

GA4 Mapping: begin_checkout

Meta Mapping: InitiateCheckout

TikTok Mapping: InitiateCheckout

---

### Event: purchase

When: Order confirmation page load

Purpose: Track revenue and conversion

```javascript

{

event: 'purchase',

ecommerce: {

transaction_id: 'ORD-12345', // Unique order reference

currency: 'GBP',

value: 140.98, // Total revenue (after discount, including tax)

tax: 23.50, // Tax amount

coupon: 'SUMMER10', // If applied (optional)

items: [

// All purchased items (products, enhancements, shipping)

{

item_id: 'prod_123',

item_name: 'Spa Day Experience',

item_category: 'Experience', // If from category (optional)

item_variant: 'Deluxe', // If variant product (optional)

price: 50.00, // Discounted price (what customer pays)

quantity: 1,

discount: 5.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

{

item_id: 'addon_456',

item_name: 'Champagne Upgrade',

item_category: 'Enhancement',

price: 15.00,

quantity: 1,

discount: 2.00, // If promotion active (optional)

promotion_id: 'promo_123', // If promotion active (optional)

promotion_name: 'Summer Sale' // If promotion active (optional)

},

// ... shipping, etc.

]

}

}

```

One-Time Protection: Only fires once per order to prevent revenue duplication on page reloads

GA4 Mapping: purchase

Meta Mapping: Purchase

TikTok Mapping: CompletePayment

---

### Event: view_promotion

When: Available discount displayed on checkout page

Purpose: Track promotion visibility

```javascript

{

event: 'view_promotion',

ecommerce: {

creative_name: 'Promotion Banner', // Display type

creative_slot: 'checkout_banner', // Location on page

promotion_id: 'promo_789', // Unique promotion ID

promotion_name: '10% Summer Sale', // Promotion title

location_id: 'checkout' // Page context

}

}

```

Note: Promotion events do NOT include items, currency, or value - they track promotion visibility and selection only.

GA4 Mapping: view_promotion

Meta/TikTok: Not sent

---

### Event: select_promotion

When: Discount code applied or auto-selected

Purpose: Track promotion engagement and conversion

```javascript

{

event: 'select_promotion',

ecommerce: {

creative_name: 'Code Entry', // How promotion was selected

creative_slot: 'checkout_code_entry', // Input location (or 'auto_applied')

promotion_id: 'promo_789', // Unique promotion ID

promotion_name: '10% Summer Sale', // Promotion title

location_id: 'checkout' // Page context

}

}

```

Note: Promotion events do NOT include items, currency, or value. To analyze promotion impact on revenue, correlate select_promotion with subsequent purchase events using the coupon parameter in the purchase event.

GA4 Mapping: select_promotion

Meta/TikTok: Not sent

---

## Consent API

We implement Google Consent Mode v2 which initializes BEFORE any tracking scripts load.

### Consent Types

Four consent categories are managed:

| Type | Purpose | Default (consent required) | Default (no consent) |

|------|---------|---------------------------|---------------------|

| analytics_storage | Analytics cookies (GA4) | denied | granted |

| ad_storage | Advertising cookies | denied | granted |

| ad_user_data | User data for ads | denied | granted |

| ad_personalization | Ad personalization | denied | granted |

### Initialization

Consent Mode v2 is initialized before GTM loads:

```javascript

window.dataLayer = window.dataLayer || [];

function gtag(){dataLayer.push(arguments);}

// If consent_required: true

gtag('consent', 'default', {

'analytics_storage': 'denied',

'ad_storage': 'denied',

'ad_user_data': 'denied',

'ad_personalization': 'denied',

'wait_for_update': 500 // Wait 500ms for stored consent

});

// If consent_required: false

gtag('consent', 'default', {

'analytics_storage': 'granted',

'ad_storage': 'granted',

'ad_user_data': 'granted',

'ad_personalization': 'granted'

});

```

### User Consent Update

When user accepts cookies via the banner:

```javascript

gtag('consent', 'update', {

'analytics_storage': 'granted',

'ad_storage': 'granted',

'ad_user_data': 'granted',

'ad_personalization': 'granted'

});

```

### Consent Storage

User consent is stored in localStorage for 365 days:

```javascript

localStorage.getItem('enjovia_consent')

// Returns:

{

"analytics_storage": "granted",

"ad_storage": "granted",

"ad_user_data": "granted",

"ad_personalization": "granted",

"timestamp": 1729449600000, // Expires after 365 days

"version": 1

}

```

### Checking Consent Programmatically

```javascript

// Check if user has made a consent choice

const consentData = JSON.parse(localStorage.getItem('enjovia_consent') || 'null');

if (consentData) {

console.log('Consent granted:', consentData.analytics_storage === 'granted');

console.log('Expires:', new Date(consentData.timestamp + 365 24 60 60 1000));

} else {

console.log('No consent choice stored');

}

```

### Updating Consent in Store-Only Mode

If you're managing consent yourself, update it before your GTM container loads:

```javascript

// Initialize with denied

gtag('consent', 'default', {

'analytics_storage': 'denied',

'ad_storage': 'denied',

'ad_user_data': 'denied',

'ad_personalization': 'denied'

});

// Update when user accepts (from your own consent banner)

function handleUserAcceptsCookies() {

gtag('consent', 'update', {

'analytics_storage': 'granted',

'ad_storage': 'granted',

'ad_user_data': 'granted',

'ad_personalization': 'granted'

});

// Store choice

localStorage.setItem('enjovia_consent', JSON.stringify({

analytics_storage: 'granted',

ad_storage: 'granted',

ad_user_data: 'granted',

ad_personalization: 'granted',

timestamp: Date.now(),

version: 1

}));

}

```

---

## Item Filtering (Meta & TikTok)

Platform automatically filters items for Meta and TikTok pixels:

Included:

- Main products (item_category != 'Enhancement' and != 'Shipping')

Excluded:

- Enhancement (item_category === 'Enhancement')

- Shipping (item_category === 'Shipping')

Value calculation:

- Total value includes all items (products + enhancements + shipping)

- Only products appear in contents array for Meta/TikTok

Example:

```javascript

// dataLayer event

{

event: 'add_to_cart',

ecommerce: {

value: 75.99, // Product (50) + Enhancement (15) + Shipping (10.99)

items: [

{ item_id: 'prod_123', price: 50.00, item_category: null },

{ item_id: 'addon_456', price: 15.00, item_category: 'Enhancement' },

{ item_id: 'del_royal', price: 10.99, item_category: 'Shipping' }

]

}

}

// What Meta/TikTok receive

{

value: 75.99, // Full value

contents: [

{ id: 'prod_123', quantity: 1, item_price: 50.00 } // Only product

]

}

```

---

## Best Practices for Developers

### GTM Variable Setup

Use dataLayer variables in GTM:

```javascript

// GA4 Measurement ID

{{DLV - ga4_measurement_id}} // store_analytics.ga4_measurement_id

// Meta Pixel ID

{{DLV - meta_pixel_id}} // store_analytics.meta_pixel_id

// TikTok Pixel ID

{{DLV - tiktok_pixel_id}} // store_analytics.tiktok_pixel_id

// Ecommerce data

{{DLV - ecommerce}} // ecommerce object

{{DLV - ecommerce.items}} // items array

{{DLV - ecommerce.value}} // transaction value

{{DLV - ecommerce.currency}} // currency code

```

### Conditional Triggers

Only fire tags when IDs are present:

```javascript

// Trigger condition for GA4 tags

{{DLV - ga4_measurement_id}} does not equal undefined

// Trigger condition for Meta tags

{{DLV - meta_pixel_id}} does not equal undefined

// Trigger condition for TikTok tags

{{DLV - tiktok_pixel_id}} does not equal undefined

```

### Event Naming

Match exact event names in GTM triggers:

- Custom Event: analytics_config

- Custom Event: view_item_list

- Custom Event: view_item

- Custom Event: add_to_cart

- Custom Event: remove_from_cart

- Custom Event: view_cart

- Custom Event: begin_checkout

- Custom Event: purchase

- Custom Event: view_promotion

- Custom Event: select_promotion


Was this article helpful?