Initial SDK setup

Install using Cocoapods

If you want to use Cocoapods to manage your external dependencies, simply add the following line to your Podfile:

pod 'FollowApps'

If you don't have a podfile yet, open a console and do a pod init in your project directory.

Then, you only need to update your cocoapods dependencies:

pod install

Using a local version of the Pod

If you'd rather have the file locally, download the SDK, copy the FollowApps/ directory located in Pod/ to your Xcode project root directory and use the following line in your Podfile: pod 'FollowApps', :path => "FollowApps"

Initialize with your API key

Prepare your API key

Be sure to have your API key for this step of the configuration. If you are not sure where to find it, please reach out to your Customer Success Manager or message

To initialize the SDK, you need to call the configureWithId method on it, and pass it your API key.

To do so:

  1. Import the <FollowApps/FAFollowApps.h>, in your AppDelegate.h file if you use Objective-C, or in your Bridging-Header.h file in Swift.

    What if I don't have a bridging header file?

    • Create a new Objective C file in your project (File->New->File[Objective C for iOS]).
    • Accept the prompt (agree) to create a bridging header file between Objective C and Swift.
    • Delete your newly created Objective C file but keep the bridging header file ${YOURPROJ}-Bridging-Header.h.
  2. Add the FollowAppsDelegate protocol to your AppDelegate, and configure the SDK using the configureWithId method:


    // in AppDelegate.h
    @interface AppDelegate : UIResponder <FAFollowAppsDelegate>
    // in AppDelegate.m
    [FAFollowApps configureWithId:@"API_KEY_STRING" debugStateOn:FADEBUG options:launchOptions];


    class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        FAFollowApps.configureWithId("API_KEY_STRING", debugStateOn:true/false, options:launchOptions)

    The switch between debug and release mode is not automatic in Swift

    • When developing your app, use debugStateOn: true to avoid sending irrelevant logs to the production server, and to see debugging information in the XCode console
    • Before publishing the app, make sure the debug state is OFF (debugStateOn: false).

Define the URL scheme

To allow users to retrieve their device ID for campaign testing and tagging plan debugging, declare a URL Scheme in the info tab of your Xcode project using the bundleId of your app as URL Scheme:

URL Scheme

Make sure that the bundle ID of your app appears in the URL Schemes field as shown in the screenshot (where com.follow-apps.followme.inHouse needs to be replaced).

Once configured, your FA device ID can be obtained by opening the following URI: xxx://, where xxx shall be replaced by the application bundle identifier (com.follow-apps.followme.inHouse in the example above).

FA users can request, from the product interface, that an e-mail message containing this link be sent to their device to facilitate the operation.

Register for notifications

If your app code is already registered to send push notifications, nothing to do here. Otherwise, simply add a call to registerForPush anytime after you have configured the SDK:


[FAFollowApps configureWithId:@"API_KEY_STRING" debugStateOn:FADEBUG options:launchOptions];
[FAFollowApps registerForPush];


FAFollowApps.configureWithId("API_KEY_STRING", debugStateOn: true/false, options: launchOptions)

UserNotifications framework

Reminder: when using the UserNotification framework, you must implement the method bellow to handle the push received (only in foreground), otherwise your app will crash.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler

Then, to ensure FollowAnalytics can detect uninstalls, activate the Silent Notifications capabilities in the capabilities tab of your Xcode Project, by clicking the Remote Notifications box under Background Modes:

There is nothing else to do, FollowAnalytics will handle its own notifications and you will still receive yours, as long as you compile with the appropriate Push certificates, and provide FollowAnalytics with the required .pem file. To generate the pem push certificate required for FollowAnalytics, you can follow the Certificates section in this tutorial.

Don't miss your only shot!

You only get to ask a user once if they accept to receive push notifications from your app.

Try not to register for push notifications without telling the user why you offer this feature. When one knows what to expect, they are more likely to opt-in.

You could even build your own pre-question, asking the user if they'd like to be notified. Should they say yes, only then register for the push notifications. If you do so, don't forget to still call the registerForPush method every now and then to ensure the push token is sync'ed with the FollowAnalytics servers.

Conflict with Notification Categories

If you register interactive notification categories and use our registerForPush method, make sure you register categories after calling registerForPush.


The SDK has a Validator that will ensure that everything is properly configured.

When your app is running in debug mode, a popup is shown at launch with the details of what is properly configured, and what is not. This makes it easier for you to validate that the various steps were performed properly.

Crash reporting test

To be able to validate that the crash configuration is working properly, you will have to launch your app once without the debugger, i.e. manually on the device or from the simulator, without using the "run" button in Xcode.

Validator description

To know more about what the validator checks and how, please refer to its dedicated page.


Data sent in debug mode will not appear on dashboards

When your app runs in DEBUG mode or in a simulator, the data is automatically sent as development logs, and is therefore not processed to be shown on the main UI page. DEBUG logs can be checked using the method given in the FAQ section.

See related entry in FAQ for more information on debug & release modes.

Logging best practices

To ensure your tags are relevant and will end up empowering your team through FollowAnalytics, please read the Logging best practices entry in the FAQ section.

Events vs Attributes

The FollowAnalytics SDK allows you to tag both events and attributes. If you are unsure about the difference, please refer to the corresponding FAQ entry.

Tag events

Regular, native event logging

The SDK allows you to log events happening in your code. These are the two methods you can call on the SDK:


+ (BOOL)logEventWithName:(NSString *)name details:(id)details;
+ (BOOL)logErrorWithName:(NSString *)name details:(id)details;


FAFollowApps.logEventWithName(name: String!, details: AnyObject!)
FAFollowApps.logErrorWithName(name: String!, details: AnyObject!)

Use the name as the unique identifier of your tag, use the details section to add specific details, context. Events can be renamed later: the name that you give to your event here can be overridden in the FollowAnalytics UI.

The details field can either be a String or a Hash, so that you can associated multiple key-values for additional context.

For instance, logging the appearance of a view could be done the following ways:


[FAFollowApps logEventWithName:@"Product view" details:@"Product reference"];
[FAFollowApps logEventWithName:@"In App purchase completed" details:@"Full pack"];

NSDictionary *detail_dictionary = @{ key_1: obj_1, key_2 : obj_2, key_3 : obj_3};
[FAFollowApps logEventWithName:@"Example log name" details:detail_dictionary];


FAFollowApps.logEventWithName("product view", details: "Product reference")
FAFollowApps.logErrorWithName("In App purchase completed", details: "Full pack")

let detail_dictionary:NSDictionary = [key_1: obj_1, key_2: obj_2, key_3: obj_3]
FAFollowApps.logEventWithName("Example log name", details: detail_dictionary)

In debug mode, the SDK will acknowledge the saving by writing in the console whatever it receives.

If the parameters sent to these methods are over 60Kb, the method will refuse them, return NO, and write a message in the console if it is running in debug mode.

Logging from a web view

If you happen to use a web view to display elements of your app, you can also tag events and errors from within your HTML/JS code. To do so:

  1. Make sure you use the FAWebView, both in your .h file and your .xib or Storyboard, instead of the regular UIWebView. For the latter, you need to set the Custom Class parameter of your UIWebView to FAWebView in the Identity Inspector.

  2. Use the provided FAWebView.js in your web page code to save events. For instance, you could do:

    <a href="#" onclick="FALogEvent('My event', 'My event details')">Log an event</a>
    <a href="#" onclick="FALogError('My error', '')">Log an error</a>
    <a href="#" onclick="FALogEvent('My event', {'hello': 'Hi', 'How are you': 'good!'})">Log an event with hash</a>
  1. In case you want to register for push through a webview, you need to call FARegisterForPush(), like for instance: <a href="#" onclick="FARegisterForPush()">register for push</a>

User ID and attributes

User ID

If users can sign in somewhere in your app, you can specify their identifier to the SDK. This way, you will be able to relate crashes to specific users, link your users between FollowAnalytics and your CRM, and more.

This identifier is usually an e-mail address, client identifier, phone number, or anything else that uniquely ties your customers to you.

To register the user identifier, use:


+ (void)setUserId:(NSString *)userId;


func setUserId(userId: AnyObject!)

If you want to remove the user identifier (in case of a sign out for instance) use the following method:


+ (void)unsetCurrentUserIdentifier;


func unsetCurrentUserIdentifier

Predefined attributes

The SDK allows to set values for both custom and predefined attributes.

For predefined attributes, the SDK has the following properties:

+ (void)setUserFirstName:(NSString *)firstName;
+ (void)setUserLastName:(NSString *)lastName;
+ (void)setUserEmail:(NSString *)email;
+ (void)setUserDateBirth:(NSDate *)dateBirth;
+ (void)setUserGender:(FAGender)gender;
+ (void)setUserCountry:(NSString *)country;
+ (void)setUserCity:(NSString *)city;
+ (void)setUserRegion:(NSString *)region;
+ (void)setUserProfilePictureUrl:(NSString *)url;

They are "predefined" in the sense that they will be attached to default fields on your user profiles.

For example, to set user Joe's city to "Paris", you would proceed as follows:

[FAFollowApps setUserFirstName:@"Joe"];
[FAFollowApps setUserCity:@"Paris"];

Custom attributes

Double check your custom attribute types

When a value for an unknown attribute is received by the server, the attribute is declared with the type of that first value.

If you change the type of an attribute in the SDK, values might be refused server-side. Please ensure the types match by visiting the profile data section of the product.

Set a custom attribute

To set your custom attributes, you can use methods that are adapted for each type:

+ (void)setInt:(NSInteger)intValue forKey:(NSString *)key;
+ (void)setDouble:(double)doubleValue forKey:(NSString *)key;
+ (void)setBoolean:(BOOL)booleanValue forKey:(NSString *)key;
+ (void)setDate:(NSDate *)dateValue forKey:(NSString *)key;
+ (void)setDateTime:(NSDate *)dateValue forKey:(NSString *)key;
+ (void)setString:(NSString *)stringValue forKey:(NSString *)key;

For example, to set the user's job:

[FAFollowApps setString:@"Taxi Driver" forKey:@"key_job"];
Delete a custom attribute value

You can delete the value of an attribute using its key. For example, to delete the user's job:

[FAFollowApps removeCustomUserAttributeForKey:@"key_job"];
Set of Attributes

You can add or remove an item to or from a set of attributes.

To add an item:

NSSet *set = [[NSSet alloc] initWithObjects:@"apple", @"strawberry", @"lemon", nil];
[FAFollowApps addCustomUserAttributeSet:set forKey:@"fruits"];

To remove an item:

[FAFollowApps removeCustomUserAttributeSet:@"lemon" forKey:@"fruits"]; // Removes "lemon" from set of fruits.

And to clear a set:

[FAFollowApps deleteCustomUserAttributeSetForKey:@"fruits"]; // Removes all the items from the set.

For further information, refer to the SDK header file.


The SDK has a feature called AdaptiveSDK: it allows to benefit from tags already in place and use them directly without having to implement a new tagging plan.

The SDK is currently compatible with Segment, Mixpanel, Google Analytics, Localytics and Urban Airship.

To check that our SDK detects the current integration you have in place, use:


[FAFollowApps detectedSDKs];



You can then pick the SDKs you want to get tags from:

For instance, to fetch tags from Mixpanel, you would use:


[FAFollowApps fetchTagsFromSDKs:FASDKMixpanelKey];



If you wish to fetch tags from all compatible SDKs, you can chain the 2 method calls:


[FAFollowApps fetchTagsFromSDKs:[FAFollowApps detectedSDKs]];



How it works

All the events you save using the compatible Analytics SDKs will also be saved on FollowAnalytics. The event name will be prefixed with a two-character code identifying the source: UA for UrbanAirship, LL for Localytics, and so on.

Just like for events tagged directly with our SDK, you can see logs in your developer console when a log is saved, so that you can check it is properly working.

Advanced Use Cases

Deep-linking: URL, Parameters

Campaigns created through FollowAnalytics allow to deep link to content in your app. You can either use an App Link, or use key-value parameters that are forwarded to your code.

Version 4.1.0 of the SDK introduced the possibility to use direct App Links like twitter://messages, which will send you to the corresponding screen inside the Twitter application.

You're able to access the functionality by enabling the Deep Linking switch in our UI, when creating a campaign. There you'll find the field App Link that expects you to enter these type of url schemas. It can either be an URL Schema to an external application or for your own application.

In the case of an external application you'll be presented with a system alert asking you to allow the redirection for the target application (the first time only).

Deep-linking parameters

In FollowAnalytics campaigns, you can specify deep-linking parameters, e.g. in your push messages or for in-app button actions.

These parameters are given to the developer's code by the SDK. It is then up to the developer to implement the deep-linking in the app (specific path of screens, format of the arguments, etc.).

The parameters are passed using the following method of the FAFollowappsDelegate delegate:


- (void)followAppsShouldHandleParameters:(NSDictionary *)customParameters actionIdentifier:(NSString *)actionIdentifier actionTitle:(NSString *)actionTitle completionHandler:(void (^)())completionHandler;


func followAppsShouldHandleParameters(customParameters: [NSObject : AnyObject]!, actionIdentifier: String!, actionTitle: String!, completionHandler: (() -> Void)!)

Through the key value format, FollowAnalytics supports both standardized deep-linking (by defining the key you'll always use to give the path), and more direct parameter passing for simpler use cases integrations.

Regular deep-linking is usually implemented using a Router, that will handle the URL called on the app and translate it into the display of the right page, with the right content. An example of an open-source deeplinking router is DeepLinkKit.

Once this Router is configured in your app, the link with the FollowAnalytics SDK can be done the following way, supposing you decide on using the key deeplinking-path to pass your deeplink when creating your campaigns:


- (void)followAppsShouldHandleParameters:(NSDictionary *)customParameters actionIdentifier:(NSString *)actionIdentifier actionTitle:(NSString *)actionTitle completionHandler:(void (^)())completionHandler
    NSURL *url = [NSURL URLWithString:customParameters[@"deeplinking-path"]];
    if (url)
        [self.router handleURL:url withCompletion:nil];


func followAppsShouldHandleParameters(customParameters: [NSObject : AnyObject]!, actionIdentifier: String!, actionTitle: String!, completionHandler: (() -> Void)!) {
    let url:NSURL = NSURL(string: customParameters["deeplinking-path"] as! String)!
    self.router?.handleURL(url, withCompletion: nil)

Control over campaigns

Custom handling of rich campaigns

Rich campaigns can be handled directly by the application code, instead of being showed automatically by the SDK. The behavior is defined when creating the campaign, using the "automatically display content" switch.

For campaigns where the content is not handled by FollowAnalytics, implement the following FAFollowAppsDelegate method in your AppDelegate:


- (void)followAppsShouldHandleWebViewUrl:(NSURL *)url withTitle:(NSString *)webviewTitle;
func followAppsShouldHandleWebViewUrl(url: NSURL!, withTitle webviewTitle: String!)

Pausing in-app campaigns

You can prevent in-app campaigns from being displayed on certain views of your app. This can be useful when you are displaying a media content, or if the topmost screen is only shown for a few seconds, for instance.

Any campaign supposed to be displayed when the mechanism is paused is stacked and shown as soon as it is resumed.

To tell the SDK to prevent the display of rich campaigns, and then to activate it back, use the following methods:


[FAFollowApps pauseCampaignDisplay]
[FAFollowApps resumeCampaignDisplay]



Tip: use view lifecycle methods

If you want to prevent the display on a given page, you can call the pause method from the viewDidAppear method, and the resume one in the viewDidDisappear call.

Tip: only allow display in some places of the app

You can use these methods the other way round, by pausing all campaigns when the app starts, right after the SDK was initialized, and then resuming where the messages can be shown. Just pause again when the user leaves that "safe" area of your app.

Interactive notifications

To allow for interactive notifications, you need to register actions in your code. This allows to use custom button and actions on your notifications.

This has to be done in your code. The categories created can then be used when creating a FollowAnalytics push campaign.

If a user receives an interactive notification sent from FollowAnalytics, and taps one of the buttons, it calls the followAppsShouldHandleParameters:actionIdentifier:actionTitle:completionHandler: method and passes the action identifier and title. If no custom parameter was defined when creating the campaign, the first parameter is an empty dictionary.

The completionHandler comes from the default interactive notification handling methods. Make sure you call it if it is not nil as it won't be called by FA if passed to you.

Conflict with Notification Categories

If you register interactive notification categories and use our registerForPush method, make sure you register categories after calling registerForPush.

To register actions, you can proceed as follows:


UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
category.identifier = @"categoryIdentifier1";
[category setActions:actionsArray forContext:UIUserNotificationActionContextDefault];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:[NSSet setWithObjects:category, nil]];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];


let category:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
category.identifier = "categoryIdentifier1"
category.setActions(actionsArray, forContext:UIUserNotificationActionContext.Default)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: Set(arrayLiteral: category))

Get params from last notification

Some applications might not be able to receive the notification custom parameters. Although this is unlikely, you can get the latest NSDictionary containing the custom parameters passed by the notification by calling:

[FAFollowApps lastPushCampaignParams]

You cannot call this method twice

This is a one shot call as a second call to this method will return an empty NSDictionary.

Apple Watch setup


Don't update the pod

If you are using pods to integrate the FollowAnalytics SDK, do not update it, because you are currently using a specific version not released yet on pods.

Please integrate the SDK version that we sent you with the FAWatchKit2 SDK. You just have to replace the old framework by the new one.

Add the watchConnectivity.framework library to your watch and app projects.

Drag and drop the FAWatchKit2SDK.framework in the Frameworks group in the XCode project navigator (left pane) and check both the Copy boxes. Select the build scheme watch Extension, as shown below.


Then you can log events and errors the way you do it with the main SDK:

+ (BOOL)logEventWithName:(NSString *)name details:(id)details;
+ (BOOL)logErrorWithName:(NSString *)name details:(id)details;

Manual install

Cocoapods is the prefered method

Even though you can install the SDK manually, cocoapods is the prefered method, since it will take care of much of the work and ensure your SDK is easily updated.

  1. Drag and drop the FollowApps.framework in the Frameworks group in the Xcode project navigator (left pane) and check both the Copy box and your target's.

  2. Go to your project configuration, select your target. Under the General pane, add the following frameworks (if not already listed) in the Linked Frameworks and Libraries section:

    • Security.framework
    • SystemConfiguration.framework
    • CoreTelephony.framework
    • CoreLocation.framework
    • PassKit.framework
    • libc++.dylib (before iOS 9) or libc++.tbd (iOS 9 and later)
    • libsqlite3.dylib (before iOS 9) or libsqlite3.tbd (iOS 9 and later)
    • UserNotifications.framework

  3. Under the Build Settings pane, look for the Other Linker Flags entry, and add it the following value: -objC -all_load

  4. To improve the accuracy of your crash reports on the platform, look for Strip style, and set it to Debugging Symbols

  5. Now, you can proceed to configuring and validating your setup.




To allow your user to opt-out of data collection, drag and drop the Settings.bundle file in the Xcode project navigator. It'll add a settings pane in the settings app on their device, in which they will find a switch that they can turn off to disable logging.

If you already have a settings bundle, simply add the two items from the provided bundle into yours (in the same order).

Settings bundle localization

In order to add localizations for the Settings bundle the procedure is as follows:

As an example, the French localization of the file looks like this:

/* Localize the settings strings here if needed */
"Anonymous usage reports" = "Rapports d'Usage Anonymes";
"Help us improve the app by sending anonymous usage reports. Your data is not shared with third parties." =
"Aidez-nous à améliorer l'application en envoyant anonymement les rapports d'usage. Vos données ne seront pas partagées avec des tiers.";
"Send usage reports" = "Envoyer les rapports";

Access your original Swift AppDelegate

If you need to access your application's original delegate you can now use:


Handling URLs in your application

Apple introduced App Transport Security (ATS) in iOS 9 to improve user security and privacy by requiring apps to use secure network connections over HTTPS. At WWDC 2016 they announced that apps submitted to the App Store will be required to support ATS at the end of the year. To give you additional time to prepare, this deadline was extended. Apple has yet to announce the new date. Learn more about it here.

While this security policy is not enforced you can load unsafe urls by adding the folloing exception to your .plist.


When creating campaigns in FollowAnalytics, you will be able to use URLs for message contents or actions. We recommend using HTTPS, but if you cannot, you will need to add this exception in your .plist file.

Migrating from older versions

Migrating from 3.* to 4.*

The migration is seamless. However, please refer to the section around user attributes to learn how to feed user profiles using the SDK.

Migrating from 2.* to 3.0.0

To use version 3.0.0+ of the iOS SDK:

Nothing else changes. Please refer to the rest of the documentation to discover what the newer versions of the SDK now allow.