---
title: "Actions"
slug: "analytics-4"
updated: 2026-04-28T03:50:33Z
published: 2026-04-28T03:50:33Z
canonical: "ignite.ticketmaster.com/analytics-4"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://ignite.ticketmaster.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Actions

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]
> **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** | `TMTicketsAnalyticsDelegate` protocol | `UserAnalyticsDelegate` singleton observer |
| **Delivery mechanism** | Delegate methods | Kotlin `SharedFlow` / `LiveData` |
| **Event structure** | Separate `Page` and `Action` enums | Single `Action` enum (screens and actions combined) |
| **Metadata format** | Typed `MetadataType` enum | `Bundle` with string keys |
| **Auth analytics API** | See [Authentication Analytics](/v1/docs/authentication-state) | See [Authentication Analytics](/v1/docs/authentication-state) |

---

## Tickets Analytics Setup

**iOS**

Set the `analyticsDelegate` on the shared `TMTickets` instance:

```swift
TMTickets.shared.analyticsDelegate = self
```

Then conform to the `TMTicketsAnalyticsDelegate` protocol, which provides two methods:

- `userDidView(page:metadata:)` — called when the user views a page
- `userDidPerform(action:metadata:)` — called when the user interacts with a control

**Android**

Observe analytics events from the `UserAnalyticsDelegate` singleton. The recommended approach uses a lifecycle-aware observer:

```kotlin
// Recommended: lifecycle-aware observer (handles cleanup automatically)
UserAnalyticsDelegate.handler.observe(lifecycleOwner) { data ->
    data?.let { logAnalytics(it) }
}
```

Alternative approaches:

```kotlin
// Flow-based (for coroutines)
UserAnalyticsDelegate.handler.getFlow().collect { data -> ... }
// LiveData with observeForever (requires manual cleanup)
UserAnalyticsDelegate.handler.getLiveData().observeForever(userAnalyticsObserver)
```

> [!WARNING]
> **Warning:** If you use `observeForever`, you must call `removeObserver` when 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.

**iOS**

Page views are delivered through `userDidView(page:metadata:)` with a typed `Page` enum:

```swift
func userDidView(page: TMTickets.Analytics.Page, metadata: TMTickets.Analytics.MetadataType) {
    print("userDidViewPage: \(page.rawValue)")
}
```

**Available pages:**

| Page | Description |
| --- | --- |
| `events` | Purchased events listing ("My Events") |
| `eventTickets` | Tickets listing for a specific event ("My Tickets") |
| `eventModules` | User scrolled down to view modules on tickets listing page |
| `ticketBarcode` | Ticket barcode page |
| `ticketDelivery` | Ticket delivery method info (non-barcode) |
| `ticketDetails` | Ticket details page ("Back of Ticket") |
| `mfaForTicketOperation` | 2FA/MFA prompt for a ticket operation |
| `mfaForViewBarcode` | 2FA/MFA prompt to view a barcode |
| `mfaForWebpage` | 2FA/MFA prompt for a webpage |
| `eventInfoBanner` | Event info banner (health check, tax info, etc.) |

**Android**

On Android, page views are delivered as action events. Screen-related actions use the suffix `SCREENSHOWED`:

| Action | Description |
| --- | --- |
| `ACTION_MYTICKETSCREENSHOWED` | My Tickets screen |
| `ACTION_MANAGETICKETSCREENSHOWED` | Manage Tickets screen |
| `ACTION_ADDPAYMENTINFOSCREENSHOWED` | Add Payment Info screen |
| `ACTION_REVIEWPOSTINGSCREENSHOWED` | Review Posting screen |
| `ACTION_POSTINGCONFIRMATIONSCREENSHOWED` | Posting Confirmation screen |
| `ACTION_CANCELPOSTINGSCREENSHOWED` | Cancel Posting screen |
| `ACTION_CANCELPOSTINGCONFIRMSCREENSHOWED` | Cancel Posting Confirmation screen |
| `ACTION_MYTICKETBARCODESCREENSHOWED` | My Ticket Barcode screen |
| `ACTION_TICKETDETAILSSCREENSHOWED` | Ticket Details screen |

> [!NOTE]
> **Note:** Android `actionName` strings are prefixed with `com.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.

**iOS**

Actions are delivered through `userDidPerform(action:metadata:)` with a typed `Action` enum:

```swift
func userDidPerform(action: TMTickets.Analytics.Action, metadata: TMTickets.Analytics.MetadataType) {
    print("userDidPerformAction: \(action.rawValue)")
}
```

**Available actions:**

| Action | Description |
| --- | --- |
| `addTicketToWalletButton` | User pressed the Apple "Add To Wallet" button |
| `barcodeScreenshot` | User took a screenshot of the barcode |
| `transferSendButton` | User pressed the Send Transfer button |
| `transferCancelButton` | User pressed the Cancel Transfer button |
| `postingEditButton` | User pressed the Edit Resale Posting button |
| `postingCancelButton` | User pressed the Cancel Resale Posting button |
| `eventInfoBannerButton` | User pressed More Info on the event info banner |
| `moduleActionButton` | User pressed a button on a custom module |
| `pullToRefreshEvents` | User pulled to refresh the events listing |
| `navbarButtonAction` | User pressed the NavBar button |

> [!NOTE]
> **Note:** The `moduleActionButton` callback is for analytics only. To handle module button taps, use `TMTicketsModuleDelegate` (see [Custom Modules](/v1/docs/modules-overview-1)). Similarly, the NavBar button is handled via `TMTicketsOrderDelegate`, not the analytics delegate.

**Android**

User actions are delivered through the same `UserAnalyticsDelegate` observer as page views:

**Transfer and resale actions:**

| Action | Description |
| --- | --- |
| `ACTION_TRANSFERINITIATED` | Transfer initiated |
| `ACTION_TRANSFERCANCELLED` | Transfer cancelled |
| `ACTION_TRANSFERACCEPTED` | Transfer accepted |
| `ACTION_RESALECANCELLED` | Resale cancelled |
| `ACTION_SHARE_TRANSFER` | Share transfer |

**Wallet and UI actions:**

| Action | Description |
| --- | --- |
| `ACTION_ADD_TO_WALLET_INITIATE` | Add to wallet initiated |
| `ACTION_MY_TICKETS_HELP` | Help button pressed on My Tickets |

**Health check actions:**

| Action | Description |
| --- | --- |
| `ACTION_HEALTH_CHECK_MORE_INFO_CLICK` | More Info clicked on health check |
| `ACTION_HEALTH_CHECK_LEARN_MORE_CLICK` | Learn More clicked on health check |
| `ACTION_HEALTH_CHECK_GOT_IT_CLICK` | Got It clicked on health check |

**Federated login actions:**

| Action | Description |
| --- | --- |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_SCREEN_SHOWED` | Link accounts screen showed |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_SCREEN_DISMISSED` | Link accounts screen dismissed |
| `ACTION_FED_LOGIN_SCREEN_DISMISSED_AFTER_SUCCESS_LOGIN_NO_LINK` | Login screen dismissed after successful login (no link) |
| `ACTION_FED_LOGIN_LINK_ACCOUNTS_BUTTON_PRESSED` | Link accounts button pressed |
| `ACTION_FED_LOGIN_NO_THANKS_BUTTON_PRESSED` | No thanks button pressed |

**Game Day actions:**

| Action | Description |
| --- | --- |
| `ACTION_GAME_DAY_MODAL_SHOWED` | Game Day modal showed |
| `ACTION_GAME_DAY_FLOW_ACCEPTED` | Game Day flow accepted |
| `ACTION_GAME_DAY_FLOW_REJECTED` | Game Day flow rejected |

**CMS module visibility:**

These events are sent as plain strings (not via the `UserAnalyticsActions.Action` enum):

| `actionName` | Description |
| --- | --- |
| `"FIRST MODULE VIEWED"` | First CMS module became visible |
| `"MODULE VIEWED: N"` | CMS module at index N became visible |

---

## Metadata

Each analytics event includes metadata providing context about the event, ticket, or module involved.

**iOS**

Metadata is delivered as a typed `MetadataType` enum. You can switch on it to extract the relevant data:

```swift
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**

Metadata is delivered as a `Bundle` with string keys defined in the `UserAnalyticsActions.ActionData` enum.

**General event/ticket context:**

| Key | Description |
| --- | --- |
| `event_id` | Event identifier |
| `event_name` | Event name |
| `event_date` | Event date |
| `event_image_url` | Event image URL |
| `event_order_id` | Order identifier |
| `venue_name` | Venue name |
| `venu_id` | Venue identifier |
| `current_ticket_count` | Current ticket count |
| `artist_name` | Artist name |
| `artist_id` | Artist identifier |

**Transfer-related:**

| Key | Description |
| --- | --- |
| `initiate_transfer_ticket_count` | Number of tickets being transferred |
| `initiate_transfer_ticket_facevalue` | Face value of tickets being transferred |
| `initiate_transfer_ticket_serializable` | Serialized transfer ticket data |
| `cancel_transfer_id` | Transfer ID being cancelled |
| `cancel_transfer_order_id` | Order ID of cancelled transfer |

**Resale-related:**

| Key | Description |
| --- | --- |
| `initiate_resale_ticket_count` | Number of tickets being listed for resale |
| `initiate_resale_price` | Listing price |
| `initiate_resale_ticket_serializable` | Serialized resale ticket data |
| `update_resale_price` | Updated resale price |
| `update_resale_posting_id` | Posting ID being updated |
| `resale_buyer_fees` | Buyer fees |
| `resale_original_face_value` | Original face value |
| `resale_seller_payout` | Seller payout amount |
| `resale_seller_fees` | Seller fees |
| `cancel_resale_posting_id` | Posting ID being cancelled |

**Other:**

| Key | Description |
| --- | --- |
| `tm_tickets_module` | Module identifier |
| `event_orders` | Event orders data |
| `app_name` | Application name |
| `package_name` | Application package name |

---

## Complete Examples

### iOS

```swift
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

```kotlin
// 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:

```kotlin
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 |
| --- | --- |
| `EVENT_NTP_SYNC_FAIL` | `com.ticketmaster.presence.time.SecureEntryClock.NTP_SYNC_FAIL` |
| `EVENT_NTP_SYNC_OFFLINE` | `com.ticketmaster.presence.time.SecureEntryClock.NTP_SYNC_OFFLINE` |
| `EVENT_NTP_SYNC_COMPLETE` | `com.ticketmaster.presence.time.SecureEntryClock.NTP_SYNC_COMPLETE` |
| `EVENT_SECUREVIEW_NOT_SHOWN` | `com.ticketmaster.presence.time.SecureEntryClock.EVENT_SECUREVIEW_NOT_SHOWN` |

---

## Related Documentation

- [Authentication Analytics](/v1/docs/authentication-state)
- [Custom Modules](/v1/docs/modules-overview-1) — for handling module button taps
- [Modules Overview](/v1/docs/modules-overview-2) — for module configuration
