The iOS Topspin library is a Swift project that can be integrated as a Cocoapod or as a framework.

Quick start

The project can be integrated as a cocoapod by putting the following line in the Podfile:

pod 'Topspin', :git => ''

If you want to send analytics to AT Internet as well, you’ll need to include the AT Internet plugin cocoapod as well:

pod 'TSAtInternet', :git => ''

In order to install a specific version of the app instead of the latest version, the following line can be used instead:

pod 'Topspin', :git => '', :tag => '1.6.0'
pod 'TSAtInternet', :git => '', :tag => '1.6.0'

Integration into your iOS app

Create a TSTopspin and TSDivoltePlugin instance by using a configured TSTopspinFactory object:

TSTopspinFactory* factory = [[TSTopspinFactory alloc] init];
TSDivoltePlugin* divolte = [[TSDivoltePlugin alloc] initWithEnvironment:TSDivolteEnvironmentTypeDevelopment];
TSTopspin* topspin = [factory buildWithPlugins:@[divolte]];
TSPageLabels* labels = [topspin pageLabels];

[labels setMerkId:@(9)];
[labels setMerk:@"topspin-demo"];
[labels setPlatform:TSPlatformTypeApp];
[labels setMerkType:TSMerkTypeStandalone];
[labels setPlatformVersie:@"1.0"];

In order to include the AT Internet plugin as well, import the TSAtInternet framework and define the plugin like this:

TSAtInternetPlugin* atInternet = [[TSAtInternetPlugin alloc] initWithEnvironment:TSAtInternetEnvironmentDevelopment];
TSTopspin* topspin = [factory buildWithPlugins:@[divolte, atInternet]];

To disable logs, put:

[TSTopspin enableLogs:NO];

To register the app to automatically send app-lifecycle events:

[topspin registerAppLifecycle];

This creates a Topspin client with all default settings. The first time it’s used, it will generate a Divolte partyId and ATInternet nmoPanelID and store it in the standard user defaults. Upon subsequent use, it will load these IDs from the user defaults. Several customisations options exist, explained below.

For testing purposes it might be useful to disable network calls. The following code will do just that:

[[TSTopspin sharedInstance] disableNetworkCalls:YES];

Tracking events

A tracker must be created to track events:

// age view, inheriting global labels from app
TSTracker* tracker = [[TSTopspin sharedInstance] createNewTracker];
// set required labels for a page
TSPageLabels* labels = [tracker pageLabels];
[labels setNiveau1:@"start"];
[labels setPagina:@"home"];

To send an page/content view event:

// perform actual pageview
[[tracker contentView] setReferrer:@"homescreen"];
[[tracker contentView] send];

Media streams

To track streaming events first make a tracker and send streaming events as follows:

- (void)startPlayback {
	_streamTracker = [_tracker streamForMID:@"KNO_2308383"];
    [_streamTracker load];

    // when the video starts:
    [_streamTracker start:0];

- (void)pause {
    [_avPlayer pause];
    CMTime position = [_avPlayer currentTime];
    [_streamTracker pause:CMTimeGetSeconds(position)];

A real-world player would add various callbacks to the player which call the corresponding methods on the StreamRecorder.


Following the general Topspin design, there are three types of recommendations: editorials, recommendations and searches. For each of the types, a specific tracker can be created from your main TSTracker object.

For detailed information about recommendation fields, see the general Topspin documentation for recommendations.


To add NPO user profile data to the gathered analytics, call [_tracker login] and [_tracker logout] when appropriate. The login data is not stored by the library, and must be properly set each time the library is initialized.

After a login call, all events will contain a reference to the profile.


Since version 1.7.3, a random nmoPanelID is generated. This is automatically send to ATInternet (if enabled) as custom var 17. You can get this parameter on the main Topspin object: topspin.nmoPanelID. This ID is used for panel identification purposes.


Both the Divolte partyID and ATInternet nmoPanelID are tracked in the standard user defaults in a dictionary that is set for the key npo_divolte. If you want to change the key name, you can do so like this:

TSTopspinFactory* factory = [[TSTopspinFactory alloc] init];
factory.preferencesName = @"examplePreference";
TSTopspin* topspin = [factory build];

If you want to disable our use of the standard user defaults entirely, this is also possible:

TSTopspinFactory* factory = [[TSTopspinFactory alloc] init];
factory.preferencesName = TSPreferencesDisabled;
TSTopspin* topspin = [factory build];

Note: you will want a persistent partyId and nmoPanelID across tracking events from any one app instance. If you disable user defaults storage, you should implement an alternative way to store and load both IDs for reuse. If you don’t provide one, the API client will generate both Ids each time it is built. You can obtain the current Ids from a Topspin instance using the partyId and nmoPanelID properties.

Sending IDFV to Mediapanel app

As of version 1.7.0, the Topspin SDK provides a helper method to send the IDFV (Identifier For Vendor, as retrieved by [[[UIDevice currentDevice] identifierForVendor] UUIDString]) to the Mediapanel app. This method can be called by +[TSTopspin sendIdfvToPanelAppForBundleId:] and should be called from -[AppDelegate applicationDidBecomeActive:]. The function then opens the Mediapanel app in the following cases:

  • If the IDFV has not been succesfully sent to the Mediapanel app before
  • If the IDFV has changed
  • Periodically:
    • Once a week after calling it first
    • Once a month after that

The Mediapanel app is then opened by calling finPanelApp://&from={bundleId}&pifv={idfv-hashed}&ispanel=1. Please note that if this app is not installed, nothing will happen.


  • Add the finPanelApp scheme to your Info.plist as item in the LSApplicationQueriesSchemes array. This allows your app to open the finPanelApp scheme, which is registered to the Mediapanel app.
  • Keep the following keys free in your UserDefaults. The helper method doesn’t work correctly if any of the following keys are used by your app:
    • IDFVKey: The last send IDFV is stored in here
    • IDFVFirstTriggerDateKey: The date when the IDFV is sent first to the Mediapanel app
    • IDFVLastTriggerDateKey: The date when the IDFV is most recently sent to the Mediapanel app
  • Call +[TSTopspin sendIdfvToPanelAppForBundleId:] from -[AppDelegate applicationDidBecomeActive:] and pass the bundleId of your app.

Supported iOS versions

This library was build for iOS 8 and up.

Demo App

The Topspin Demo project is an iOS app that uses the Topspin client library to demonstrate its code integration.

Update instructions

To version 1.6.0

These instructions only apply when you use the TSAtInternetPlugin and you’re using [[ATInternet sharedInstance] defaultTracker]. As of 1.6.0, the TSAtInternetPlugin uses a custom Tracker instead of the default Tracker. As a result, the default Tracker is no longer configured by TSAtInternetPlugin and needs to be configured manually. You can get this configuration through -[TSAtInternetPlugin topspinConfiguration].

To version 1.5.3

Only if you include the AT Internet plugin, you’ll need to follow the following steps:

  1. Add the TSAtInternet pod to your podfile: pod ‘TSAtInternet’, :git => ''
  2. Import the framework to your code: #import <TSATInternet/TSAtInternet.h>

To version 1.5.2

  1. Change Topspin initialisation code to match the code fragment above. For this library version, you’ll need to specify which plugins (backends) to use.
  2. If you use the AT Internet plugin, make sure to include the AT Internet pod: ‘ATInternet-Apple-SDK/Tracker’
  3. Change/rename the app’s base label set to match the new page labels.
  4. Change the per-page labels to match the new page label names.

To version 1.2.0:

  1. Add code to the app-wide Topspin initialisation code:

    [topspin registerAppLifecycle];
  2. Use [_tracker editorials], [_tracker search] and [_tracker push] to create trackers for editorials, search queries and push messages.

  3. Use [TSStreamTracker streamExternal:deviceType] when playback switches to an external playback device, like Chromecast.

Change Log

Version 1.7.3

  • ATInternet: added nmoPanelId property on Topspin which is sent as custom var 17.

Version 1.7.1

  • Fix bug where errors where showing up in the logs about passing a nil reference to a Calendar function.
  • Add functions to enable ATInternet offline hits. Disabled by default (as it already was).

Version 1.7.0

  • Add the noboVendorId property to the page labels. This version is sent to ATInternet as custom variable x16
  • Add helper method to periodically send the IDFV to the Mediapanel app. See Sending IDFV to Mediapanel app

Version 1.6.1

  • Fixed a bug where the environment (also known als the Level1-ID) was not correctly sent to AT Internet (this bug was introduced in 1.6.0).

Version 1.6.0

  • TSAtInternetPlugin no longer uses the default Tracker but creates a custom one. Please check the update instructions for more information.

Version 1.5.5

  • AT Internet: remove userId from AT Internet attributes
  • AT Internet: remove preprod environment
  • AT Internet: use category ‘3’ for anonymous visitors

Version 1.5.4

  • Update AT Internet configuration (pixelPath, identifier)

Version 1.5.3

  • The AT Internet plugin is now distributed in a separate project: TSAtInternet. This project can also be included by adding pod TSAtInternet to your Podfile.

Version 1.5.2

  • Plugin architecture [TAS-23]
  • Added: AT Internet plugin
  • Fix various namings in Divolte backend

Version 1.2.1, March 9, 2018

  • Fixed rare crash when submitting Topspin events [TIS-23]
  • Update TSConverter and TSDeviceData to support tvOS (by Johan Kool)

Version 1.2.0, September 27, 2017

  • Add editorials tracker [TIS-2]
  • Add app start/stop events [TIS-4]
  • Add search tracker [TIS-5]
  • Add push messages tracker [TIS-13]
  • Stream recorder: add event for external playback [TIS-14]

Version 1.1.0, March 23, 2017

  • Add recommendations
  • Add login/logout

Version 0.1.0, November 21, 2016

  • First release of iOS port of Android version