Collecting data with Trackers and Webhooks

  1. Home
  2. Docs
  3. Collecting data with Trackers and Webhooks
  4. Trackers – collecting data from your own applications
  5. Mobile Native Trackers
  6. Mobile Trackers v3.0
  7. Tracking Events

Tracking Events

The mobile trackers capture two types of events, automatically captured and manual events.

Auto Tracking

Automatically captured events in the iOS Tracker are:

  • App Lifecycle Tracking: Captures application foreground and application background events.
  • Screen View Tracking: Captures each time a new “screen” is loaded.
  • Exception Tracking: Captures any unhandled exceptions within the application.
  • Installation Tracking: Captures an install event which occurs the first time an application is opened.

These are enabled in the tracker configuration. In this example, some helpful automatic contexts and all Autotracking is enabled:

let trackerConfig = TrackerConfiguration()
    .sessionContext(true)
    .platformContext(true)
    .screenContext(true)
    .applicationContext(true)
    .lifecycleAutotracking(true)
    .screenViewAutotracking(true)
    .exceptionAutotracking(true)
    .installAutotracking(true)

Session Context

Client session tracking is activated by default but it can be disabled through the TrackerConfiguration as explained above. When enabled the tracker appends a client_session context to each event it sends and it maintains this session information as long as the application is installed on the device.

Sessions correspond to tracked user activity. A session expires when no tracking events have occurred for the amount of time defined in a timeout (by default 30 minutes). The session timeout check is executed for each event tracked. If the gap between two consecutive events is longer than the timeout the session is renewed. There are two timeouts since a session can timeout in the foreground (while the app is visible) or in the background (when the app has been suspended, but not closed).

The lifecycle events (application_foreground and application_background events) have a role in the session expiration. The lifecycle events can be enabled in the TrackerConfiguration enabling lifecycleAutotracking (Note: on Android it requires androidx.lifecycle:lifecycle-extensions). Once enabled they will be fired automatically when the app moves from foreground state to background state and vice versa.

When the app moves from foreground to background the application_background event is fired. If session tracking is enabled, the session context will be attached to the event checking the session expiration using the foreground timeout. When the app moves from background to foreground the application_foreground event is fired. If session tracking is enabled, the session context will be attached to the event checking the session expiration using the background timeout.

For instance, with this configuration:

SessionConfiguration(
    TimeMeasure(360L, TimeUnit.SECONDS),
    TimeMeasure(15L, TimeUnit.SECONDS)
)

the session would expire if the app is backgrounded for more than 15 seconds, like in this example:

time: 0s - screen_view event - foreground timeout session check - session 1
time: 3s - application_background event - foreground timeout session check (3  15) - session 2
time: 30s - application_foreground event - background timeout session check (30 > 15) - session 2

In the above example the application_foreground event triggers a new session because the time spent on background (without tracked events) is bigger than the background timeout for the session.

Session callback

(Available from v3.1)

The tracker allows the configuration of a callback to inform the app everytime a new session is created (in correspondence of a session timeout check). This can be configured in the SessionConfiguration and it provides the SessionState where can be accessed all the info already tracked in the SessionContext.

Below an example of where the session callback is used to print out the values of session every time a new session is generated by the tracker:

...
let sessionConfig = SessionConfiguration()
    .onSessionStateUpdate { session in
        print("SessionState: id: \(session.sessionId) - index: \(session.sessionIndex) - userID: \(session.userId) - firstEventID: \(session.firstEventId)")
    }
...
let tracker = Snowplow.createTracker(namespace: kNamespace, network: networkConfig, configurations: [sessionConfig])

Custom Event Context

Custom context can be used to augment any standard Snowplow event type, including self describing events, with additional data. We refer to this custom context as Event Entities.

Each custom context is an array of self-describing JSON following the same pattern as a self describing event. As with self describing events, if you want to create your own custom context, you must create a JSON schema for it and upload it to an Iglu repository using the Snowplow BDP Console UI, Data Structures API, igluctl or one of the other supported Iglu clients.

Note: Even if only one custom context is being attached to an event, it still needs to be wrapped in an array.

Here are two example custom context JSONs. One describes a screen:

{
    schema: 'iglu:com.example/screen/jsonschema/1-2-1',
    data: {
        screenType: 'test',
        lastUpdated: '2021-06-11'
    }
}

and the other describes a user on that screen:

{
    schema: 'iglu:com.example/user/jsonschema/2-0-0',
    data: {
      userType: 'tester'
    }
}

Tracking events with Custom Context

How to track a screen view with both of these contexts attached:

let event = ScreenView(name: "DemoScreenName", screenId: UUID())
event.contexts.add(
    SelfDescribingJson(schema: "iglu:com.example/screen/jsonschema/1-2-1",
        andDictionary: [
             "screenType": "test",
             "lastUpdated": "2021-06-11"
        ])!)     
event.contexts.add(
    SelfDescribingJson(schema: "iglu:com.example/user/jsonschema/2-0-0", 
        andDictionary: [
             "userType": "tester"
        ])!)

tracker.track(event)

It is also possible to add contexts in a declarative way, so that they are applied to all (or a subset of) events within an application.

Manual Tracking

Self Describing

You may wish to track events in your app which are not directly supported by Snowplow and which structured event tracking does not adequately capture. Your event may have more than the five fields offered by Structured events, or its fields may not fit into the category-action-label-property-value model. The solution is Snowplow’s self-describing events. Self-describing events are a data structure based on JSON Schemas and can have arbitrarily many fields.

To define your own custom event, you must create a JSON schema for that event and upload it to an Iglu Schema Repository using igluctl (or if a Snowplow BDP customer, you can use the Snowplow BDP Console UI or Data Structures API). Snowplow uses the schema to validate that the JSON containing the event properties is well-formed.

let data = ["targetUrl": "http://a-target-url.com" as NSObject];       
let event = SelfDescribing(schema: "iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1", payload: data)       

tracker.track(event)

A Self Describing event is a self-describing JSON. It has two fields:

  • A data field, containing the properties of the event
  • A schema field, containing the location of the JSON schema against which the data field should be validated.

Structured

Our philosophy in creating Snowplow is that users should capture important consumer interactions and design suitable data structures for this data capture. You can read more about that philosophy here. Using trackSelfDescribingEvent captures these interactions with custom schemas, as desribed above.

However, as part of a Snowplow implementation there may be interactons where custom Self Describing events are perhaps too complex or unwarranted. They are then candidates to track using Structured, if none of the other event-specific methods outlined below are appropriate.

let event = Structured(category: "Example", action: "my-action")
    .label("my-label")
    .property("my-property")
    .value(5)

tracker.track(event)

Timing

Use the Timing events to track user timing events such as how long resources take to load.

let event = Timing(category: "timing-category", variable: "timing-variable", timing: 5)
    .label("optional-label")       

tracker.track(event)

Screen View

Track the user viewing a screen within the application. This type of tracking is typically used when automatic screen view tracking is not suitable within your application.

let event = ScreenView(name: "DemoScreenName", screenId: UUID())

tracker.track(event)

Consent

Consent Granted

Use the ConsentGranted event to track a user opting into data collection. A consent document context will be attached to the event using the id and version arguments supplied.

let event = ConsentGranted(expiry: "2022-01-01T00:00:00Z", documentId: "1234abcd", version: "1.2")       
    .name("document-name")
    .documentDescription("document-description")
                
tracker.track(event)

Consent Withdrawn

Use the ConsentWithdrawn event to track a user withdrawing consent for data collection. A consent document context will be attached to the event using the id and version arguments supplied. To specify that a user opts out of all data collection, all should be set to true.

let event = ConsentWithdrawn()
    .all(true)
    .documentId("1234abcd")
    .version("1.2")       
    .name("document-name")
    .documentDescription("document-description")
                
tracker.track(event)

Ecommerce Transaction

Modelled on Google Analytics ecommerce tracking capability, Snowplow uses three steps that can be used together to track online transactions:

  1. Create a Ecommerce event. Use Ecommerce to initialize a transaction object. This will be the object that is loaded with all the data relevant to the specific transaction that is being tracked including all the items in the order, the prices of the items, the price of shipping and the order_id.

  2. Add items to the transaction. Create an array of EcommerceItem to pass to the Ecommerce object.

  3. Submit the transaction to Snowplow using the track() method, once all the relevant data has been loaded into the object.

let transactionID = "6a8078be"       
                
let itemArray = [       
  EcommerceItem(sku: "DemoItemSku", price: 0.75, quantity: 1)
    .name("DemoItemName")       
    .category("DemoItemCategory")       
    .currency("USD")       
]       
                
let event = Ecommerce(orderId: transactionID, totalValue: 350, items: itemArray)   
    .affiliation("DemoTransactionAffiliation")
    .taxValue(10)
    .shipping(15)
    .city("Boston")
    .state("Massachisetts")
    .country("USA")
    .currency("USD")

tracker.track(event)

Push and Local Notification

To track an event when a push (or local) notification is used, it is possible to use the MessageNotification event:

let event = MessageNotification(title: "title", body: "body", trigger: .push)
    .notificationTimestamp("2020-12-31T15:59:60-08:00")
    .action("action")
    .bodyLocKey("loc key")
    .bodyLocArgs(["loc arg1", "loc arg2"])
    .sound("chime.mp3")
    .notificationCount(9)
    .category("category1")
    .attachments([
        MessageNotificationAttachment(identifier: "id", type: "type", url: "https://snowplowanalytics.com")
    ]);
tracker.track(event)

Deep Link

The Deep Link is received by the mobile operating system and passed to the related app. Our mobile tracker can’t automatically track the Deep Link, but we provide an out-of-the-box event that can be used by the developer to manually track it as soon as the Deep Link is received in the app.

It will be the duty of the tracker to automatically attach the information of the Deep Link to the first ScreenView tracked.

In practice, when the app receives a Deep Link the developer can track it through the DeepLinkReceived event:

public func application(_ application: UIApplication,
                        continue userActivity: NSUserActivity,
                        restorationHandler: @escaping ([Any]?) -> Void) -> Bool
{
    ...
    if let url = userActivity.webpageURL {
        let deepLinkEvent = DeepLinkReceived(url: userActivity.webpageURL.absoluteString)
            .referrer(userActivity.referrerURL.absoluteString)
        tracker.track(deepLinkEvent)
    }
    ...
}

The tracker keeps memory of the tracked Deep Link event and will attach a Deep Link entity to the first ScreenView tracked in the tracker. This is helpful during the analysis of the data because it will be clear the relation between the content visualized by the user (ScreenView event) and source (DeepLink entity) that originated that visualisation.

This behaviour is enabled by default but it can be disabled from the TrackerConfiguration.

For example:

let trackerConfig = TrackerConfiguration()
    ...
    .deepLinkContext(false)
    ...

The DeepLinkReceived event can be used in pair with a campaign-attribution-enrichment appropriately enabled in the Snowplow pipeline. It works exactly like for PageView events in the web/JS tracker. When the user taps on an advertising banner or a marketing email or message, it can trigger the launch of the app through the Deep Linking feature. The referral from the advertising campaigns, websites, or other source can be composed by UTM parameters used to attribute the user activity back to the campaign. The Campaign Attribution Enrichment can parse the DeepLinkReceived event extracting the UTM parameters in the deep link url.

The mobile trackers capture two types of events, automatically captured and manual events.

Auto Tracking

Automatically captured events in the Android Tracker are:

  • App Lifecycle Tracking: Captures application foreground and application background events.
  • Screen View Tracking: Captures each time a new “screen” is loaded.
  • Exception Tracking: Captures any unhandled exceptions within the application.
  • Installation Tracking: Captures an install event which occurs the first time an application is opened.

These are enabled in the tracker configuration. In this example, some helpful automatic contexts and all Autotracking is enabled:

TrackerConfiguration trackerConfiguration = new TrackerConfiguration(appId)       
    .sessionContext(true)
    .platformContext(true)
    .applicationContext(true)
    .screenContext(true)
    .lifecycleAutotracking(true)
    .screenViewAutotracking(true)
    .exceptionAutotracking(true)
    .installAutotracking(true);

Session Context

Client session tracking is activated by default but it can be disabled through the TrackerConfiguration as explained above. When enabled the tracker appends a client_session context to each event it sends and it maintains this session information as long as the application is installed on the device.

Sessions correspond to tracked user activity. A session expires when no tracking events have occurred for the amount of time defined in a timeout (by default 30 minutes). The session timeout check is executed for each event tracked. If the gap between two consecutive events is longer than the timeout the session is renewed. There are two timeouts since a session can timeout in the foreground (while the app is visible) or in the background (when the app has been suspended, but not closed).

The lifecycle events (application_foreground and application_background events) have a role in the session expiration. The lifecycle events can be enabled in the TrackerConfiguration enabling lifecycleAutotracking (Note: on Android it requires androidx.lifecycle:lifecycle-extensions). Once enabled they will be fired automatically when the app moves from foreground state to background state and vice versa.

When the app moves from foreground to background the application_background event is fired. If session tracking is enabled, the session context will be attached to the event checking the session expiration using the foreground timeout. When the app moves from background to foreground the application_foreground event is fired. If session tracking is enabled, the session context will be attached to the event checking the session expiration using the background timeout.

For instance, with this configuration:

new SessionConfiguration(
    new TimeMeasure(360, TimeUnit.SECONDS),
    new TimeMeasure(15, TimeUnit.SECONDS)
)

the session would expire if the app is backgrounded for more than 15 seconds, like in this example:

time: 0s - screen_view event - foreground timeout session check - session 1
time: 3s - application_background event - foreground timeout session check (3 < 360) - session 1
time: 30s - application_foreground event - background timeout session check (30 > 15) - session 2

In the above example the application_foreground event triggers a new session because the time spent on background (without tracked events) is bigger than the background timeout for the session.

Session callback

(Available from v3.1)

The tracker allows the configuration of a callback to inform the app everytime a new session is created (in correspondence of a session timeout check). This can be configured in the SessionConfiguration and it provides the SessionState where can be accessed all the info already tracked in the SessionContext.

Below an example of where the session callback is used to print out the values of session every time a new session is generated by the tracker:

...
SessionConfiguration sessionConfig = new SessionConfiguration(
                new TimeMeasure(6, TimeUnit.SECONDS),
                new TimeMeasure(30, TimeUnit.SECONDS)
        )
                .onSessionUpdate(state -> log("Session: " + state.getSessionId()));
...
Snowplow.createTracker(getApplicationContext(),
                namespace,
                networkConfiguration,
                sessionConfiguration
);

Custom Event Context

Custom context can be used to augment any standard Snowplow event type, including self describing events, with additional data. We refer to this custom context as Event Entities.

Each custom context is an array of self-describing JSON following the same pattern as a self describing event. As with self describing events, if you want to create your own custom context, you must create a JSON schema for it and upload it to an Iglu repository using the Snowplow BDP Console UI, Data Structures API, igluctl or one of the other supported Iglu clients.

Note: Even if only one custom context is being attached to an event, it still needs to be wrapped in an array.

Here are two example custom context JSONs. One describes a screen:

{
    schema: 'iglu:com.example/screen/jsonschema/1-2-1',
    data: {
        screenType: 'test',
        lastUpdated: '2021-06-11'
    }
}

and the other describes a user on that screen:

{
    schema: 'iglu:com.example/user/jsonschema/2-0-0',
    data: {
      userType: 'tester'
    }
}

Tracking events with Custom Context

How to track a screen view with both of these contexts attached:

ScreenView event = new ScreenView("screen", UUID.randomUUID().toString());         

event.customContexts.add(
    new SelfDescribingJson("iglu:com.example/screen/jsonschema/1-2-1",                         
        new HashMap() {{
            put("screenType", "test");
            put("lastUpdated", "2021-06-11");
        }})
);

event.customContexts.add(
    new SelfDescribingJson("iglu:com.example/user/jsonschema/2-0-0",                         
        new HashMap() {{
            put("userType", "tester");
        }})
);

tracker.track(event);

It is also possible to add contexts in a declarative way, so that they are applied to all (or a subset of) events within an application.

Manual Tracking

Self Describing

You may wish to track events in your app which are not directly supported by Snowplow and which structured event tracking does not adequately capture. Your event may have more than the five fields offered by Structured events, or its fields may not fit into the category-action-label-property-value model. The solution is Snowplow’s self-describing events. Self-describing events are a data structure based on JSON Schemas and can have arbitrarily many fields.

To define your own custom event, you must create a JSON schema for that event and upload it to an Iglu Schema Repository using igluctl (or if a Snowplow BDP customer, you can use the Snowplow BDP Console UI or Data Structures API). Snowplow uses the schema to validate that the JSON containing the event properties is well-formed.

Map properties = new HashMap();
properties.put("targetUrl", "http://a-target-url.com");
SelfDescribingJson sdj = new SelfDescribingJson("iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1", attributes);

SelfDescribing event = new SelfDescribing(sdj);

tracker.track(event);

A Self Describing event is a self-describing JSON. It has two fields:

  • A data field, containing the properties of the event
  • A schema field, containing the location of the JSON schema against which the data field should be validated.

Structured

Our philosophy in creating Snowplow is that users should capture important consumer interactions and design suitable data structures for this data capture. You can read more about that philosophy here. Using trackSelfDescribingEvent captures these interactions with custom schemas, as desribed above.

However, as part of a Snowplow implementation there may be interactons where custom Self Describing events are perhaps too complex or unwarranted. They are then candidates to track using Structured, if none of the other event-specific methods outlined below are appropriate.

Structured event = Structured("my-category", "my-action")
    .label("my-label")
    .property("my-property")
    .value(5);

tracker.track(event);

Timing

Use the Timing events to track user timing events such as how long resources take to load.

Timing event = new Timing("timing-category", "timing-variable", 5)
    .label("optional-label");
                
tracker.track(event);

Screen View

Track the user viewing a screen within the application. This type of tracking is typically used when automatic screen view tracking is not suitable within your application.

ScreenView event = new ScreenView("screen", UUID.<em>randomUUID</em>().toString());

tracker.track(event);

Consent

Consent Granted

Use the ConsentGranted event to track a user opting into data collection. A consent document context will be attached to the event using the id and version arguments supplied.

ConsentGranted event = new ConsentGranted("2018-05-08T18:12:02+00:00", "doc id", "1.2")
        .documentDescription("doc description")
        .documentName("doc name");

tracker.track(event);

Consent Withdrawn

Use the ConsentWithdrawn event to track a user withdrawing consent for data collection. A consent document context will be attached to the event using the id and version arguments supplied. To specify that a user opts out of all data collection, all should be set to true.

ConsentWithdrawn event = new ConsentWithdrawn(true, "doc id", "1.2")
        .documentDescription("doc description")
        .documentName("doc name");

tracker.track(event);

Ecommerce Transaction

Modelled on Google Analytics ecommerce tracking capability, Snowplow uses three steps that can be used together to track online transactions:

  1. Create a Ecommerce event. Use Ecommerce to initialize a transaction object. This will be the object that is loaded with all the data relevant to the specific transaction that is being tracked including all the items in the order, the prices of the items, the price of shipping and the order_id.

  2. Add items to the transaction. Create an array of EcommerceItem to pass to the Ecommerce object.

  3. Submit the transaction to Snowplow using the track() method, once all the relevant data has been loaded into the object.

EcommerceTransactionItem item = new EcommerceTransactionItem("sku-1", 35.00, 1)
    .name("Acme 1")
    .category("Stuff")
    .currency("USD");
List items = new LinkedList();
items.add(item);

EcommerceTransaction event = new EcommerceTransaction("order-1", 40.00, items)
    .shipping(5.00);

tracker.track(event);

Push and Local Notification

To track an event when a push (or local) notification is used, it is possible to use the MessageNotification event:

MessageNotification event =
    new MessageNotification("title", "body", MessageNotificationTrigger.push)
                .notificationTimestamp("2020-12-31T15:59:60-08:00")
                .action("action")
                .bodyLocKey("loc key")
                .bodyLocArgs(Arrays.asList("loc arg1", "loc arg2"))
                .sound("chime.mp3")
                .notificationCount(9)
                .category("category1");
tracker.track(event);

Deep Link

The Deep Link is received by the mobile operating system and passed to the related app. Our mobile tracker can’t automatically track the Deep Link, but we provide an out-of-the-box event that can be used by the developer to manually track it as soon as the Deep Link is received in the app.

It will be the duty of the tracker to automatically attach the information of the Deep Link to the first ScreenView tracked.

In practice, when the app receives a Deep Link the developer can track it through the DeepLinkReceived event:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    // Extract info from Intent
    Intent intent = getIntent();
    String deepLinkUrl = intent.getData().toString();
    String referrer = null;
    Bundle extras = intent.getExtras();
    if (extras != null) {
        Uri referrerUri = extras.get(Intent.EXTRA_REFERRER);
        if (referrerUri != null) {
            referrer = referrerUri.toString();
        }
    }
    // Create and track the event
    DeepLinkReceived event = new DeepLinkReceived(deepLinkUrl).referrer(referrer);
    tracker.track(event);

    ...
}

The tracker keeps memory of the tracked Deep Link event and will attach a Deep Link entity to the first ScreenView tracked in the tracker. This is helpful during the analysis of the data because it will be clear the relation between the content visualized by the user (ScreenView event) and source (DeepLink entity) that originated that visualisation.

This behaviour is enabled by default but it can be disabled from the TrackerConfiguration.

For example:

TrackerConfiguration config = new TrackerConfiguration()
    ...
    .deepLinkContext(false)
    ...

The DeepLinkReceived event can be used in pair with a campaign-attribution-enrichment appropriately enabled in the Snowplow pipeline. It works exactly like for PageView events in the web/JS tracker. When the user taps on an advertising banner or a marketing email or message, it can trigger the launch of the app through the Deep Linking feature. The referral from the advertising campaigns, websites, or other source can be composed by UTM parameters used to attribute the user activity back to the campaign. The Campaign Attribution Enrichment can parse the DeepLinkReceived event extracting the UTM parameters in the deep link url.

If you’d like to learn more about Snowplow BDP you can book a demo with our team, or if you’d prefer, you can try Snowplow technology for yourself quickly and easily.