iOS Client Usage Guide


The Keen iOS client is designed to be simple to develop with, yet incredibly flexible. Our goal is to let you decide what events are important to you, use your own vocabulary to describe them, and decide when you want to send them to Keen IO.

For a detailed class reference, please visit our Keen iOS Client API Reference.

  • Install Guide - How to install the Keen iOS Client into your application.
  • Register Client - How to register your Project ID with the Keen iOS Client.
  • Add Events - How to add an event with the Keen iOS Client.
  • Geo Location - How to use Geo Location with the Keen iOS Client.
  • Upload to Keen - How to upload all previously saved events with the Keen iOS Client.

Got questions or feedback? Come hang out with us in the Keen chat:

Install Guide

Installing the client should be a breeze. If it’s not, please let us know at!

Universal Binary

Our recommended way of installing the Keen Client is to use the universal binary we’ve created. With this, you’ll be able to instrument your app regardless of whether or not it uses ARC (Automatic Reference Counting).


While we think the universal binary makes things really easy, we love to be transparent. Come check out our work on GitHub at We love feedback, especially in the form of pull requests. :)


Download the binary and public headers. Get the latest from here:


Uncompress the archive. It should contain a folder called “KeenClient” with the following contents:

  • libKeenClient-Aggregate.a
  • KeenClient.h
  • KeenProperties.h

Add Files to Xcode

Just drag the “KeenClient” folder into your Xcode project.

Add Required Frameworks

Go into your app’s target’s Build Phases screen and add CoreLocation.framework to the “Link Binary With Libraries” section.

Enable Linker Flag

Enable a linker flag to include the special categories on some of the NSFoundation classes that are required for the Keen client to work correctly. Start by choosing the correct target for your project, selecting the “Build Settings” tab, and then search for “other linker”. Under “Other Linker Flags”, add the text “-ObjC”.



Try and compile. It should work! If it doesn’t, you probably forgot to enable the linker flag (see above). If you still can’t get it to work, let us know at and one of us will help you right away.

Get Project ID

If you haven’t done so already, login to Keen IO to get your Project ID.


Now it’s time to actually use the client!

Register Client

Register the KeenClient shared client with your Project ID and access keys. The recommended place to do this is in one of your application delegates. Here’s some example code:

- (void)applicationDidBecomeActive:(UIApplication *)application
    [KeenClient sharedClientWithProjectId:@"your_project_id"

The [KeenClient sharedClientWithProjectId: andWriteKey: andReadKey:] does the registration. From now on, in your code, you can just reference the shared client by calling [KeenClient sharedClient].

Add Events

Add events to track. Here’s a very basic example for an app that includes two tabs. We want to track when a tab is switched to.

- (void)viewWillAppear:(BOOL)animated
    [super viewWillAppear:animated];

    NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];
    [[KeenClient sharedClient] addEvent:event toEventCollection:@"tab_views" error:nil];

The idea is to first create an arbitrary dictionary of JSON-serializable values. We support:

NSString, NSNumber, NSDate, NSDictionary, NSArray, and BOOL


The JSON spec doesn’t include anything about date values. At Keen, we know dates are important to track. Keen sends dates back and forth through its API in ISO-8601 format. The Keen Client handles this for you.

Keys must be alphanumeric, with the exception of the underscore (_) character, which can appear anywhere but the beginning of the string. For example, “view_name” is allowed, but “_view_name” is not.

Add as many events as you like. The Keen client will cache them on disk until you’re ready to send them.

The client will automatically stamp every event you track with a timestamp. If you want to override the system value with your own, use the following example. Note that the “timestamp” key is set in the header properties dictionary.

- (void)viewWillAppear:(BOOL)animated
    [super viewWillAppear:animated];

    NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];
    NSDate *myDate = [NSDate date];
    KeenProperties *keenProperties = [[[KeenProperties alloc] init] autorelease];
    keenProperties.timestamp = myDate;
    [[KeenClient sharedClient] addEvent:event

Global Properties

Now you might be thinking, “Okay, that looks pretty easy. But what if I want to send the same properties on EVERY event in a particular collection? Or just EVERY event, period?” We’ve got you covered through something we call Global Properties.

Global properties are properties which are sent with EVERY event. For example, you may wish to always capture device information like OS version, handset type, orientation, etc.

There are two ways to handle Global Properties - one is more simple but more limited, while the other is a bit more complex but much more powerful. For each of them, after you register your client, you’ll need to set an Objective-C property on the KeenClient instance you’re using.

Dictionary-based Global Properties

For this, the Objective-C property is called globalPropertiesDictionary. The property’s value will be an NSDictionary that you define. Each time an event is added, the iOS client will look at the value of this property and add all its contents to the user-defined event. Use this if you have a bunch of static properties that you want to add to every event.

Here’s an example using a dictionary:

- (void)applicationDidBecomeActive:(UIApplication *)application
    KeenClient *client = [KeenClient sharedClient];
    client.globalPropertiesDictionary = @{@"some_standard_key": @"some_standard_value"};


If there are two properties with the same name specified in the user-defined event AND the global properties, the user-defined event’s property will be the one used.

Block-based Global Properties

For this, the Objective-C property is called globalPropertiesBlock. The property’s value will be a block that you define. Every time an event is added, the block will be called. The client expects the block to return an NSDictionary consisting of the global properties for that event collection. Use this if you have a bunch of dynamic properties (see below) that you want to add to every event.

Here’s an example using blocks:

- (void)applicationDidBecomeActive:(UIApplication *)application
    KeenClient *client = [KeenClient sharedClient];
    client.globalPropertiesBlock = ^NSDictionary *(NSString *eventCollection) {
        if ([eventCollection isEqualToString:@"apples"]) {
            return @{ @"color": @"red" };
        } else if ([eventCollection isEqualToString:@"pears"]) {
            return @{ @"color": @"green" };
        } else {
            return nil;

The block takes in a single string parameter which corresponds to the name of this particular event. And we expect it to return an NSDictionary of your construction. This example doesn’t make use of the parameter, but yours could!


Because we support a block here, you can create DYNAMIC global properties. For example, you might want to capture the orientation of the device, which obviously could change at run-time. With the block, you can use functional programming to ask the OS what the current orientation is, each time you add an event. Pretty useful, right?


Another note - you can use BOTH the dictionary property AND the block property at the same time. If there are conflicts between defined properties, the order of precedence is: user-defined event > block-defined event > dictionary-defined event. Meaning the properties you put in a single event will ALWAYS show up, even if you define the same property in one of your globals.

Geo Location

Like any good mobile-first service, Keen supports geo localization so you can track WHERE events happened. This is enabled by default. Just use the client as you normally would and your users will be asked to allow geo location services. All events will be automatically tagged with the current location.

Refreshing Current Location

Every time the app is freshly loaded, the client will automatically ask the device for its current location. It won’t ask again in order to save battery life. You can tell the client to ask the device for location again. Simply call:

[[KeenClient sharedClient] refreshCurrentLocation];

Manually Setting Location

You can also set the location manually. See the following example:

NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];
KeenProperties *keenProperties = [[[KeenProperties alloc] init] autorelease];
CLLocation *location = [[[CLLocation alloc] initWithLatitude:37.73 longitude:-122.47] autorelease];
keenProperties.location = location;
[[KeenClient sharedClient] addEvent:event withKeenProperties:keenProperties toEventCollection:@"tab_views" error:nil];

Upload to Keen

Upload the captured events to the Keen service. This must be done explicitly. We recommend doing the upload when your application is sent to the background, but you can do it whenever you’d like (for example, if your application typically has very long user sessions). The uploader spawns its own background thread so the main UI thread is not blocked.

- (void)applicationDidEnterBackground:(UIApplication *)application
    UIBackgroundTaskIdentifier taskId = [application beginBackgroundTaskWithExpirationHandler:^(void) {
        NSLog(@"Background task is being expired.");

    [[KeenClient sharedClient] uploadWithFinishedBlock:^(void) {
        [application endBackgroundTask:taskId];

In this example, the upload is done in a background task so that even once the user backgrounds your application, the upload can continue. Here we first start the background task, start the upload, and then end the background task once the upload completes.

If you want to call upload periodically during your application’s execution, you can do so by simply invoking the uploadWithFinishedBlock method on your KeenClient instance at any point.

[[KeenClient sharedClient] uploadWithFinishedBlock:nil];


The Keen iOS client code does a lot of logging, but it’s turned off by default. If you’d like to see the log lines generated by your usage of the client, you can enable logging easily:

[KeenClient enableLogging];

Just put this at any point before you use KeenClient. A good place is in your application delegate.

To disable logging, simply call:

[KeenClient disableLogging];

So, what are you waiting for? It only takes a few minutes and a few lines of code to start collecting the events that really matter to you.

Sign Up Free