Auto events
For additional information, please also refer to documentation of configSet(autoEventsConfig:) method, pa_autoEventDataSource instance property, which conforms to the AutoTrackableEventDataSource protocol. For container views such as UITableViewController and UICollectionView, there is a pa_itemsViewDataSource instance property, which conforms to the ItemsViewDataSource protocol.
Overview
Pulse SDK provides a way to automatically generate events when certain predefined actions occur. Auto events use swizzling under the hood and need to be explicitly enabled first. They only work with UIKit, and SwiftUI is not supported. Similar functionality in SwiftUI can be achieved using custom view modifiers, which must be explicitly applied to the views you want to track.
By default, most auto-events that describe the user's journey across the application are disabled to support the best app performance and network traffic consumption. To configure auto-event tracking granularly, call the configSet(autoEventsConfig:) method and pass a list of the auto-event types you'd like to enable. Each of this types is related to specific UIKit controls and user interactions. Below is an overview of the supported events and their corresponding types used to enable them.
| auto-event | trigger | corresponding type of PAAutoEventType |
|---|---|---|
click | UIButton is clicked | .buttonClick |
click | UISlider is clicked | .sliderControlClick |
click | UISwitch is clicked | .switchControlClick |
click | UIStepper is clicked | .stepperControlClick |
click | UISegmentedControl is clicked | .segmentedControlClick |
click | UIBarButtonItem is clicked | .barButtonClick |
click | UITableViewCell is clicked | .tableViewClick |
click | UICollectionViewCell is clicked | .collectionViewClick |
page_load | UIViewController is loaded ("viewDidLoad()" is called) | .viewController |
page_view | UIViewController appeared ("viewWillAppear(:)" is called) | .viewController |
items_impression | UITableViewCell was visible for given amount of time | .tableViewImpression |
items_impression | UICollectionViewCell was visible for given amount of time | .collectionViewImpression |
scroll | UIScrollView was scrolled | .scroll |
gesture | UIGestureRecognizer was fired | .gesture |
revenue_xxx | Specific StoreKit revenue-related transaction is occurring | .revenueTracking |
To maintain a clean auto-events sequence and avoid irrelevant events, the Pulse SDK excludes the following classes from page_load and page_view events:
UINavigationControllerUITabBarControllerUIPageViewControllerUISplitViewController
This exclusion also applies to their subclasses.
Code sample for enabling auto-events:
let config = PAAutoEventsConfig()
config.addType(.viewController)
config.addType(.buttonClick)
PAAnalytics.configSet(autoEventsConfig: config)
or
let config = PAAutoEventsConfig(autoEventTypes:
[
.viewController,
.buttonClick,
.barButtonClick,
.collectionViewClick
]
)
PAAnalytics.configSet(autoEventsConfig: config)
Note: Once auto-events are enabled via the configSet(autoEventsConfig:) method, they cannot be disabled during the current session. This limitation ensures the integrity of the swizzled call chain and helps prevent potential runtime issues.
If you configure auto-events at app startup, it allows the SDK to begin recording the user journey as early as possible, providing better insights into user behavior.
General auto event contents
Auto events contain a number of predefined and automatically populated fields in the data section of the event. Here's an overview:
| field name | type | optional | corresponding UIKit property |
|---|---|---|---|
element.value | String | yes | title/image |
element.id | String | yes | pa_autoEventDataSource |
element.type | String | no | - |
element.sequence 1) | Int | yes | - |
element.accessibility_id | String | yes | accessibilityIdentifier |
sources_info | [[String: String]] | no | - |
parent_info 2) | [String: String] | yes | - 3) |
previous_events | [String] | no | - |
additional_properties | [String: Any] | yes | pa_autoEventDataSource |
additional_ids | [String: Any] | yes | pa_autoEventDataSource |
group | String | yes | pa_autoEventDataSource |
section | String | yes | pa_autoEventDataSource |
1) only in page_view
2) not included in page_load or page_view events
3) you can influence parent_info content indirectly by changing parent's of elementName property if AutoTrackableEventData object that is retrieved by pa_autoEventDataSource
The Pulse Analytics SDK includes the public optional delegate property pa_autoEventDataSource for the following classes::
UIViewUIViewControllerUIBarButtonItemUIGestureRecognizer
The pa_autoEventDataSource property references a class that conforms to the AutoTrackableEventDataSource protocol. It is assigned to supply real-time data for any trackable UIKit element, provided that this delegate has been set for the specific instance of the UIKit element. When the SDK determines that the conditions for tracking a specific auto-event are met, it requests the delegate to provide a populated AutoTrackableEventData object that contains contextual information about the particular element.
element
element field contains information about the element that generates the event: a button, a collection view cell, a view controller, etc. It contains multiple subfields that describe the properties of the element.
| field name | optional | description |
|---|---|---|
value | yes | Contains the value of the element, such as its title or image name in the case of a button, title in the case of the view controller, first found label in the case of UITableView/UICollectionViewCell, etc. |
id | yes | Contains custom name (identifier) of the element via the AutoTrackableEventData.elementName property |
type | no | Describes the type of the element that generated the event. Can be one of these values: button, toggle, slider, stepper, segment, bar_button, collection_view_cell, table_view_cell, scroll_view. |
sequence | yes | The number of times this view controller appeared. |
accessibility_id | yes | Contains the value of the element's accessibilityIdentifier property. |
sources_info
sources_info field contains an array of dictionaries, each of which contains information about previously visited view controllers. It can be used to trace the user's journey leading to the current screen. Each item in the array contains the following subfields:
| field name | optional | description |
|---|---|---|
class | no | Contains class name of the view controller |
id | yes | Contains custom name (identifier) of the view controller |
accessibility_id | yes | Contains accessibility ID of the view controller |
sources_info contains up to three past screens. Screens are added to the array in order of appearance, meaning the last item in the array is the one that was shown most recently.
parent_info
parent_info contains information about the element's parent view controller.
| field name | optional | description |
|---|---|---|
class | no | Contains class name of the view controller |
id | yes | Contains custom name (identifier) of the view controller |
accessibility_id | yes | Contains accessibility ID of the view controller |
previous_events
previous_events contains IDs of up to 10 previous events.
additional_properties
additional_properties contains key-value pairs provided to the element via the AutoTrackableEventData.additionalProperties property.
additional_ids
additional_ids contains key-value pairs provided to the element via the AutoTrackableEventData.additionalIDs property.
group and section
Groups and sections are means of grouping elements together. Set AutoTrackableEventData.trackingGroup or AutoTrackableEventData.trackingSection in autoTrackEventData(for:) delegate method for a given view, and all of its containing elements that can generate auto events will contain the assigned values in their respective group and section fields.
sub_sids
Optional sub_sids parameter contains a dictionary where keys are custom IDs and values are view controller class names that exist in the hierarchy. This dictionary allows inspection of the view controller navigation path, describing the user's journey to the touchpoint where the event occurred.
Specialized contents
items_impression
items_count
items_count field contains the number of items counted as seen and contained in the params field.
params
params field contains information about each individual seen item.
gesture
The JSON schema of gesture event contains unique gesture_params parameter that may have different members depending of gesture recogniser type
gesture_params
gesture_params field contains information about the performed gesture. The internal mandatory type field indicates the type of gesture recognizer and the corresponding JSON schema structure.
gesture_params for UITapGestureRecognizer
| field name | type | optional | description |
|---|---|---|---|
tap_x | Int | yes | Horizontal coordinate of tap |
tap_y | Int | yes | Vertical coordinate of tap |
taps_count | Int | yes | Number of fingers required to match |
type | String | no | "tap" |
gesture_params for UILongPressGestureRecognizer
| field name | type | optional | description |
|---|---|---|---|
tap_x | Int | yes | Horizontal coordinate of tap |
tap_y | Int | yes | Vertical coordinate of tap |
taps_count | Int | yes | Number of fingers required to match |
type | String | no | "long_press" |
gesture_params for UIPinchGestureRecognizer
| field name | type | optional | description |
|---|---|---|---|
scale_start | Int | yes | Start value of pinch gesture recognizer in percentage |
scale_end | Int | yes | Final value of pinch gesture recognizer in percentage |
scale_value | Int | yes | Accumulated scale change in percentage |
type | String | no | "scale" |
gesture_params for UIRotationGestureRecognizer
| field name | type | optional | description |
|---|---|---|---|
rotate_start | Int | yes | Start value of rotation gesture recognizer in degrees |
rotate_end | Int | yes | Final value of rotation gesture recognizer in degrees |
rotate_value | Int | yes | Accumulated rotation change in degrees |
type | String | no | "rotate" |
gesture_params for UIPanGestureRecognizer
| field name | type | optional | description |
|---|---|---|---|
move_start_x | Int | yes | Horizontal coordinate before finger moving |
move_start_y | Int | yes | Vertical coordinate before finger moving |
move_end_x | Int | yes | Horizontal coordinate after finger moving |
move_end_y | Int | yes | Vertical coordinate after finger moving |
move_distance_x | Int | yes | Distance between move_end_x and move_start_x in pixels |
move_distance_y | Int | yes | Distance between move_end_y and move_start_y in pixels |
type | String | no | "move" |
scroll
The JSON schema of the scroll event contains a unique scroll_info parameter that is included regardless of the scroll direction, whether horizontal or vertical.
scroll_info
scroll_info field contains information about the performed scroll.
| field name | type | optional | description |
|---|---|---|---|
distance | Int | no | Scrolling distance in pixels |
speed | Int | no | Scrolling speed (pixels per second) |
direction | String | no | Scrolling direction ("up", "down", "left", "right") |
scroll_depth | Int | no | Visible percentage of scrolling |
start_position | Int | no | Start position before scrolling (content offset) |
end_position | Int | no | Final position after scrolling (content offset) |
duration | Int | no | Scrolling duration in milliseconds |
General customization
Auto events will contain as much useful info as our SDK can gather by itself, but if you'd like to have some control over the data, auto events can be customized in a few ways. This section discusses customization options available for all of the auto events.
Opt behavior
After enabling certain types of auto events, all objects of that class will generate those events when the trigger is met. All instances of classes that have their auto events enabled are opted in by default.
If you'd like to change that, use the pa_optBehavior property on the appropriate class:
UIButton.pa_optBehavior = .autoOptOut
UIScrollView.pa_optBehavior = .autoOptOut
The pa_autoEventDataSource optional delegate can be assigned to any view controller, view, or UI element. This delegate refers to an instance conforming to the AutoTrackableEventDataSource protocol, and it is used to provide additional information about the element generating the event. Additional details can be supplied by implementing the optional delegate method:
func autoTrackEventData(for element: AutoTrackableElement) -> AutoTrackableEventData?
This method, defined in the AutoTrackableEventDataSource protocol, enables you to pass relevant event data for enhanced tracking capabilities.
You can enable or disable event generation on a per-instance basis by implementing of func shouldAutoTrack(for element: AutoTrackableElement) -> Bool optional delegate method by pa_autoEventDataSource instance.
@MainActor
extension ABCDController: AutoTrackableEventDataSource {
func shouldAutoTrack(for element: AutoTrackableElement) -> Bool {
false
}
}
Identifying the element
Use AutoTrackableEventData.elementName to give elements a unique identifier that helps you identify events from specific objects. The element name will be included in the element.name field of the event.
@MainActor
extension ABCDController: AutoTrackableEventDataSource {
func autoTrackEventData(for element: AutoTrackableElement) -> AutoTrackableEventData? {
if let cell = element as? UICollectionViewCell {
if let indexPath = collectionView.indexPath(for: cell) {
let item = items[indexPath.row]
let data = AutoTrackableEventData(elementName: item.name)
print("Ask data for collection view cell with indexPath: \(indexPath)")
return data
} else {
print("Can't resolve indexPath of `AutoTrackableElement` collection view cell")
}
} else {
print("Ask data for other view: \(NSStringFromClass(type(of: element))) ")
}
return nil
}
}
Adding custom fields to the event
To add more data to the auto event, use the AutoTrackableEventData.additionalProperties and AutoTrackableEventData.additionalIDs properties that might be set by func autoTrackEventData(for element: AutoTrackableElement) -> AutoTrackableEventData? method.
@MainActor
extension ABCDController: AutoTrackableEventDataSource {
func autoTrackEventData(for element: AutoTrackableElement) -> AutoTrackableEventData? {
if let button = element as? MyLoginButton {
let params = ["username": "john-doe"]
let ids = ["sid": "e0182f1b-41e4-41aa-a30a-f19cfce0bd39"]
let data = AutoTrackableEventData(elementName: "login_button_signup", additionalProperties: params, additionalIDs: ids)
return data
}
return nil
}
}
Key-value pairs passed in the dictionaries will be added to the data.additional_properties and data.additional_ids fields of the auto event, respectively.
Detailed customization
Certain auto events have additional customization options due to their specific nature. This section discusses these additional options.
click localized string reverse lookup
click auto events include the button's title or asset name (if the button contains an image instead of text). This can be problematic for apps supporting multiple languages, as the same button could be "Si", "Ja", or "Yes" depending on the language. To mitigate this, you can set a custom AutoTrackableEventData.elementName or accessibilityIdentifier, or enable reverse string lookup to automate unique button identification.
Our SDK can track resolved localized strings and their keys in a reverse lookup table. This ensures that regardless of the resolved, localized string, the event includes the localized key used for resolving that string.
To enable this feature, call Bundle.enableLocalizedStringSwizzling().
As a result, the element field will contain an additional localized_key field:
"element": {
"localized_key": "universal.save",
"value": "Speichern",
"type": "button"
}
items_impression
The items_impression event is generated by any UITableView and UICollectionView instance. It contains data about items visible for more than 3 seconds and with over 50% visible area. Items are collected while the collection view or table view is visible and the event is closed when the collection view disappears (e.g., navigating to another screen or the app entering the background).
Our analytics SDK can only capture the index path of visible items, which is not very useful by itself. To properly populate the event with data, we introduced the ItemsViewDataProvider protocol. The collection view (table view) requests data about items at specific index paths (similar to UICollectionViewDataSource and collectionView(_:cellForItemAt:)). To provide items_impression data, assign the pa_itemsViewDataSource property of the collection view and implement ItemsViewDataSource methods, for example:
extension MyCollectionViewController: ItemsViewDataSource {
// global event data contained in root of `data` field
func eventData() -> [String: Any]? {
["sid": self.sessionID]
}
// per item data
func itemData(for indexPath: IndexPath) -> [String: Any]? {
guard let item = items[indexPath.row] else {
return nil
}
var data: [String: Any] = [:]
data["id"] = item.id
data["name"] = item.name
return data
}
}
Examples of events
page_load
{
"event_type": "page_load",
"event_id": "307CBBE7-8A92-4856-97AB-8F7CC10E4B22",
"timestamp": 1722336443065,
"sub_sids": {
"PAHomeViewController": "C2446833-4351-405B-A02F-CA463D648BA0"
},
"is_background": false,
"data": {
"metadata": {
"auto_generated": true,
"event_id_source": "sdk"
},
"connection_type": "WIFI",
"element": {
"class": "PADetailViewController",
"id": "Detail",
"type": "controller"
},
"previous_events": [
"EB66B7A8-8F25-450E-9A56-996C58779BBD",
"42012EEE-28F9-481F-8646-CCA5FB5CBC13",
"B3613147-D129-40A0-A407-9F1EEE910436",
"C0EE4335-C250-418B-963B-5030411DCB26"
],
"sources_info": [
{
"class": "PAHomeViewController",
"id": "Home"
}
]
}
}
page_view
{
"event_type": "page_view",
"event_id": "29FA66EC-D92E-4ED6-9CCA-BE93100FAEAD",
"timestamp": 1722336443122,
"is_background": false,
"sub_sids": {
"PAHomeViewController": "C2446833-4351-405B-A02F-CA463D648BA0",
"PADetailViewController": "70952851-2932-4BFF-A1DE-98A2345F1F3A"
},
"data": {
"metadata": {
"event_id_source": "sdk",
"auto_generated": true
},
"connection_type": "WIFI",
"element": {
"class": "PAProfileViewController",
"id": "Profile",
"type": "controller",
"sequence": 2
},
"previous_events": [
"42012EEE-28F9-481F-8646-CCA5FB5CBC13",
"B3613147-D129-40A0-A407-9F1EEE910436",
"C0EE4335-C250-418B-963B-5030411DCB26",
"51ED3F3D-20BD-4056-86EA-6E7466A5E998",
"22C85D49-CCB1-444B-B8B2-61458C74C2C7",
"B48AD8B9-1096-4F82-A808-AC390705A7B6",
"307CBBE7-8A92-4856-97AB-8F7CC10E4B22"
],
"sources_info": [
{
"class": "PAHomeViewController",
"id": "Home"
},
{
"class": "PADetailViewController",
"id": "Detail"
}
]
}
}
click
{
"event_type": "click",
"event_id": "FD8AF18C-B0EA-430A-A701-A7E7243FACA4",
"timestamp": 1722330200930,
"is_background": false,
"sub_sids": {
"PAHomeViewController": "3DD731ED-0F72-4847-BA08-1D4343E76D15"
},
"data": {
"metadata": {
"event_id_source": "sdk",
"auto_generated": true
},
"connection_type": "WIFI",
"element": {
"type": "button",
"value": "Speichern",
"localized_key": "universal.save"
},
"parent_info": {
"class": "PAHomeViewController"
},
"previous_events": [
"4EE35B59-078A-4B70-B3B6-EDF468561C1A",
"AA3EFA00-1FFA-4804-9DB9-E6C891BD7399",
"FE8830FD-E720-4E09-9C01-6440092C66F9"
],
"sources_info": [],
}
}
items_impression
{
"event_type": "items_impression",
"event_id": "F3D7D292-0180-4A1F-8BDE-047CD5C52542",
"timestamp": 1722351318853,
"is_background": false,
"sub_sids": {
"PAHomeViewController": "013CEE0A-7F71-43F0-ACFE-1E4CE8B7620E",
"PASimpleCollectionViewController": "49703FFD-C43A-4695-9EE1-E7C671211C5E"
},
"data": {
"metadata": {
"auto_generated": true,
"event_id_source": "sdk"
},
"connection_type": "WIFI",
"element": {
"type": "collection_view_cell"
},
"items_count": 8,
"params": [
{
"id": "83204de9",
"view_time": 4,
"name": "item 3",
"timestamp": 1722351315226
},
{
"id": "7ecd1b15",
"name": "item 6",
"timestamp": 1722351315226,
"view_time": 4
},
{
"id": "1b050eac",
"timestamp": 1722351315226,
"view_time": 4,
"name": "item 5"
},
{
"timestamp": 1722351315226,
"name": "item 4",
"view_time": 4,
"id": "6cc0d7ff"
},
{
"view_time": 4,
"name": "item 1",
"id": "a531edcc",
"timestamp": 1722351315226
},
{
"id": "b546f395",
"view_time": 4,
"timestamp": 1722351315226,
"name": "item 2"
},
{
"view_time": 4,
"id": "077fd072",
"name": "item 0",
"timestamp": 1722351315226
},
{
"view_time": 4,
"timestamp": 1722351315226,
"name": "item 7",
"id": "fd6426c3"
}
],
"parent_info": {
"class": "PASimpleCollectionViewController"
},
"previous_events": [
"44509F2A-1D13-435A-943F-8F6798116FEF",
"41E5961F-97A0-4B2C-AB65-4C450799DC6C",
"DE04BC5B-F750-4A46-8B68-A790C26D6712",
"12CF5246-97FD-40C2-B831-092BD4EADDF6"
],
"sources_info": [
{
"class": "PAHomeViewController",
"id": "Home"
},
{
"class": "PASimpleCollectionViewController"
}
]
}
}
scroll
{
"event_type": "scroll",
"event_id": "AD9DD603-0CD0-4E58-9831-19F609DA6DF6",
"timestamp": 1722348525771,
"is_background": false,
"sub_sids": {
"PAHomeViewController": "4A29E66E-12EB-42DB-BCD2-E708ED19BE4E"
},
"data": {
"metadata": {
"event_id_source": "sdk",
"auto_generated": true
},
"connection_type": "WIFI",
"element": {
"type": "scroll_view"
},
"parent_info": {
"class": "PAHomeViewController",
"id": "Home"
},
"previous_events": [
"FB155738-B97A-4E95-A95B-5CE044D37FE3",
"2BF72AAF-906B-4207-9581-11C4641AEA1D",
"D0880F56-514E-4DBE-A460-AA8D6C3E0EF7"
],
"sources_info": [],
"scroll_info": {
"distance": 36,
"speed": 73,
"direction": "up",
"scroll_depth": 27,
"end_position": 36,
"start_position": 0,
"duration": 487
}
}
}
gesture
{
"event_type": "gesture",
"event_id": "7749CD2D-8309-47D2-9448-2FD9089A099F",
"timestamp": 1722350412882,
"is_background": false,
"sub_sids": {
"settings": "A0095D03-5DD6-4FBA-8925-42B2C893F9D4",
"PAHomeViewController": "802D7F69-E2EB-4F76-98BF-7696EB18D913"
},
"data": {
"metadata": {
"event_id_source": "sdk",
"auto_generated": true
},
"connection_type": "WIFI",
"previous_events": [
"AEB4421F-3627-4D6B-AC7E-44090CF4DD9D",
"8335E620-3ABE-4238-ACD2-132DA59E94BB",
"6206B02C-87AF-424C-BF76-FB4270DF8FCE",
"A0E3B9F1-11B1-4313-97D6-F3C74BA54A2A"
],
"sources_info": [
{
"id": "Home",
"class": "PAHomeViewController"
},
{
"class": "PAProfileViewController",
"id": "Profile"
}
],
"parent_info": {
"id": "Settings",
"class": "PASettingsViewController"
},
"gesture_params": {
"tap_x": 185,
"type": "tap",
"tap_y": 376,
"taps_count": 1
},
"target_info": {
"class": "UIView"
},
}
}