No matter what your motivation is for adding analytics to an iPhone app, it’s easy to get started. Setup is very straightforward and the code is easily abstracted so that you can swap providers and/or use multiple services at the same time. The benefit of doing it this way is that there’s one class file to manage, and less chance to make errors. I recently experimented with adding the new Google Analytics package and it was a breeze to implement. Here’s how I did it.


To get started you’ll need to set up accounts and download SDKs. In the example below I am using the analytics packages from Pinch Media, Flurry, and Google, three of the many choices for the iPhone OS today. Each solution contains one or more header files and a static library to add to your Xcode project. Read the specific instructions for the latest details on configuring your project properly. You may want to use a single one, or you may want to implement more than one to verify/validate your results. Also, each service provides a distinct developer “dashboard” of results; you’ll soon discover which one suits your particular needs.

All of the analytics packages I’ve used follow a similar pattern: create a singleton instance, initialize it at startup, log events, cleanup and terminate at shutdown. I’ve encapsulated this behavior in my own class like this:

// MMTrackingController.h
// Copyright Mundue LLC 2008. All rights reserved.

@interface MMTrackingController : NSObject {
+ (MMTrackingController*) sharedTrackingController;
- (void) startTracking;
- (void) stopTracking;
- (void) logEvent:(NSString*)event;

Import the MMTrackingController.h file in your application delegate and add the housekeeping code like this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Add this first to track launch events.
[[MMTrackingController sharedTrackingController] startTracking ];
[[MMTrackingController sharedTrackingController] logEvent:@”Launch” ];


- (void)applicationWillTerminate:(UIApplication *)application {

// Add this last to track terminate events.
[[MMTrackingController sharedTrackingController] logEvent:@”Terminate” ];
[[MMTrackingController sharedTrackingController] stopTracking ];

Now you just need sprinkle logging calls wherever you need them in your code. For a game, this might be when an achievement is earned, or high scores are bested. Here are some examples:

[[MMTrackingController sharedTrackingController] logEvent:@”newGame” ];

[[MMTrackingController sharedTrackingController] logEvent:@”addHighScore” ];

[[MMTrackingController sharedTrackingController] logEvent:@”gameOver” ];

That’s really all there is to it. The details of the tracking controller are not that interesting, but that’s where you’ll hook up the various back-end services. I’m currently using Flurry, Pinch Media, and Google Analytics, but I’ve also hooked up Mobclix and others in the same way. Implement the tracking controller singleton like this:

// MMTrackingController.m
// Copyright Mundue LLC 2008. All rights reserved.

#import “MMTrackingController.h”
#import “Beacon.h” // The pinch API
#import “FlurryAPI.h” // The flurry API
#import “GANTracker.h” // The google API

static MMTrackingController* _sharedTrackingController = nil;

+ (MMTrackingController*) sharedTrackingController {
if ( _sharedTrackingController == nil ) {
_sharedTrackingController = [[MMTrackingController alloc] init];
return _sharedTrackingController;

- (void) startTracking {
[Beacon initAndStartBeaconWithApplicationCode:@"abcdef1234567890" // Your pinch app id
useCoreLocation:NO // or YES
useOnlyWiFi:NO]; // or YES
[FlurryAPI startSession:@"abcdef1234567890"]; // Your flurry app id
[[GANTracker sharedTracker] startTrackerWithAccountID:@”us123456-00″ // Your google tracking code
dispatchPeriod:10 // some amount of time
delegate:nil]; // read the google API docs

- (void) stopTracking {
[[Beacon shared] endBeacon];
// Flurry:Nothing to do
[[GANTracker sharedTracker] stopTracker];

- (void) logEvent:(NSString*)event {
[[Beacon shared] startSubBeaconWithName:event
[FlurryAPI logEvent:event];
NSError *error;
if (![[GANTracker sharedTracker] trackEvent:@”reMovem free” // “category”
action:event //read the google API docs
withError:&error]) {
// Handle error here


You’ll need to take the standard precautions when implementing your singleton (shared instance) class, to avoid potential multiple allocations and threading issues. I’ve left the details of that out, see the Cocoa documentation for complete information.


Calls made to the tracking code are typically cached on the device in a sqlite database, then sent to the server only when a connection is available. Modern implementations will not waste time or battery by constantly attempting to connect, but do so at well-defined times like launch and shutdown. If a connection is not available, the cached information is simply updated and saved for the next session.

Most services take several hours to aggregate the data. That is, you won’t see results immediately, but definitely within a day. Because all devices are not always connected, the data could appear days or even weeks later, when a connection is eventually made. I usually don’t consider the data from within the last several days to be fully baked, but it will help you to see trends nevertheless.

If you’ve ever used Google Analytics for a website, you’ll be familiar with the types of reports available on the developer dashboards. Each service gives a breakdown of accumulated events (that you logged with logEvent) and unique “visitors,” or users. For example, here is a snippet of the Google Analytics for an unreleased application:


You normally want to drill down into the “events” to get an idea of what is going on. This shows the Pinch Media event reporting for a random period of days for one of my games:


The event reporting again, this time in Flurry:


You can see the wide variety in reporting styles, and each includes the ability to download or save as CSV or XLS data files. You can easily import the data into Excel or Numbers and manipulate it further on the desktop, if desired. If you want to see how many users, or how many sessions occurred, you can easily get that too. In fact the level of detail in some reports is too much, and often a simple graph paints a pretty good picture, like this (also from Flurry):



It’s easy to add a tracking controller to manage the various analytics packages you might want to use. By merely commenting out a few lines (or #ifdef-ing them out) in the tracking controller you can enable and disable new ones without rewriting the other parts of your code. With a little bit of imagination, you can even allow the code to turn on and off the various tracking mechanisms. However, should you wish to provide a more generic “opt-out” mechanism there are other ways. See each SDK for specific details.

Hope this helps. Enjoy!