Skip to content

iOS Objective-C


Kumulos provides an SDK in the form of framework to ease integration Kumulos Analytics, Push Notification, Crash Reporting and Build features into your iOS app. This guide provides an overview of setting up the SDK for your project and sample usage.

Integrate SDK components

The Kumulos SDK is an open source project hosted on Github, for ease of use it is linked to from the agency console and can be found at

Both Carthage and CocoaPods integration instructions are available in the GitHub repo.


To initialize the Kumulos SDK, simply alloc & init the Kumulos class with your application's API key and secret key.

@import KumulosSDK;
KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[Kumulos initializeWithConfig:config];

A good place to do this is in your AppDelegate application:didFinishLaunchingWithOptions: method.

Checking installs of your App

When you run your app on a simulator or install your app on a device, you can check that the SDK has been initialized correctly by selecting the app and clicking the Installs tab to see the ten most recent installs of your app. Click on any install to see more information.

Recent installs

If you experience any difficulties integrating an SDK or initializing the Kumulos client, please don't hesitate to contact support who are standing by to help!

Installation ID

When initialized for the first time, the Kumulos SDK will create a unique identifier for the app installation that initialized the SDK.

This identifier can be used to target push notifications to a specific device through KScript or the Push Notifications API.

In order to retrieve this installation ID, simply use the class method:

NSString* installId = [Kumulos installId];

Once you have the installation ID, you can send it to your app's backend to be used later for push targeting. For more information about push targeting, please see the KScript Documentation or push notification documentation as appropriate.


Session Analytics

Kumulos records sessions based on application foreground and background events. When an app enters the background, Kumulos will wait for a configurable idle period. If there are no more foreground events during that idle period, the current session will be closed.

Session analytics

You can configure the idle period to suit your app's use-case. By default the idle period is 23 seconds of inactivity. The idle period does not count towards session duration calculations.

To adjust the idle period, you can configure the SDK as follows:

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config setSessionIdleTimeout:120];
[Kumulos initializeWithConfig:config];

Note that due to background task limits, in practice the idle timeout can only reasonably be up to a few minutes for iOS < 13 and up to 30 seconds for iOS 13+.

Event Tracking

Kumulos allows you to track custom analytics events that can be used as a trigger to fire automation rules (e.g. to trigger a push notification) or as steps in a funnel to track conversion through key user journeys in your app.

Track conversion

To track a custom analytics event, use trackEvent as follows:

Kumulos.shared trackEvent:@"product.purchased" withProperties:@{
    @"productId": 42

Each event and its properties must be less than 250 KiB in size for the event to be tracked.

Event tracking is available offline as all events are persisted locally before being synced to the server in batches in the background.

A similar method trackEventImmediately will immediately start an event sync rather than waiting for the next time the app is backgrounded.

Checking events from your App

When you run your app on a simulator or install your app on a device, you can check that the SDK is recording events correctly by selecting the app and clicking the Installs tab to see the ten most recent installs of your app. Click on any install and then click on the Events tab.

Install events

Alternatively, to see counts of all analytics events, including system events such as opened a push notification, recorded by installs of the app in the last 30 days, expand 'Analytics' and click 'Explore' in the left menu. For comparison, the total number of sessions in the same period is shown.

Analytics Explorer

User Association

Kumulos allows associating a user identifier with the current installation ID. This user identifier is useful for performing analytics aggregations & analyses at the user level, for example, funnels completed by users across multiple devices. You can also optionally associate a collection of attributes with the user.

To associate the current app installation with a user, you can use the helper method as shown below:

Kumulos.shared associateUserWithInstall:@"Bob"];

User association is time-aware, so in the case of two different users sharing a device to log in to the app, their user IDs will be associated with the same install for the time between subsequent calls to the helper method. For example:

Kumulos.shared associateUserWithInstall:@"Bob"];

// This event will belong to Bob
Kumulos.shared trackEvent:@"product.purchased" withProperties:@{
    @"productId": 42

Kumulos.shared associateUserWithInstall:@"Alice"];

// This event will belong to Alice
Kumulos.shared trackEvent:@"product.purchased" withProperties:@{
    @"productId": 42


You can optionally associate a collection of attributes with the user for targeting, personalization or attribution. To associate attributes with the user, pass a collection into the helper method as shown.

Kumulos.shared associateUserWithInstall:@"Bob" attributes:@{
    @"name": "Shawn",
    @"age": 25

The collection of attributes for a given user must be less than 250 KiB in size.

If you do not have a user identifier, use the installation id generated by the Kumulos SDK.

Location Tracking

You can send Kumulos location updates and use this to trigger events such as push notifications when an install enters a GeoFence.

How you configure the Core Location services for iOS depends on the specific use case of your app. You should consider both accuracy and battery life when making this decision. Refer to the Apple documentation for details of how to configure location services.

Once you have created a CLLocationManagerDelegate you can use the helper method in the Kumulos SDK to send location updates to Kumulos.

Kumulos.shared sendLocationUpdate:location];

iBeacon Detection

You can send Kumulos beacon proximity updates and use these to trigger automations such as sending a push notification when an install is in proximity to a beacon.

How you configure the Core Location services for iOS depends on the use case for your app and you should consider throttling how regularly these events are transmitted for both battery life and network traffic.

The Kumulos SDK provides a helper method to notify our services of proximity to a detected beacon.

Kumulos.shared sendiBeaconProximity:beacon];

Messaging & Push Notifications

Kumulos provides powerful multi-channel messaging services to reach your users. By initializing the SDK you can quickly and easily receive both push notifications to re-engage your users as well as feature-rich In-App messages.

Configuration & Integration

To integrate Kumulos Messaging into your iOS project, you have to complete the following steps with either Key or Certificate based credentials.

  1. Set up APNs credentials in your Apple Developer account
  2. Configure Push in the Kumulos Agency Console
  3. Integrate SDK components with your iOS project & enable in-app messaging
  4. Register for push from the client app

Configure APNs

In order to generate a P8 key for Apple services first access your account at and select 'Certificates, Identifiers & Profiles', then select 'Keys' on the left.

Apple Developer - Keys

Select 'Create a Key' and on the form 'Register a New Key' enter a meaningful name such as 'APNS Access Key' and check the 'Enable' checkbox for 'Apple Push Notifications service (APNs)', click 'Continue'.

Apple Developer - Register Key

On the confirmation screen double check the APNs enablement is set then click 'Register'

On the final screen take note of your KeyID and download the key. Note that you can only download the key once, if lost the key must be revoked and re-created.

Downloading the key will save a .p8 file with the access credentials.

You now have all the details to configure your Kumulos App, expand 'Messaging' in the left menu, select 'Configuration' and click the cog next to the Apple icon. Select APNs P8 and select your file, enter your other details and click 'Configure'.

Configuring APNs

Configure your app capabilities and entitlements

In your app project settings use the "+ capability" button to add the App Groups, Background Modes and Push Notifications capabilities, in Background Modes you should have the "Remote Notifications" mode checked.

The video below shows how to create a push certificate on your Apple Developer portal, configure these certificates in Kumulos, and how to then configure the necessary entitlements in your iOS Xcode project.

Configuring APNS for iOS with Kumulos

Note you must use a real device to test push notifications on iOS because simulators cannot register for push notifications.

Enable In-App Messaging

Add the following to your Kumulos config:

@import KumulosSDK;
KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config enableInAppMessaging:KSInAppConsentStrategyAutoEnroll];
[Kumulos initializeWithConfig:config];

Next, enable the 'background-fetch' Background Mode in your Xcode project's Capabilities section.

Requesting a Push Token

When you consider it appropriate, you need to request permission from the user to send them push notifications. You can potentially use a Kumulos in-app message to prompt the user to accept push at a later time.

Whilst you can handle this yourself, Kumulos provides a convenience method:

// Assuming you initialized the Kumulos object using [Kumulos initializeWithConfig:]
[Kumulos.shared pushRequestDeviceToken];

This will prompt the user to accept push notifications with the badge, alert, and sound settings. When the user accepts, the Kumulos SDK will store the push token.

To remove the token from Kumulos, call this method:

[Kumulos.shared pushUnregister];


Checking Push Registrations

When you run your app on a simulator or install your app on a device, you can check that the install has successfully registered for push notifications by selecting the app and clicking the Installs tab to see the ten most recent installs of your app.

Click on an install, click the 'Push' tab and click Send Test Push.

Install push details

If you do not receive the push notification, check the Error Log for any errors sending the push notification to the native push gateways. If you continue to experience problems, please don't hesitate to contact support who are standing by to help!

Supporting Pictures and Action Buttons in Notifications

When sending a push notification you can attach a picture or action buttons to it. They will show on iOS 10+ devices.

The notification will expand upon swiping the notification on devices supporting 3D Touch. In order to enable this functionality you need to add a Notification Service Extension to your application.

If using CocoaPods, add the following to your Podfile and run pod install.

target 'KumulosNotificationServiceExtension' do
  pod 'KumulosSdkObjectiveCExtension', '5.0.0'

Then replace the contents of NotificationService.m with the following lines:

#import "NotificationService.h"
#import <KumulosSDKExtension/KumulosNotificationService.h>

@interface NotificationService ()

@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
   [KumulosNotificationService didReceiveNotificationRequest:request withContentHandler: contentHandler];

Supporting push delivery tracking, dismissed tracking and badges

For push delivery tracking, dismissed tracking and badges to work correctly you need to

  1. Set up Notification Service Extension as described above
  2. Add App Groups capability to your App and Notification Service Extension targets
  3. Set group to group.{your.bundle.identifier}.kumulos for both targets

Note that due to iOS limitations badge is not set when app is in the foreground

Handling notification action buttons

When a user interacts with your push message the pushOpenedHandlerBlock will be called, in this block you can provide further behavior to handle custom actions.

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config setPushOpenedHandler:^(KSPushNotification* _Nonnull notification) {
    //- Inspect notification data and do work.
    NSString* action = notification.actionIdentifier;
    if (action != nil) {
        NSLog(@"User pressed an action button.");
    else {
        NSLog(@"Just an open event.");

[Kumulos initializeWithConfig:config];

Kumulos' helper function automatically adds picture attachments and buttons to the notification content. You can modify the content before calling didReceive or replace the implementation with your own.

If you would like your users to opt-in to receive In-App messages you can configure the SDK during initialization to make opt-in explicit by setting the strategy, then calling the SDK helper to manage their consent.

// Set the strategy to require explicit user consent when initializing the SDK
KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config enableInAppMessaging:KSInAppConsentStrategyExplicitByUser];

// Call this method to update consent based on user preferences / settings screen etc.
[KumulosInApp updateConsentForUser:YES];

Deep-linking for In-App

In-App messages allow you to hand-off to native application screens via deep-linking action buttons. When tapped, these buttons pass control to the defined deep-link handler, including their defined data payload (configured in the In-App message composer for the action button).

If you want to handle deep-links with custom data payloads as part of an In-App message you can add a handler block to your configuration options during SDK initialization.

[config setInAppDeepLinkHandler:^(KSInAppButtonPress * _Nonnull press) {
    //- Inspect the data payload and run code as needed.
    NSLog(@"Deep link data: %@", press.deepLinkData);

Using the In-App Inbox

In-app messages can optionally be persisted in a user-level inbox for later retrieval. This allows you to build features such as loyalty rewards or expiring coupons into your app. Regardless of whether they are stored in the inbox, the maximum amount of in-apps stored on a device is 50 (the oldest messages exceeding this limit will be evicted).

Retrieve messages

To retrieve a list of messages from the user's inbox and present the first in the list, see the following example:

NSArray<KSInAppInboxItem*>* items = [KumulosInApp getInboxItems];
[KumulosInApp presentInboxMessage:items[0]];
Mark as read

To mark a single or all inbox messages as read:

NSArray<KSInAppInboxItem*>* items = [KumulosInApp getInboxItems];
[KumulosInApp markAsRead:items[0]];

[KumulosInApp markAllInboxItemsAsRead];
Delete message

You can also delete an in-app message from inbox:

NSArray<KSInAppInboxItem*>* items = [KumulosInApp getInboxItems];
[KumulosInApp deleteMessageFromInbox:items[0]];
Inbox updated handler

In order to be notified when inbox changes you may set up a handler. The handler fires on the main thread when one of the following happens to an in-app with inbox:

  • message fetched from server
  • message opened
  • message marked as read
  • message deleted
  • message evicted (expires or limit of stored messages exceeded)

You can use it as follows:

[KumulosInApp setOnInboxUpdated:^(){
    NSArray<KSInAppInboxItem*>* items = [KumulosInApp getInboxItems];

    //refresh your inbox

Note, you should set the handler after Kumulos has been initialized.

Note, you can do [KumulosInApp setOnInboxUpdated:nil] when you stop being interested in inbox updates.

Get inbox summary

You can retrieve inbox summary as follows:

[KumulosInApp getInboxSummaryAsync:^(InAppInboxSummary* inboxSummary) {
    if (inboxSummary != nil){
        NSLog(@"total: %d, unread: %d", inboxSummary.totalCount, inboxSummary.unreadCount);

The method runs asynchronously and calls back on the main thread.

Get inbox item's image URL

Each inbox item may have an image associated with it. getImageUrl returns a URL to the image of specified width or nil if there is no image.

NSArray<KSInAppInboxItem*>* items = [KumulosInApp getInboxItems];

// Default width is 300px
NSURL* url = [items[0] getImageUrl];

// Get URL to a 200px wide image
NSURL* url = [items[0] getImageUrl:200];

Note if the message was created through the API (as opposed to Kumulos Messaging Dashboard) and contains a full URL to an image hosted elsewhere, getImageUrl returns original URL without any resizing applied.

Handling Push Notification Opens for Deep Linking

If you want to implement your own deep links for push notifications, the SDK offers an integrations point which is called when the user opens a push notification.

To set up a handler, simply add the following to your config:

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config setPushOpenedHandler:^(KSPushNotification* _Nonnull notification) {
    // Inspect and take action as desired

Note you do not need to handle deep links to in-app messages yourself, the Kumulos SDK already handles these.

Handling Background Data Pushes

When you send a background data push with Kumulos, the content-available flag will be set on the notification.

This will allow your app to be woken up to process the push notification in the background.

Make sure you have enabled the "Remote notifications" background mode in your project's "Capabilities" settings

The background push notification will trigger the application:didReceiveRemoteNotification:fetchCompletionHandler: application delegate:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // userInfo[@"aps"][@"content-available"] will be set to 1
    // userInfo[@"custom"][@"a"] will contain any additional data sent with the push


Note if you set a title & message then a notification will be shown to the user. If you want the push to be silent, don't set a title or message when sending.

Handling Push Notifications Received while the app is Foregrounded

When a push notification is received while your app is in the foreground the Kumulos SDK will by default still show the alert tile at the top of the display.

You can override this by setting the foregroundPresentationOptions during configuration, for example hiding them.

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config setForegroundPushPresentationOptions:UNNotificationPresentationOptionNone];

You can also perform work using the contents of the notification by providing a handler block to the configuration.

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config setPushReceivedInForegroundHandler:^(KSPushNotification * _Nonnull notification) {
    NSLog(@"Do work.");


You can create and manage subscriptions to push notification Channels via the SDK. Channels allow your users to define preferences for the type of content they would like to receive via notifications.

You can manage all channel interactions via the KumulosPushSubscriptionManager class.

KumulosPushSubscriptionManager* manager = [[KumulosPushSubscriptionManager alloc] initWithKumulos:Kumulos.shared];

The push manager exposes several methods to manage subscriptions:

@interface KumulosPushSubscriptionManager

- (void) subscribeToChannels:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) unsubscribeFromChannels:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) setSubscriptions:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) clearSubscriptions:(KSPushSubscriptionCompletionBlock) complete;

- (void) listChannels:(KSPushChannelsSuccessBlock) complete;

- (void) createChannelWithUuid:(NSString* _Nonnull) uuid shouldSubscribe:(BOOL) subscribe name:(NSString* _Nullable) name showInPortal:(BOOL) shownInPortal andMeta:(NSDictionary* _Nullable) meta onComplete:(KSPushChannelSuccessBlock) complete;


Results are handled by passing a block for the operation's completion like so:

[self.manager listChannels:^(NSError * _Nullable error, NSArray<KSPushChannel *> * _Nullable channels) {
    if (error) {
        // Handle any error as you want

    // Handle channel listing result

When creating channels, the visibility and meta data can be controlled. Please make sure you understand these concepts when creating channels from the SDK.

Deferred Deep Linking

Deep linking allows users to reach app content by clicking a link. This can be achieved even if app is not installed.

Configuration & Setup

To integrate deep linking into your Objective-C project, you have to complete the following steps.

If your app doesn't use scenes, add to your AppDelegate.m:

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
    return [Kumulos application:application continueUserActivity:userActivity restorationHandler:restorationHandler];

If your app uses scenes: add to SceneDelegate.m:

- (void) scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
    [Kumulos scene:scene continueUserActivity: userActivity];

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions{
    if(![scene isKindOfClass:[UIWindowScene class]]){

    // Deep links from cold starts
    NSUserActivity* userActivity = [[[connectionOptions userActivities] allObjects] firstObject];
    if (userActivity){
        [Kumulos scene:scene continueUserActivity: userActivity];

Configure a deep link handler:

KSConfig *config = [KSConfig configWithAPIKey:@"API_KEY" andSecretKey:@"SECRET_KEY"];
[config enableDeepLinking:^(KSDeepLinkResolution resolution, NSURL* url, KSDeepLink* deepLink) {
     switch (resolution) {
            case KSDeepLinkResolutionLinkMatched:
                NSLog(@"deep link matched");
[Kumulos initializeWithConfig:config];

Finally, you need to associate a domain with your app. Note that the subdomain you specify here should match the one you specified on the deep link configuration page on Kumulos Dashboard.

  1. Add the Associated Domains capability to your main app target
  2. Set 'domains' to applinks:{yourSubdomain}

Associated Domain capability


This section shows various examples of calling your Kumulos API methods using the SDK or the generated bindings, and handling results with blocks or delegates as desired.

To talk to Kumulos, you need three things:

  • your method title (in lowerCamelCase)
  • a method parameters map (field names are also in lowerCamelCase)
  • some response handler code

All networking is performed asynchronously, but your result handling blocks & delegates will always be called back on the application's main thread

Using the SDK

Handling Results with Blocks

To make calls to your API methods, use the callMethod:... selectors on the Kumulos class. For an example using blocks to handle the response:

NSDictionary* params = @{@"author": @"Jane Austin"};
// Assuming Kumulos instance has been initialized as shown in the Initialization section
[Kumulos.shared callMethod:@"getAllBooksByAuthor" withParams:params success:^(KSAPIResponse * _Nonnull response, KSAPIOperation * _Nonnull op) {
    NSArray* books = response.payload;

    // Do something with the books
  } andFailure:^(NSError * _Nonnull err, KSAPIOperation * _Nonnull op) {
    NSLog(@"Something went wrong!");

Handling Results with Delegates

Alternatively you can handle results using a delegate conforming to the KSAPIOperationDelegate protocol:

@import KumulosSDK;

@interface ViewController () <KSAPIOperationDelegate>

@property (nonatomic) Kumulos* k;


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.k = [[Kumulos alloc] initWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
    [self.k callMethod@"getAllAuthors" withDelegate:self];

- (void) operation:(KSAPIOperation *)operation didCompleteWithResponse:(KSAPIResponse *)response {
    NSString* methodAlias = operation.method;
    NSLog(@"%@", response.payload);

    // Check which method it was and handle result as appropriate

// Optionally conform to handle errors
- (void) operation:(KSAPIOperation *)operation didFailWithError:(NSError *)error {
    NSLog(@"Something went wrong!");


Cancelling API Operations

To cancel requests, just grab the KSAPIOperation* from the Kumulos object and call the cancel selector. For example:

KSAPIOperation* theOperation = [Kumulos.shared callMethod:@"myNotSoAwesomeOperation" withDelegate:self];
// Change your mind
[theOperation cancel];

Using the Generated Bindings

If you are using the generated bindings, each of your API methods will be available to invoke directly on the Kumulos class thanks to the Kumulos (Bindings) category implemented by Kumulos.m.


Using the generated bindings assumes that you have deployed an API for iOS/OSX and downloaded the libraries.

After downloading the libraries, to make use of the generated bindings, drag & drop the Kumulos.h and Kumulos.m files from the download into your project.

Add the files to your project

Finally, you should install the KumulosSDK core framework from CocaPods, Carthage, or sources (instructions on GitHub).


After integration, you can use the generated init method that has the keys provided:

#import "Kumulos.h"
Kumulos* k = [[Kumulos alloc] init];


In this mode of operation, you can only handle the reults using a delegate conforming to the KumulosDelegate protocol defined in Kumulos.h.

For example:

#import "Kumulos.h"

@interface ViewController () <KumulosDelegate>

@property (nonatomic) Kumulos* k;


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.k = [[Kumulos alloc] initWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];

    // Tell Kumulos which delegate will handle API operation results
    [self.k setDelegate:self];
    // Invoke the API method directly
    [self.k getAllAuthors];

- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation getAllAuthorsDidCompleteWithResult:(NSArray*)theResults {
    // Handle the results for the getAllAuthors API call

// Optionally handle errors
- (void) kumulosAPI:(kumulosProxy *)kumulos apiOperation:(KSAPIOperation *)operation didFailWithError:(NSString *)theError {



Crash reporting allows you to track unhandled exceptions in your app, and optionally log any caught exceptions for further investigation. Crash reporting is not enabled by default, to enable this feature, simply modify your Kumulos initialization to include enabling crash reporting.

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config enableCrashReporting];
[Kumulos initializeWithConfig:config];

Unhandled exceptions that lead to crashes will now be recorded automatically and shown in your App Delivery Console.

Note that crash reporting is not available whilst connected to a debugger, but it does work with debug builds.

If you wish to log any caught exceptions, you can record them with the helper method:

[Kumulos.shared logExceptionWithName:@"name" reason:@"reason" language:@"objc" lineNumber:@"1" stackTrace:@[@"boom", @"clunk", @"bang"] loggingAllThreads:YES];

Ensure that crash reporting is enabled when attempting to log exceptions.

Upload dSYM Files for Symbolication

In order to ensure your stack traces are fully symbolicated, it is necessary to upload your dSYM information from your project.

To upload dSYM files for Release builds, you should add a new "Run Script Phase" to your Xcode project's "Build Phases".

For CocoaPods installations, use this script:


For Carthage installations, use this script:

"$SRCROOT/Carthage/Checkouts/KumulosSdkObjectiveC/" API_KEY SERVER_KEY

Copy the script snippet into a new Run Script Phase as shown below:

Add a new Run Script Build Phase

Make sure you replace the API_KEY and SERVER_KEY tokens with your app's API and server keys which can be found on the application's dashboard.

Bitcode-enabled Builds

If your project has bitcode enabled, it will be necessary to upload the dSYM files that Apple generates as part of App Store distribution step.

These generated dSYM files can be downloaded using the Xcode Organizer. Once downloaded, the generated dSYM files will be available in your app's archive.

You should follow the steps of the screen capture below to prepare your symbols for upload.

Fetching & preparing generated dSYMs for upload

Once prepared for upload, you should upload the dSYM zip file to your App Delivery Console.



In-app enhancements:

  • Expose in-app message data to KSInAppDeepLinkHandlerBlock
  • Track event properties with in-app button conversion events
  • Improve in-app error handling for network edge-cases


  • Add flags to stats data for notification settings & group entitlement (#71)

Breaking changes:

  • KSInAppDeepLinkHandlerBlock now takes KSInAppButtonPress* as its only argument. The original deep link button data is in now in the deepLinkData field of the passed object.


  • Add support for UNNotificationActionIcon on notification buttons, added with iOS 15


  • Add probability-based matching for Web-to-App Banners


  • Throw when trying to set set onInboxUpdated handler before initializing Kumulos


  • Inbox sort order consistent with other SDKs


  • Store image for InAppInboxItem, getImageUrl helper method
  • Allow setting onInboxUpdated handler, see docs above
  • Add getInboxSummaryAsync helper method, see docs above
  • Expose extra fields on InAppInboxItem: sentAt and data
  • Consistent sort order of inbox messages
  • Limit amount of stored inbox messages
  • Allow marking in-app messages as read


  • Track push notification dismissed event
  • Bugfix: NSDateFormatter is not parsing dates on some devices


  • Deep Linking (see integration guide)
  • Improve reliability of channel subscription
  • Improve reliability of delivery tracking
  • Guard unwrapping APNS payloads


  • Fix header conflicts with KSCrash when installed through CocoaPods


  • Guards against a rare exception in the session finalization codepath


  • Delivery tracking
  • Incrementing badges

You need to set up App Groups and add Notification Service Extension as described above for delivery tracking and badges to work.


  • In-App inbox deletion


  • Add configuration setting for foreground push presentation
  • Add action button support to the Notification service extension
Upgrade Guide

If you were not using the foreground push handler block, you dont need to do anything to update.

If you had previously configured a block the second argument for the completion handler has been removed from the block, the presentation behavior for foreground pushes can now be set by calling setForegroundPushPresentationOptions on your config.


  • Allow apps to handle local notifications with their own delegate


  • NotificationServiceExtension moved into its own Podspec.


  • Add support for expiry dates for In-App messages


  • Support pictures in push notifications


  • Add in-app messaging support
  • Handle all push lifecycle & notification delegates out the box
Upgrade Guide

If you are not using push notifications, you don't need to do anything to update.

All relevant changes are related to the setup of push notification delegates. As part of the in-app messaging feature, the Kumulos SDK needs more control of these delegates.

As such, the SDK now handles the following delegates for you:

  • application:didRegisterForRemoteNotificationsWithDeviceToken:
  • application:didFailToRegisterForRemoteNotificationsWithError:
  • application:didReceiveRemoteNotification:fetchCompletionHandler:
  • application:performFetchWithCompletionHandler:
  • UNUserNotificationCenterDelegate

All behaviors related to correctly persisting the push token, tracking notification opens, opening URL pushes, etc. are now handled by the SDK, making integration simpler.

This means it is safe to remove all delegate setups listed above if you previously followed the base Kumulos integration guide for their setup and added no further customization.

If you did implement any of the above application delegates and customize their behavior, the Kumulos SDK will still call them first, and then continue handling the logic required for Kumulos. The only exception to this is the UNUserNotificationCenterDelegate which does not call to any existing delegate.

Note that it is important to invoke the completionHandler callbacks from all delegate methods in a timely fashion.

In addition, it is necessary to add the background-fetch background mode to your app's capabilities in the Xcode project setup.

If you want to continue handling push open behavior yourself, you can now set the push notification opened handler block in the KSConfig class with setPushOpenedHandler method.


  • Add new helper method for device token removal


  • Persist userIdentifier to NSUserDefaults on association and add accessor
  • Record current userIdentifier with events and send in server sync
  • Add helper to clear any existing user association
  • Create analytics data model in code
  • Ensure correct thread usage for CoreData operations


  • Allow overriding target type for use in SDKs where sources are not used


  • Remove AFNetworking dependency to allow use in static libraries
  • Add static library target to allow embedding the SDK in React Native
  • Increase priority for analytics task dispatch (background priority can be starved)


  • Don't sync events which have not been fully persisted yet


  • Add support for storing user attributes when associating an install with a user


Use quoted header import style for CocoaPods usage

Works around an issue with Cordova plugin usage from a pod where headers can't be resolved using the system style imports.


  • Expose helper to allow tracking event then flushing events to the server
  • Allow configuring SDK & runtime info for use in wrapper SDKs
  • Early return from event tracking when properties are not serializable


  • Remove use of NSBatchDeletionRequest to support iOS < 9
  • Drop required iOS deployment target to 8.0
  • Fix availability warning by using @available guard
  • Enable availability warnings for all versions


  • Don't import using the module syntax to allow usage from non-framework pod targets
  • Remove unnecessary framework links and set headers dir for consistent include statements
  • Update import statements and remove use_frameworks! note


  • Add iBeacon proximity helper
  • Refactor most server interactions to be recorded in the events DB
  • Fix Podspec missing resources file


  • Add dSYM upload script to SDK distribution


  • Record background event synchronously


  • Prevent intermittent build failures by explicitly referencing dependency targets from the SDK schemes


  • Add custom event tracking
  • Capture session analytics events
  • Add user association helper


  • Add public header file to Podspec


  • Add Crash Reporting


  • Version bump


  • Expose geolocation update helper publicly
  • Fix nil reference exception in stats


  • Add geolocation update helper method
  • Add locale & bundle to stats payload


  • Add missing header guard for macOS


  • Add Podspec for CocoaPods support
  • Update installation instructions
  • Fix include guards for iOS & macOS headers


  • Add push channel subscription management


  • Fix compilation of framework to include full bitcode


  • Initial release of SDK as a framework
  • Initial release of support for Kumulos Push
  • Clean up of public interfaces & properties
  • Move supporting behavior for generated bindings from the core SDK to the generated bindings
  • Modernize Objective-C throughout
  • Utilize latest AFNetworking throughout

The generated bindings code has been updated to be compatible with our latest SDK whilst aiming to maintain backwards compatibility with the most commonly used features of the older SDKs. However, if you have any trouble upgrading, please drop a line to -- we'd be happy to help.