Integration Overview Guide for App Analytics
This guide aims to help a developer understand the high level points of integrating with Localytics which are relevant to all platforms. It is possible to get away with just reading the 10 minute Integration Guides, but this document covers more topics and provides greater detail.
Platform Specific Guides
Here is the documentation specific to each platform. It is recommended that this page be read first because this material is relevant to all platforms and is not covered in as much depth in the guides, but you may skip ahead if you are in a hurry.
These are some of the terms we use in discussion of analytics:
- session – The span over which analytics are collected. In almost all cases this will be the start of your application to the end of your application.
- datapoint or metric – A piece of data collected about a user, such as device make, or carrier.
- event – An action or situation which occurred in an application which a developer wishes to track. Examples include:
- - user clicks on a button
- - user sets a particular setting
- - user reaches a new level in a game
- tag – The act of recording an event.
- attributes – the additional data which may be collected and associated with a tag
The process of integrating with the Localytics service consists of several steps:
- 1) Registering with the webservice and creating an API key for the application.
- 2) Downloading the client library for the correct platform from the homepage.
- 3) Instantiating the object, and adding calls to open(), upload(), and close.
- 4) (Optional) Adding tagEvent() calls to record specific events.
- 5) (Optional-Premium) Adding tagScreen() calls to record specific screens.
- 6) Testing the integration by running the app and viewing the uploaded data.
TIP: Once data is uploaded it cannot be deleted. Therefore it is recommended to create a test app in Localytics and use that while you perfect your instrumentation and then switch the app key for the production app.
Library Design Goals
The libraries were created on each platform with the following goals:
- - Be as transparent as possible. This code is running in the integrator’s application and they have a right to know what it does.
- - Maintain as consistent an API and integration model across platforms as possible.
- - Minimize integration effort. A minimum integration should take less than 15 minutes.
- - Provide enough flexibility to allow deeper integration if desired.
- - Keep the design simple so it can be adapted to fit custom requirements
Adding the Object
Once you have included the library in your project, the following function calls are used to control your session:
- open() – Opens the session for data collection and records some basic user data such as country, carrier, and device model. This should be done as early in the code as possible because this is what determines the session start time. Any calls to other data collection functions such as getLocation(), tagEvent(), and close() will do nothing until the session is opened. This is a synchronous call which does not create any threads. Once it returns no cycles will be consumed by Localytics until the next Localytics API call is made.
- upload() – This causes a new, low-priority thread to be created which uploads any data collected for this application including any previously stored sessions which did not get uploaded. It is best to have this call happen after the open() call so this session’s basic data gets uploaded. Once the data upload is done the thread terminates and will not have further impact on the application. This model causes each session to get uploaded in two parts. The open blob gets uploaded immediately, and the rest of the session gets uploaded the next time the app is stared. It would be nice to upload the rest of the session after closing it, however the close call usually happens as the app is exiting and on most platforms it is not possible to do the upload at this time without delaying the app exit which would provide a bad user experience. In some platforms, such as iPhone and Android, it is possible to have a second upload() call when the application is destroyed because on these platforms the user is brought back to the home screen while the upload is happening so the upload will not impact the user experience.
- close() – Closes the session. This should be called at the end of program execution because it determines the end time for the session. Like open, this is a synchronous call and once it completes no further work is done.
- tagEvent() – (Optional) Records specific events in an opened session. Examples include ‘Button 1 was pressed’ and ‘Player got to level 5′. This is another synchronous call which has no impact on the application after it returns. This function also supports a list of key/value pairs of extra data to associate with a given tag.
- tagScreen() – (Optional-Premium) Records screens visited in an opened session. This is another synchronous call which has no impact on the application after it returns.
- setOptIn / isOptedIn – (Optional) These functions are provided to allow the developer the ability to let the user choose whether or not they are opted in to data collection. Be aware that there are significant business ramifications to enabling opt in because this will cause data skew.
As mentioned above it is possible to tag specific events in an application with a string describing the event. This is particularly useful for answering business questions and design questions such as:
- - What options do users prefer?
- - What level in a game do users tend to get to?
When doing this, it is best to use constant strings defined at compile time. This is advantageous because it avoids the risk of collecting personally identifiable information, it is more efficient, and it guarantees that the charts on the webservice won’t have too many events to be actionable. In some cases it is acceptable to create these strings dynamically. For example, consider a game with an infinite number of levels. It might be appropriate to record an event named START_LEVEL_X (where X is the current level) every time a user reaches a new level.
To make tagging work for you, keep the following points in mind:
- - Avoid tagging events in a loop. This can cause enough data to be collected as to impact the user.
- - Tags are only useful if they are comparable across sessions. To guarantee this, make sure the string you pass to the tagEvent API is a constant.
- - If you wish to compare behaviors across versions it will be necessary to keep the tag names the same. So choose names that are not version specific.
- - If a tag exists in a code path, make sure all code paths are covered. If an event can be reached in multiple ways, and only some of the ways are tagging the event the data will be skewed.
- - Consider when to use Event Attributes while tagging. For example, determining which options are on in an settings screen a user selected is best done by having a single event which is uploaded when the user closes the screen which captures each specific option as an attribute.
Following on the idea of tagging, Localytics also allows you to upload attributes associated with your tags. This can be very powerful, as demonstrated in our blog post introducing the feature. However, to get the best mileage out of your attributes, keep the following in mind:
Most importantly make sure never to upload data from a continuous set. Consider tagging a file transfer event with the file size. If the file can be any size this will cause many buckets to be created on our server. When you look at the data in the charts, there will be many charts each with only a few results and the data will be in-actionable. Instead, it is necessary to bucket this data into groups such as “0 to 1K”, “1K to 50K”, etc.
Only tag events with information that is interesting. It is easy to fall into the trap of overtagging events. This will only result in making it harder to answer the questions you really care about because the charts will be full of extraneous data.
Only 10 attributes per event may be recorded, the rest will be discarded.
Crashes / Exceptions
Using event attributes it is possible to collect data about exceptions and crashes w/in your application. All platforms provide some way to catch exceptions globally, either through an exception filter or by just wrapping the code in a try/catch. Normally this isn’t a good practice but with analytics it is helpful because you can tag an event in the exception filter with data about what the exception was, and where it occurred in the code. As a result there will be a event in your dashboard showing how many exceptions have been hit as well as what and where they were.
Instrumentation Best Practices
- - Data collection should never happen in a loop. This can cause excessive amounts of data to be stored and uploaded.
- - Only one LocalyticsSession should be used inside an application. If multiple objects, or multiple keys are used there is the risk of sessions clobbering each other.
- - All sessions should be closed. It is a good practice to have a single app exit point, and close the session there.
- - Event Tagging must not be used to collect Personally Identifiable Information. All logged information should be predefined constants.
Testing the Instrumentation
The value of the instrumentation effort is only as good as the data collected. So it is important to test the integration to ensure data is being uploaded. The service updates data in real time so the simplest thing to do is run the application in an emulator or, even better, on an actual device and verify the data is visible on the webservice. Some things to consider when testing instrumentation include:
- - Mobile applications often have multiple entry and exit points. Do all of them cause an open() and close() call to occur?
- - Is it possible to have multiple instances of the application running at the same time? If so, each instance should be creating a new object.
- - Do all of the tagged events appear?
- - Has upload been called early enough to allow the application time to upload?
- - Are all code paths instrumented? If you record an event after a code branch, should there be another event on the other branch?