This is how we implemented metrics in recent apps I’ve worked on:
Right before the app shipped we’d go thru the app and anywhere something interesting happened, we’d add a metric by naming it and inserting a line of code to trigger the metric. Some header file would contain all the metric names.

Later after the app shipped we’d need to answer a question like: How many of our users are using a specific feature? To answer this, we’d open up the header file, find the right metric name. Often times the names are confusing and we’d dig into the code. With the metric name in hand, we’d then figure out how to lookup the metric data using the web interface of the metrics provider.

The whole process is clunky. Peppering the app with metrics calls is a laborious task. Inevitably we’d miss adding a metric call somewhere and our metrics would be blind to that area. I also never liked the web interface of any of the metrics providers. No matter what their marketing copy said, everything felt like web metrics bolted onto mobile apps.

When I started work on my latest app, I decided to rethink this clunky metrics approach. Here is the solution I ended up with:

  1. Use Keen.io as the backend provider of metrics
    Keen’s tagline is “Analytics Backend as a Service”. They provide three basic parts:

  2. Write a simple iOS library that auto handles most of the interesting iOS metrics
    When you really think about it, how we interact with apps is pretty standard. Apps are launched, we navigate in and out of views and on those views we tap and touch things on the screen.
    By thinking generically about these things and how to automatically record them, we can skip the entire laborious process of instrumenting an app for metrics.

PBMetrics

The PBMetrics library has two basic parts. The first is PBMetricsManager which handles the basics of calling the Keen iOS SDK to report metrics. It also handles the basic concept of a session.

Sessions

Here’s how PBMetrics handles sessions:
When the app comes to the foreground, the current time is saved locally as the start of the session.
When the app goes to the background, the current time is used as the end time and a metric session is sent to the server with the start time, end time and session duration.

Standard attributes

One of the nice things about Keen is that a metric/event is simply a JSON dictionary. What goes in that dictionary is up to you.

The Keen iOS library creates a “keen” entry with a timestamp, created_at and optionally a location attribute.

PBMetrics adds a “standard_properties” entry with lots of standard stuff about the device, the app and other global information

Here’s an example of an app session metric:

{
    "keen": {
        "created_at": "2013-06-04T21:19:08.026000+00:00",
        "location": {
            "coordinates": [
                -122.4183,
                37.775
            ]
        },
        "timestamp": "2013-06-04T21:19:05+00:00"
    },
    "session_duration": 23.580490946769714,
    "session_end": "2013-06-04T14:19:05-0700",
    "session_start": "2013-06-04T14:18:41-0700",
    "standard_properties": {
        "app_build_number": "1.0",
        "app_version": "1.0",
        "device": "x86_64",
        "device_name": "Simulator",
        "enabled_remote_notification_types": [],
        "first_time_app_launch": "1",
        "jb": "0",
        "language": "en",
        "location_services_enabled": "1",
        "logged_in": "1",
        "logged_in_user": {
            "email": "foo@foo.com",
            "name": "User"
        },
        "model": "iPhone Simulator",
        "screen_scale": 2,
        "system": "iPhone OS",
        "system_version": "6.1"
    }
} 

Base Classes

The second part of the library is a set of base classes that record basic events.
For example a base class for UIViewController records when the view controller is on screen. A base class for a button records a metric when it is tapped. A base table view controller class records a metric when a cell is tapped.

Here is a metric recorded for a view controller appearing on screen:

{
    "appear_time": "2013-06-04T14:18:39-0700",
    "appearance_duration": 6.953963994979858,
    "appeared_animated": false,
    "class_name": "FirstViewController",
    "disappear_time": "2013-06-04T14:18:46-0700",
    "disappeared_animated": false,
    "is_being_dismissed": false,
    "is_being_presented": false,
    "is_moving_from_parent_view_controller": false,
    "is_moving_to_parent_view_controller": false,
    "keen": {
        "created_at": "2013-06-04T21:19:08.033000+00:00",
        "location": {
            "coordinates": [
                -122.4183,
                37.775
            ]
        },
        "timestamp": "2013-06-04T21:18:39+00:00"
    },
    "standard_properties": {
        "app_build_number": "1.0",
        "app_version": "1.0",
        "device": "x86_64",
        "device_name": "Simulator",
        "enabled_remote_notification_types": [],
        "first_time_app_launch": "1",
        "jb": "0",
        "language": "en",
        "location_services_enabled": "1",
        "logged_in": "1",
        "logged_in_user": {
            "email": "foo@foo.com",
            "name": "User"
        },
        "model": "iPhone Simulator",
        "screen_scale": 2,
        "system": "iPhone OS",
        "system_version": "6.1"
    },
    "was_popped": false,
    "was_pushed": false
} 
}

Here’s a metric when a tab bar item is selected:

{
    "keen": {
        "created_at": "2013-06-04T21:19:07.873000+00:00",
        "location": {
            "coordinates": [
                -122.4183,
                37.775
            ]
        },
        "timestamp": "2013-06-04T21:18:49+00:00"
    },
    "standard_properties": {
        "app_build_number": "1.0",
        "app_version": "1.0",
        "device": "x86_64",
        "device_name": "Simulator",
        "enabled_remote_notification_types": [],
        "first_time_app_launch": "1",
        "jb": "0",
        "language": "en",
        "location_services_enabled": "1",
        "logged_in": "1",
        "logged_in_user": {
            "email": "foo@foo.com",
            "name": "User"
        },
        "model": "iPhone Simulator",
        "screen_scale": 2,
        "system": "iPhone OS",
        "system_version": "6.1"
    },
    "tab_bar_selected": "FirstViewController"
} 

Take a look at the PBMetrics source on github and let me know what you think:
https://github.com/boctor/pbmetrics

Tweet This!Hacker NewsShare on Facebook

Advertisements