Custom Widget Analytics Integration

TicketingHub V2 Widget Custom Integration


Overview


This document describes the custom JavaScript events that the TicketingHub V2 checkout widget sends to the parent window via the browser's postMessage API. These events allow you to track user interactions throughout the checkout flow and build custom integrations with analytics platforms or your own systems.


All events are prefixed with th: (TicketingHub namespace) and are sent from the widget iframe to the parent window using window.parent.postMessage().



How to Listen to Events


To receive widget events, add a message listener to the parent window:


window.addEventListener('message', function(event) {
// Check if it's a TicketingHub event
if (!event.data || !event.data.event) return;
if (!event.data.event.startsWith('th:')) return;

const eventName = event.data.event;
const eventData = event.data.data;

console.log('Event:', eventName);
console.log('Data:', eventData);
});


Event Message Structure


All events follow this structure:


{
event: "th:event_name", // Event name with th: prefix
data: { // Event-specific data
// ... parameters
}
}



Events Reference


Page View Events


th:page_view


Sent when a user navigates to a checkout step. This is the most common event and fires on every page/step transition.


Data:

{
page_title: "Page Title", // Human-readable page name
page_path: "page_path", // URL-friendly page identifier
start_date: "2024-06-01T00:00:00Z", // (date pages only) ISO8601
selected_date: "2024-06-15T14:00:00Z" // (date pages only) ISO8601
}


Example:

// User navigates to date selection
{
event: "th:page_view",
data: {
page_title: "Date and Time Selection",
page_path: "date_and_time_selection",
start_date: "2024-06-01T00:00:00Z",
selected_date: "2024-06-15T14:00:00Z"
}
}



Selection Events


th:select_item


Sent when a user selects a product, variant, or merchandise item.


Data:

{
item_list_id: "uuid", // Widget ID or Product ID
item_list_name: "Sellable List", // "Sellable List" or "Variant List"
items: [
{
item_id: "uuid", // Product/Variant/Merchandise ID
item_name: "Product Name",
item_category: "Product" // "Product", "Variant", "Merchandise", or "Package"
}
]
}


Example:

// User selects a product
{
event: "th:select_item",
data: {
item_list_id: "widget-123",
item_list_name: "Sellable List",
items: [
{
item_id: "product-456",
item_name: "City Walking Tour",
item_category: "Product"
}
]
}
}



th:tier_selection_selected


Sent when a user selects ticket quantities.


Data:

{
tickets: {
"0": { tier_id: "uuid", quantity: 2 },
"1": { tier_id: "uuid", quantity: 1 }
}
}


Example:

{
event: "th:tier_selection_selected",
data: {
tickets: {
"0": { tier_id: "tier-adult-123", quantity: 2 },
"1": { tier_id: "tier-child-456", quantity: 1 }
}
}
}



th:extras_selection_selected


Sent when a user selects add-on extras.


Data:

{
extras: {
"0": { extra_id: "uuid", quantity: 1 },
"1": { extra_id: "uuid", quantity: 2 }
}
}



th:settings_selected


Sent when a user changes locale or currency settings.


Data:

{
settings: {
locale: "en-GB",
currency: "GBP"
}
}



th:package_tickets_selection_selected


Sent when a user selects ticket quantities for a package booking.


Data:

{
tickets: {
"0": { tier_type: "ADULT", quantity: 2 },
"1": { tier_type: "CHILD", quantity: 1 }
}
}



Form Submission Events


th:add_customer_details_submit


Sent when a user submits customer details.


Data:

{
customer: {
first_name: "John",
last_name: "Doe",
email: "john@example.com",
phone: "+44123456789",
// ... additional form fields
}
}




th:questions_and_answers_submit


Sent when a user submits answers to booking questions.


Data:

{
answers: {
"question-uuid-1": "Answer text",
"question-uuid-2": "Selected option"
}
}




th:package_booking_questions_and_answers_submit


Sent when a user submits answers for a package booking.


Data:

{
booking_index: 0,
answers: {
"question-uuid-1": "Answer text"
}
}



Voucher Redemption Events


th:voucher_booking_code_applied


Sent when a gift voucher code is successfully applied.


Data:

{
voucher_booking_code: "GIFT-ABC123"
}



th:voucher_purchase


Sent when a user initiates a voucher/gift card purchase.


Data: Empty object {}



th:voucher_booking_redemption_cancelled


Sent when a user cancels a voucher redemption.


Data: Empty object {}



th:voucher_booking_redemption_attendee_details_submit


Sent when a user submits attendee details during voucher redemption.


Data:

{
attendee_details: {
first_name: "Jane",
last_name: "Doe",
email: "jane@example.com"
}
}



th:voucher_booking_redemption_questions_and_answers_submit


Sent when a user submits answers during voucher redemption.


Data:

{
answers: {
"question-uuid": "Answer text"
}
}



Basket Events


th:discount_code_applied


Sent when a discount code is successfully applied.


Data:

{
discount_code: "SUMMER20"
}



th:discount_code_removed


Sent when a discount code is removed.


Data: Empty object {}



th:basket_delete_booking


Sent when a booking is removed from the basket.


Data:

{
booking_id: "booking-uuid"
}



th:basket_delete_package_booking


Sent when a package booking is removed from the basket.


Data:

{
bookings_package_id: "package-booking-uuid"
}



Order Events


th:purchase


Sent when an order is successfully completed. This is the main conversion event.


Data:

{
transaction_id: "TH-ABC123XYZ",
value: 150.00,
currency: "GBP",
items: [
{
item_id: "TKT-001",
item_name: "Adult Ticket",
item_brand: "City Walking Tour",
item_category: "standard",
item_variant: "Morning Session",
price: 50.00,
quantity: 1
}
]
}



Session Events


th:order_expired


Sent when the order/session expires due to timeout.


Data: Empty object {}



Integration Examples


Example 1: Track All Events


window.addEventListener('message', function(event) {
if (!event.data || !event.data.event) return;
if (!event.data.event.startsWith('th:')) return;

const eventName = event.data.event;
const eventData = event.data.data || {};

// Log all events
console.log('[TicketingHub]', eventName, eventData);

// Send to your analytics
if (window.analytics) {
window.analytics.track(eventName, eventData);
}
});


Example 2: Send Purchases to Multiple Platforms


window.addEventListener('message', function(event) {
if (!event.data || event.data.event !== 'th:purchase') return;

const data = event.data.data;

// Google Analytics 4
if (window.gtag) {
gtag('event', 'purchase', {
transaction_id: data.transaction_id,
value: data.value,
currency: data.currency,
items: data.items
});
}

// Facebook Pixel
if (window.fbq) {
fbq('track', 'Purchase', {
value: data.value,
currency: data.currency,
content_ids: data.items.map(i => i.item_id),
content_type: 'product',
num_items: data.items.length
});
}

// Google Ads Conversion
if (window.gtag) {
gtag('event', 'conversion', {
send_to: 'AW-XXXXXXXXX/XXXXXXXXXXXXX',
value: data.value,
currency: data.currency,
transaction_id: data.transaction_id
});
}

// TikTok Pixel
if (window.ttq) {
ttq.track('CompletePayment', {
value: data.value,
currency: data.currency,
content_id: data.items.map(i => i.item_id).join(',')
});
}

// Custom Backend
fetch('/api/conversions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
order_id: data.transaction_id,
revenue: data.value,
currency: data.currency,
items: data.items
})
});
});



Event Flow Diagram


User Opens Widget
|
+-- th:page_view (sellable_list)
|
User Selects Product
|
+-- th:select_item
+-- th:page_view (variant_list) [if variants exist]
|
User Selects Variant [if applicable]
|
+-- th:select_item
+-- th:page_view (tier_selection)
|
User Selects Ticket Quantities
|
+-- th:tier_selection_selected
+-- th:page_view (date_and_time_selection)
|
User Selects Date/Time
|
+-- th:page_view (extras_selection) [if extras available]
|
User Selects Extras [if applicable]
|
+-- th:extras_selection_selected
+-- th:page_view (questions_and_answers) [if questions configured]
|
User Answers Questions [if applicable]
|
+-- th:questions_and_answers_submit
+-- th:page_view (basket)
|
User Reviews Basket
|
+-- th:discount_code_applied [if code entered]
+-- th:basket_delete_booking [if item removed]
+-- th:page_view (add_customer_details)
|
User Enters Details
|
+-- th:add_customer_details_submit
+-- th:page_view (payment)
|
User Completes Payment
|
+-- th:purchase
+-- th:conversion
+-- th:page_view (success)



All Events Summary


Event

Trigger

Has Data

th:page_view

Every page navigation

Yes

th:select_item

Product/variant selection

Yes

th:tier_selection_selected

Ticket quantity selection

Yes

th:extras_selection_selected

Extras selection

Yes

th:settings_selected

Locale/currency change

Yes

th:package_tickets_selection_selected

Package ticket selection

Yes

th:add_customer_details_submit

Customer form submission

Yes

th:questions_and_answers_submit

Q&A form submission

Yes

th:package_booking_questions_and_answers_submit

Package Q&A submission

Yes

th:voucher_booking_code_applied

Voucher code applied

Yes

th:voucher_purchase

Voucher purchase started

No

th:voucher_booking_redemption_cancelled

Redemption cancelled

No

th:voucher_booking_redemption_attendee_details_submit

Voucher attendee form

Yes

th:voucher_booking_redemption_questions_and_answers_submit

Voucher Q&A form

Yes

th:discount_code_applied

Discount code applied

Yes

th:discount_code_removed

Discount code removed

No

th:basket_delete_booking

Booking removed from cart

Yes

th:basket_delete_package_booking

Package removed from cart

Yes

th:purchase

Order completed

Yes

th:conversion

Conversion (purchase/redemption)

Yes

th:order_expired

Session timeout

No



Security Considerations


When processing events:


  1. Validate event origin in production environments
  2. Sanitize data before inserting into DOM
  3. Never use eval() on event data


window.addEventListener('message', function(event) {
// Validate origin (optional but recommended for production)
// if (!event.origin.includes('ticketinghub.com')) return;

if (!event.data || !event.data.event) return;
if (!event.data.event.startsWith('th:')) return;

// Safe to process
handleEvent(event.data);
});



Reference



Looking for Google Analytics 4 Integration?




Updated on: 29/01/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!