Accurate Apple Device Reporting in Google Analytics

Posted by Craig Edwards on 4 February
Craig Edwards

For some reason Google Analytics doesn't expose a dimension that represents which specific model of iPhone/iPad that the user is using (iPhone 4, iPhone 5, iPad Mini 2, et al). This makes it very difficult to track your mobile users' usage by specific device type.

This article describes the technique that Bilue uses to provide a comprehensive, accurate, future-proof solution.

Possible Solutions

Firstly, let's look at a couple of other techniques that are often considered and discuss the shortcomings of each.

Option 1. Raw values from utsname

Apple offers APIs to retrieve the raw identifier (eg. iPhone7,2). For example:

#import <sys/utsname.h>

struct utsname un;
uname(&un);
NSString *identifier = [NSString stringWithCString:un.machine encoding:NSUTF8StringEncoding];

This identifier can then be sent to Google Analytics as a custom dimension.

However, the values returned from this API (eg. iPhone7,1) are not fit for human consumption. Business stakeholders don't want to see reports containing these values. Not only that, it is virtually impossible to look at the values and know which specific identifiers are related to which physical devices.

This is a technically correct solution, but offers little business value.

Option 2. In-app mapping

This seems to be the most commonly chosen solution, and basically involves the app having a big lookup table that maps the raw device identifier mentioned above into something more readable (eg. iPhone 6 Plus), and then sending this translated value to Google Analytics as a custom dimension.

The big problem with this is that the lookup table is hard-coded into the app at the time the app is shipped. The lookup logic will not know what type of device it is running on for any phone that was launched after the app was released. At that point, it has two choices:

  • Send a generic value like Unknown. In this case, Google Analytics will have a whole collection of events that are all lumped in together as coming from unknown devices. Consider the case when Apple launches 3 new phones... all three phones will be reporting as the same type: Unknown.
  • Send the raw identifier iPhoneX,Y. This is a more technically correct solution in that it doesn't lose the raw information, however, the output in the reports will continually have to be massaged because it will contain a mixture of human readable device names and raw device identifiers.

Every time new devices are launched by Apple, the only hope for correct reporting is to release a new version of the app and hope that users choose to upgrade.

This is a brittle solution.

Option 3. Screen resolution

Out of the box, Google Analytics does provide a Screen Resolution dimension that contains values like 375x667. At a high level, these values can be reverse engineered to determine roughly what type of device it was based on the following table:

  • 320x480 => iPhone 4 (and smaller)
  • 320x568 => iPhone 5
  • 375x667 => iPhone 6
  • 414x736 => iPhone 6+
  • ... plus some other values for iPad

Again, this has problems in the reporting space because the translation of the resolutions to specific models is non-obvious to the casual observer. It also is very general in that you cannot differentiate between, say, the iPhone 5, 5c and 5s.

Data Mapping in Google Analytics

An oft-overlooked feature in Google Analytics is the ability to upload a mapping file that can be used to translate custom dimensions from one value to another. We can use this to our advantage to get Google Analytics to perform the mapping.

Solution Overview

Broadly speaking, the solution involves the following steps:

  • When setting up Google Analytics, a mapping file is created to map the raw identifiers (iPhone7,1) into human readable variants (iPhone 6 Plus)
  • At run-time, the phone sends up the raw device identifier (iPhone7,1)
  • Google Analytics maps that raw identifier into the human readable value
  • Run reports using the mapped human readable version value
  • Profit?

When new devices are released by Apple, the mapping info can be updated in Google Analytics without having to ship a new app.

Another awesome benefit is that Google Analytics will also apply that new mapping info to historical events, so even if you take a few days/weeks to update the mapping info after a new device is released, it will be retroactively applied.

Implementation Details

Creating Custom Dimensions in Google Analytics

We are going to create three new Custom Dimensions in Google Analytics:

  • appleDeviceModel - Contains the raw device identifier sent from the device. eg. iPhone5,3
  • formFactor - Contains a reasonably general description. eg. iPhone 5
  • formFactorDetailed - Contains a pretty exact description. eg. iPhone 5c (GSM)

To do this, click on the Admin tab at the top of Google Analytics, and navigate your way to the Custom Definitions/Custom Dimensions menu for your property. Add 3 new Session dimensions with the names outlined above.

Google Dimensions

Your dimension numbers may be different depending on how many custom dimensions you are already using. Take note of the dimension numbers; you will need them in the next step.

Creating input data

Now you need to create a file that contains the mapping info.

Important: The first row of the mapping file must contain the dimension numbers of the dimensions you just created. The first one is the key (appleDeviceModel), and the next two are the values that will be mapped (formFactor and formFactorDetailed).

For reference, our latest file looks like:

ga:dimension7,ga:dimension8,ga:dimension9
"iPhone1,1","iPhone 2","iPhone 2G"
"iPhone1,2","iPhone 3","iPhone 3G"
"iPhone2,1","iPhone 3","iPhone 3GS"
"iPhone3,1","iPhone 4","iPhone 4"
"iPhone3,2","iPhone 4","iPhone 4"
"iPhone3,3","iPhone 4","iPhone 4"
"iPhone4,1","iPhone 4","iPhone 4S"
"iPhone5,1","iPhone 5","iPhone 5"
"iPhone5,2","iPhone 5","iPhone 5 (GSM+CDMA)"
"iPhone5,3","iPhone 5","iPhone 5c (GSM)"
"iPhone5,4","iPhone 5","iPhone 5c (GSM+CDMA)"
"iPhone6,1","iPhone 5","iPhone 5s (GSM)"
"iPhone6,2","iPhone 5","iPhone 5s (GSM+CDMA)"
"iPhone7,1","iPhone 6","iPhone 6 Plus"
"iPhone7,2","iPhone 6","iPhone 6"
"iPhone8,1","iPhone 6+","iPhone 6s"
"iPhone8,2","iPhone 6+","iPhone 6s Plus"
"iPod1,1","iPod 1","iPod Touch (1 Gen)"
"iPod2,1","iPod 2","iPod Touch (2 Gen)"
"iPod3,1","iPod 3","iPod Touch (3 Gen)"
"iPod4,1","iPod 4","iPod Touch (4 Gen)"
"iPod5,1","iPod 5","iPod Touch (5 Gen)"
"iPad1,1","iPad 1","iPad"
"iPad1,2","iPad 1","iPad 3G"
"iPad2,1","iPad 2","iPad 2 (WiFi)"
"iPad2,2","iPad 2","iPad 2"
"iPad2,3","iPad 2","iPad 2 (CDMA)"
"iPad2,4","iPad 2","iPad 2"
"iPad2,5","iPad Mini","iPad Mini (WiFi)"
"iPad2,6","iPad Mini","iPad Mini"
"iPad2,7","iPad Mini","iPad Mini (GSM+CDMA)"
"iPad3,1","iPad 3","iPad 3 (WiFi)"
"iPad3,2","iPad 3","iPad 3 (GSM+CDMA)"
"iPad3,3","iPad 3","iPad 3"
"iPad3,4","iPad 4","iPad 4 (WiFi)"
"iPad3,5","iPad 4","iPad 4"
"iPad3,6","iPad 4","iPad 4 (GSM+CDMA)"
"iPad4,1","iPad Air","iPad Air (WiFi)"
"iPad4,2","iPad Air","iPad Air (Cellular)"
"iPad4,4","iPad Mini 2","iPad Mini 2 (WiFi)"
"iPad4,5","iPad Mini 2","iPad Mini 2 (Cellular)"
"iPad4,6","iPad Mini 2","iPad Mini 2"
"iPad4,7","iPad Mini 3","iPad Mini 3"
"iPad4,8","iPad Mini 3","iPad Mini 3"
"iPad4,9","iPad Mini 3","iPad Mini 3"
"iPad5,1","iPad Mini 4","iPad Mini 4 (WiFi)"
"iPad5,2","iPad Mini 4","iPad Mini 4 (LTE)"
"iPad5,3","iPad Air 2","iPad Air 2"
"iPad5,4","iPad Air 2","iPad Air 2"
"iPad6,8","iPad Pro","iPad Pro"
"AppleTV2,1","Apple TV","Apple TV 2G"
"AppleTV3,1","Apple TV","Apple TV 3"
"AppleTV3,2","Apple TV","Apple TV 3 (2013)"
"AppleTV5,3","Apple TV","Apple TV 3 (2013)"
"i386","Simulator","Simulator"
"x86_64","Simulator","Simulator"

Importing Custom File

Using the Admin/Data Import menu item for your Google Analytics property, perform the following actions:

  • Create a new Data Set
  • Choose Custom Data
  • Give it a name like Apple Device Identifier to Form Factor Mapping
  • Choose which view you want it applied to (you probably want all views)
  • Click on Next Step
  • Select appleDeviceModel as the key
  • Select formFactor and formFactorDetailed as the imported data.

Your settings should look like the following screenshot.

Google Data Import

  • Click on Save
  • Click on Finished

At this point, you've defined how the mapping will be performed but you haven't loaded any data.

Choose the Managed Uploads option for your newly created data set, and upload the file containing the mapping data. Google Analytics will verify that your data matches what it expects (for example, the header rows match the custom dimension numbers, and the coloumn count is correct). You will notice that the Status field will be temporarily be set to Processing - sometimes this takes a few minutes to change to Completed.

At this stage, the import is successful and the data will start to be mapped.

Posting from App

The behaviour within the app is pretty straightforward. You just need to send the raw device identifier to Google Analytics as a custom dimension (making sure that you reference the correct number). In the example above, the appleDeviceModel dimension is 7.

#import <sys/utsname.h> 

struct utsname un;
uname(&un);
NSString *identifier = [NSString stringWithCString:un.machine encoding:NSUTF8StringEncoding];
[tracker set:[GAIFields customDimensionForIndex:7] value:identifier];

Downsides

So far, the only downside with this approach is that the mapped custom dimension data is not available in the Real-Time view of Google Analytics. For us, this hasn't been a real problem but it is worth mentioning.

And, of course, it is worth mentioning that there has to be a very real discipline of updating the mapping data in Google Analytics when Apple releases new devices. As I mentioned before, though, at least these updates can be made outside of the app release cycle.

New Call-to-action

Topics: Development, Mobile