Native Collector API v3

In Summer 2023, we introduced a new major version of our iOS and Android collectors (v3). This doc describes the changes in this release.
Specific migration guides for each platform can be found here: iOS, Android

Why did we introduce a new major version?

We wanted to improve our API in the following ways:

  1. Provide a clear separation of config and metadata
  2. Streamline collector behaviour in iOS and Android
  3. Use more intuitive field and method names
  4. Remove unnecessary configs and metadata fields

Each of these is described in more detail below.

Clear separation of config and metadata

Our v2 API lacked a clear separation of config and metadata. This made it cumbersome to use since the config doesn't change much over the lifetime of a collector but the metadata does. With v3 we've introduced a clear separation between metadata and config.

Config

The config object AnalyticsConfig contains the analytics license key and config fields that determine the collector behaviour. It doesn't contain any metadata to enrich analytics data itself.

Metadata

Metadata is split into the objects DefaultMetadata and SourceMetadata

DefaultMetadata holds metadata that is source independent and doesn't change after creation of the collector (e.g.: customUserId, app version)

SourceMetadata holds source related metadata that is only relevant for a specific source (e.g.: title, videoId, genre)

Both have a customData object which allows for arbitrary data to be collected together with each sample.
If the same field (e.g. customData1) is specified in SourceMetadata and DefaultMetadata, SourceMetadata takes precedence. All customData fields are merged on a field basis, with SourceMetadata taking higher priority.

Streamline collector behaviour in iOS and Android

Our v2 API had some inconsistencies in field names and default behaviour when comparing iOS and Android.
For example, on iOS, ad tracking is disabled by default, while it's enabled by default on Android.
This behaviour was unified with v3.

More intuitive field and method names

API v2 has some confusing method names (e.g.: setCustomDataOnce) which we tried to make easier to understand (e.g.:sendCustomDataEvent). The same applies for some field names ( e.g.: tryResendDataOnFailedConnection is now RetryPolicy.SHORT_TERM).

Remove unnecessary configs and metadata fields

API v2 has deprecated configs like playerKey, heartbeatInterval which are not part of the new AnalyticsConfig to simplify setup.

With v3 we also removed some Metadata fields like playerType, m3u8Url or mpdUrl since they can be autodetected in most cases.

Behavioural changes compared to v2

CustomData is merged on a field level

If customData is specified in DefaultMetadata and SourceMetadata, SourceMetadata takes precedence. With the v3 API, this is done at the field level and not on the whole CustomData object anymore.

The example below illustrates how this works:

val customData1 = CustomData(customData1 = "appVersion1", customData2 = "exampleData")
val defaultMetadata = DefaultMetadata(customData = customData1)
val customData2 = CustomData(customData2 = "sourceData1", customData3 = "exampleGenre")
val sourceMetadata = SourceMetadata(title = "exampleTitle", customData = customData2)

// when the defaultMetadata is set and the sourceMetadata is active for the current source
// the resulting CustomData that is sent to the back end will look like this
CustomData(customData1 = "appVersion1", customData2 = "sourceData1", customData3 = "exampleGenre")

sendCustomDataEvent is merged with CustomData

With API v2 only the CustomData that was given as a parameter to the sendCustomDataEvent (or setCustomDataOnce) method was sent to the backend.
Using the v3 API, the CustomData that is specified as parameter is merged with the CustomData that is sent with the current source. The specified CustomData takes precedence and it's merged on a field-level.

Player-specific changes

ExoPlayer error tracking changed

The errorCodes reported are using the actual errorCodes as reported by ExoPlayer, instead of the error types. This allows for more specific error tracking and helps with debugging.