The Tickets SDK provides analytics callbacks so you can track user behavior within the SDK experience. You can observe page views, user actions, and associated metadata to feed into your own analytics systems.
Note: These analytics callbacks are for your own tracking purposes. You can process these how you wish and send them to your own analytics backend
Overview
Both iOS and Android expose analytics for the Tickets SDK and the Authentication SDK. The table below summarizes the key differences in how each platform delivers analytics events.
Aspect | iOS | Android |
|---|---|---|
Tickets analytics API |
|
|
Delivery mechanism | Delegate methods | Kotlin |
Event structure | Separate | Single |
Metadata format | Typed |
|
Auth analytics API |
Tickets Analytics Setup
Set the analyticsDelegate on the shared TMTickets instance:
TMTickets.shared.analyticsDelegate = self
Then conform to the TMTicketsAnalyticsDelegate protocol, which provides two methods:
userDidView(page:metadata:)— called when the user views a pageuserDidPerform(action:metadata:)— called when the user interacts with a control
Observe analytics events from the UserAnalyticsDelegate singleton. The recommended approach uses a lifecycle-aware observer:
// Recommended: lifecycle-aware observer (handles cleanup automatically)
UserAnalyticsDelegate.handler.observe(lifecycleOwner) { data ->
data?.let { logAnalytics(it) }
}
Alternative approaches:
// Flow-based (for coroutines)
UserAnalyticsDelegate.handler.getFlow().collect { data -> ... }
// LiveData with observeForever (requires manual cleanup)
UserAnalyticsDelegate.handler.getLiveData().observeForever(userAnalyticsObserver)
Warning: If you use
observeForever, you must callremoveObserverwhen the Activity is destroyed to avoid leaking the observer.
Each event is delivered as a UserAnalyticsDelegate.AnalyticsData object containing an actionName string and optional data Bundle.
Page Views
Page view events fire when the user navigates to a screen within the SDK.
Page views are delivered through userDidView(page:metadata:) with a typed Page enum:
func userDidView(page: TMTickets.Analytics.Page, metadata: TMTickets.Analytics.MetadataType) {
print("userDidViewPage: \(page.rawValue)")
}
Available pages:
Page | Description |
|---|---|
| Purchased events listing ("My Events") |
| Tickets listing for a specific event ("My Tickets") |
| User scrolled down to view modules on tickets listing page |
| Ticket barcode page |
| Ticket delivery method info (non-barcode) |
| Ticket details page ("Back of Ticket") |
| 2FA/MFA prompt for a ticket operation |
| 2FA/MFA prompt to view a barcode |
| 2FA/MFA prompt for a webpage |
| Event info banner (health check, tax info, etc.) |
On Android, page views are delivered as action events. Screen-related actions use the suffix SCREENSHOWED:
Action | Description |
|---|---|
| My Tickets screen |
| Manage Tickets screen |
| Add Payment Info screen |
| Review Posting screen |
| Posting Confirmation screen |
| Cancel Posting screen |
| Cancel Posting Confirmation screen |
| My Ticket Barcode screen |
| Ticket Details screen |
Note: Android
actionNamestrings are prefixed withcom.ticketmaster.presencesdk.eventanalytic.action.(e.g.,com.ticketmaster.presencesdk.eventanalytic.action.MYTICKETSCREENSHOWED).
User Actions
User action events fire when the user interacts with buttons and controls in the SDK.
Actions are delivered through userDidPerform(action:metadata:) with a typed Action enum:
func userDidPerform(action: TMTickets.Analytics.Action, metadata: TMTickets.Analytics.MetadataType) {
print("userDidPerformAction: \(action.rawValue)")
}
Available actions:
Action | Description |
|---|---|
| User pressed the Apple "Add To Wallet" button |
| User took a screenshot of the barcode |
| User pressed the Send Transfer button |
| User pressed the Cancel Transfer button |
| User pressed the Edit Resale Posting button |
| User pressed the Cancel Resale Posting button |
| User pressed More Info on the event info banner |
| User pressed a button on a custom module |
| User pulled to refresh the events listing |
| User pressed the NavBar button |
Note: The
moduleActionButtoncallback is for analytics only. To handle module button taps, useTMTicketsModuleDelegate(see iOS Custom Modules). Similarly, the NavBar button is handled viaTMTicketsOrderDelegate, not the analytics delegate.
User actions are delivered through the same UserAnalyticsDelegate observer as page views:
Transfer and resale actions:
Action | Description |
|---|---|
| Transfer initiated |
| Transfer cancelled |
| Transfer accepted |
| Resale cancelled |
| Share transfer |
Wallet and UI actions:
Action | Description |
|---|---|
| Add to wallet initiated |
| Help button pressed on My Tickets |
Health check actions:
Action | Description |
|---|---|
| More Info clicked on health check |
| Learn More clicked on health check |
| Got It clicked on health check |
Federated login actions:
Action | Description |
|---|---|
| Link accounts screen showed |
| Link accounts screen dismissed |
| Login screen dismissed after successful login (no link) |
| Link accounts button pressed |
| No thanks button pressed |
Game Day actions:
Action | Description |
|---|---|
| Game Day modal showed |
| Game Day flow accepted |
| Game Day flow rejected |
CMS module visibility:
These events are sent as plain strings (not via the UserAnalyticsActions.Action enum):
| Description |
|---|---|
| First CMS module became visible |
| CMS module at index N became visible |
Metadata
Each analytics event includes metadata providing context about the event, ticket, or module involved.
Metadata is delivered as a typed MetadataType enum. You can switch on it to extract the relevant data:
switch metadata {
case .events(let events):
print(" - events: \(events.count)")
case .event(let event):
print(" - event: \(event.info.identifier)")
case .eventTickets(let event, let tickets):
print(" - event: \(event.info.identifier) tickets: \(tickets.count)")
case .eventTicket(event: let event, let ticket):
let ticketSummary = "\(ticket.sectionName ?? "_") \(ticket.rowName ?? "_") \(ticket.seatName ?? "_")"
print(" - event: \(event.info.identifier) ticket: \(ticketSummary)")
case .module(let event, let identifier):
print(" - module: \(identifier) event: \(event.info.identifier)")
case .moduleButton(let event, let module, let button):
print(" - module: \(module.identifier) button: \(button.title)(\(button.callbackValue)) event: \(event.info.identifier)")
case .empty:
print(" - empty")
@unknown default:
print(" - empty")
}
Metadata is delivered as a Bundle with string keys defined in the UserAnalyticsActions.ActionData enum.
General event/ticket context:
Key | Description |
|---|---|
| Event identifier |
| Event name |
| Event date |
| Event image URL |
| Order identifier |
| Venue name |
| Venue identifier |
| Current ticket count |
| Artist name |
| Artist identifier |
Transfer-related:
Key | Description |
|---|---|
| Number of tickets being transferred |
| Face value of tickets being transferred |
| Serialized transfer ticket data |
| Transfer ID being cancelled |
| Order ID of cancelled transfer |
Resale-related:
Key | Description |
|---|---|
| Number of tickets being listed for resale |
| Listing price |
| Serialized resale ticket data |
| Updated resale price |
| Posting ID being updated |
| Buyer fees |
| Original face value |
| Seller payout amount |
| Seller fees |
| Posting ID being cancelled |
Other:
Key | Description |
|---|---|
| Module identifier |
| Event orders data |
| Application name |
| Application package name |
Complete Examples
iOS
extension TicketsHelper: TMTicketsAnalyticsDelegate {
func userDidView(page: TMTickets.Analytics.Page, metadata: TMTickets.Analytics.MetadataType) {
print("userDidViewPage: \(page.rawValue)")
// different Pages return different types of metadata
switch metadata {
case .events(let events):
print(" - events: \(events.count)")
case .event(let event):
print(" - event: \(event.info.identifier)")
case .eventTickets(let event, let tickets):
print(" - event: \(event.info.identifier) tickets: \(tickets.count)")
case .eventTicket(event: let event, let ticket):
let ticketSummary = "\(ticket.sectionName ?? "_") \(ticket.rowName ?? "_") \(ticket.seatName ?? "_")"
print(" - event: \(event.info.identifier) ticket: \(ticketSummary)")
case .module(let event, let identifier):
print(" - module: \(identifier) event: \(event.info.identifier)")
case .moduleButton(let event, let module, let button):
print(" - module: \(module.identifier) button: \(button.title)(\(button.callbackValue)) event: \(event.info.identifier)")
case .empty:
print(" - empty")
@unknown default:
print(" - empty")
}
}
func userDidPerform(action: TMTickets.Analytics.Action, metadata: TMTickets.Analytics.MetadataType) {
print("userDidPerformAction: \(action.rawValue)")
// different Actions return different types of metadata
switch metadata {
case .events(let events):
print(" - events: \(events.count)")
case .event(let event):
print(" - event: \(event.info.identifier)")
case .eventTickets(let event, let tickets):
print(" - event: \(event.info.identifier) tickets: \(tickets.count)")
case .eventTicket(event: let event, let ticket):
let ticketSummary = "\(ticket.sectionName ?? "_") \(ticket.rowName ?? "_") \(ticket.seatName ?? "_")"
print(" - event: \(event.info.identifier) ticket: \(ticketSummary)")
case .module(let event, let identifier):
print(" - module: \(identifier) event: \(event.info.identifier)")
case .moduleButton(let event, let module, let button):
print(" - module: \(module.identifier) button: \(button.title)(\(button.callbackValue)) event: \(event.info.identifier)")
case .empty:
print(" - empty")
@unknown default:
print(" - empty")
}
}
}
Android
// Recommended: lifecycle-aware approach
class TicketsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupAnalytics()
}
private fun setupAnalytics() {
UserAnalyticsDelegate.handler.observe(this) { data ->
data?.let {
Log.d("Analytics", "Action: ${it.actionName}")
it.data?.let { bundle ->
bundle.getString("event_id")?.let { eventId ->
Log.d("Analytics", " - event_id: $eventId")
}
bundle.getString("event_name")?.let { eventName ->
Log.d("Analytics", " - event_name: $eventName")
}
}
}
}
}
}
If you need to use observeForever (for example, in an Application class), make sure to clean up:
private val userAnalyticsObserver = Observer<UserAnalyticsDelegate.AnalyticsData?> {
it?.let {
Log.d("Analytics", "Action name: ${it.actionName}, data: ${it.data}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
UserAnalyticsDelegate.handler.getLiveData().observeForever(userAnalyticsObserver)
}
override fun onDestroy() {
super.onDestroy()
UserAnalyticsDelegate.handler.getLiveData().removeObserver(userAnalyticsObserver)
}
Webviews
Many ticket operations such as Transfer and Resale have been moved into webviews (internal web pages). Currently, only a limited set of analytics events are returned from these web pages to the SDK.
Additional webpage analytics will be surfaced in future SDK releases.
Secure Entry SDK Analytics (Android Only)
The Secure Entry SDK on Android emits analytics via LocalBroadcastManager. You can register a BroadcastReceiver to listen for these events:
Event Constant | Value |
|---|---|
|
|
|
|
|
|
|
|
Related Documentation
iOS Custom Modules — for handling module button taps
Modules Overview — for module configuration