1. Home
  2. Blog
  3. Releases
Engineering, Releases

Modernising the mobile trackers: version 5 is here

We’re very excited to announce the version 5 of our mobile trackers for Android and iOS. The major enhancement is the modernization of the trackers – we migrated the iOS tracker code base from Objective-C to Swift, and Android from Java to Kotlin. The trackers got a couple of brand new features too!

Act on events with tracker plugins

The new tracker plugins architecture, based around the PluginConfiguration class, allows you to intercept events and run callbacks.

  • The entity closure allows you to attach an entity just before an event is tracked. You can choose to add the entity to all events, or just events of a certain type.
  • The afterTrack closure lets you inspect tracked events and act based on their properties and entities. It’s called when the event is handed over to the EventStore for buffering and processing into a request. So, once the event has been tracked, but before it’s been sent.

Here’s how it works on Android (it’s very similar on iOS):

// Create a new PluginConfiguration with a unique identifier 

val plugin = PluginConfiguration(“myPlugin”)

// Use the entities closure to attach entities to events

// This plugin will add an entity based on the “iglu:xx” schema

// to events based on the “iglu:abc” schema only

plugin.entities(schemas = listOf(“iglu:abc”)) {

    listOf(SelfDescribingJson(“iglu:xx”, hashMapOf(“property” to true)))


// The afterTrack callback is called on a background thread to inspect tracked events

// Here, a message is printed for every event tracked based on the “iglu:yy” schema

plugin.afterTrack(schemas = listOf(“iglu:yy”)) {

    print(“Tracked event with ${it.entities.size} entities”)


// The plugin can be supplied to the tracker as a configuration on creation

val tracker = Snowplow.createTracker(

    context = context,

    namespace = “namespace”,

    network = networkConfig,


  // multiple PluginConfiguration can be provided!


// Alternatively, add plugins like this


// You can inspect the enabled plugins and get the list of their identifiers

val pluginIdentifiers = tracker.plugins.identifiers

// Finally, remove registered plugins by their identifiers


Some of the existing tracker functionality, such as the Global Contexts API for adding entities, is now based on plugins behind the scenes.

By the way, the tracker allows you to provide other closures too. Check out the requestCallback option, set in EmitterConfiguration, to act on counts of successful or unsuccessful event sending. There’s also the SessionConfiguration.onSessionUpdate configuration that, as the name suggests, is a callback for every time the user session is updated.

Screen view tracking in SwiftUI and Jetpack Compose

One of the benefits of the language migration is support for the newer UI frameworks: SwiftUI on iOS and Jetpack Compose for Android. This is particularly important in tracking screen views. Both mobile trackers aim to automatically track an event every time a new screen loads – this default behaviour is set by the TrackerConfiguration.screenViewAutotracking property.

On iOS, the tracker detects and tracks the loading of UIKit Views by swizzling the ViewController.viewDidAppear method. SwiftUI views are not detected, so the autotracking doesn’t work! It’s a similar story for Android, where the tracker uses the Application.ActivityLifecycleCallbacks interface. Screens in Compose apps use composable functions, not Activities. Unfortunately, we haven’t been able to replicate the fully automatic tracking for the new frameworks: the architecture doesn’t support that.

Instead, for the v5 iOS tracker, we’ve created a snowplowScreen annotation for SwiftUI apps. It’s an extension of View. Call snowplowScreen on every View you want tracked.

import SwiftUI

struct ProductList: View {

    var body: some View {

        List {



        // This View extension will track a screen view event when it loads

        .snowplowScreen(name: "ProductList")



It’s also possible to attach one or more context entities to the screen view, by providing them as a list to snowplowScreen. While the plugins feature is for general entity addition, this is the opposite – giving you fine control over adding specific entities to a specific screen view. For example, a product detail entity for a product page.

On Android, because Jetpack Compose is so flexible as to how apps are constructed, there’s no obvious single view component to extend in the same way. We suggest adding a listener to the Navigation component, using the NavController.addOnDestinationChangedListener callback. This code will track a screen view every time the navigation destination changes. The screen name will be the name of the destination (without argument parsing).

fun autoTrackScreenView(navController: NavController) {

    navController.addOnDestinationChangedListener { _, destination, _ ->

        Snowplow.defaultTracker?.track(ScreenView(destination.route ?: "null"))



This solution unfortunately doesn’t provide the same kind of control as the SwiftUI snowplowScreen. For specific addition of entities to certain screens, we recommend manually tracking the screen view on a screen-by-screen basis.

We’d love to hear how you instrument your iOS and Android trackers! Chat to us on Discourse.

Upgraded documentation

All the iOS and Android documentation has been overhauled and improved. We’ve made the main Snowplow docs easier to use, and the trackers have new API docs (Android; iOS).

Both trackers have new demo apps! We’ve created very simple SwiftUI and Jetpack Compose apps to show how to instrument the trackers and track events in those frameworks. The demo apps use the Iglu Server API to show all the publicly available Iglu schemas.

For Android, we provide demo apps in Kotlin, Java, and Kotlin with Jetpack Compose. They’re all part of the main Android tracker repository. For iOS, we now provide demo apps in Swift with SPM or Cocoapods, Objective-C with Cocoapods, and Swift with SwiftUI. Find all these demos in the Examples submodule in the iOS tracker repository.

Let us know what you think

We hope you enjoy using the v5 mobile trackers. Please let us know your thoughts! We’ve kept API changes to a minimum, but check out the migration guide to be sure.

More about
the author

Miranda Wilson
Miranda Wilson

Miranda is a junior software engineer in the Snowplow tracker SDKs team. She has worked mainly with Java and Ruby and is excited about learning new coding languages.

View author

Ready to start creating rich, first-party data?

Image of the Snowplow app UI