Google Analytics – Best Practice for Android

Google Analytics – Best Practice for Android

In this article, I dive deep into how I set up multiple Google Analytics trackers and most importantly, how I keep organized with what data I’m collecting.  Recently I have been more involved with statistical data, focusing on user flow and interaction.  Tracking one or two elements can be very clear on how to setup the data hierarchy. Once you move past the basics, planning and organization are the key ingredients to success.

Getting Starting

This article requires that you are familiar with the basic setup for Google Analytics on Android.  If not, please first go through Google’s documentation.  If you want to add code to your application as you read, you should take the time now to make sure the Android SDK and Google Play Services SDK is added to your project.  If you are still using a separate analytics library, I encourage you to review the latest documentation Google offers before continuing.

In some cases, you may want to use two trackers.  Whether you want the same data going two places or if you want to track data using two separate Analytics tracking id’s, below is the best way I found to setup and initialize multiple trackers.

First let’s setup some basic variables which should mostly be self explanatory.

Now lets add a enum used to identify trackers and define a HashMap to keep track of initialized trackers.  You may not see enums being used very much but I personally love how easy enums can be used and what they accomplish.  I highly suggest you read up on them if you never used them before.

Before we can start tracking we need to initialize an instance of Google Analytics.  If this is not done, your tracking will not work correctly and your app will error at runtime.

Take notice that I .setDryRun(GA_IS_DRY_RUN), which is using the static variable defined above.  This is a boolean that is manually set and controls whether or not actual data gets sent to the server.  If set to true, your tracking hits will only be logged.  You can also see how we set the log level based on the  GA_IS_DRY_RUN variable as well as the runtime build config.  It’s good practice to keep logging to the minimum when the build config is compiled as release.

Now that Google Analytics has an instance initialized, set whether or not this is a dry run and the log level configured… we now need an easy but efficient way to reference each tracker as needed.  For this, I setup a synchronized method.  By using a synchronized method I can get each tracker that I need with it being thread safe.  You can see that this is where the HashMap mTrackers that I set up comes into play.  Also, please notice the simple logic to set  CLIENT_PROPERTY_ID = null  while in debug mode.  This is a easy way to help prevent data corruption from unwanted data being sent to the live server.  Once data is sent to Google’s server, you can’t delete it.  Yes, you can filter or create a new Analytics property… but that is just a huge pain when it could easily be prevented.

Awesome!  If you have read to this point, we are close.  For convenience and sanity, I created multiple Application level methods that keep me organized and consistent.


I create two methods for events HitBuilders.EventBuilder that I track.  The first method is used to only send the event to the global tracker and the second method is used to send the event to both the global and client tracker.  The last method is used by the first two methods to actually send the event to the server.  You can change this as needed to accommodate your specific analytics requirements.  In my case I have some Hits that I only want to send to the global tracker.  I also use some simple logic to NOT to send global tracking data if I am in a Debug build config.  Again, just an easy way to prevent your analytics data from being corrupted.  Please note in the source code I commented this out so I can collect real data for this tutorial.

IMPORTANT Subsequent fields need cleared after the event hit is sent. If you do not clear these fields, every hit thereafter will received unwanted data if you do not set them with new data prior. In the code above, we clear each subsequent field by setting it to null.

Event Screens - Google Analytics

So what is the deal with the subsequentParams?  It’s actually pretty simple.  I use the screen name and app title field to pass some extra data (if needed) for each event.  I recommend to at least send the screen name with each event that you track.  You can use custom dimensions and metrics but this requires a little more manual setup prior to implementation.  In my case I don’t want the burden to show every client how to enter custom fields on their Google Analytics.  This is very tedious due to the fact their indexes need to exactly match the data I am sending to each or it won’t make sense.  If you send custom field data to the server before you set them up the extra data passed would simply not be kept.

Google uses the Screen Name dimension in the events sub menu and is one of the easiest extra fields to see without extensive training.  I always think of who my audience will be to review the data.  Event – Screens are associated with each event and should not be confused with Screens.  I personally always try to use the same names for Event – Screens and Screens for screen tracking.  If you use different values, the data just looks more confusing and is especially harder to visualize in Behavior Flow.

Viewing the App Title field is not as obvious but you can easily view this data when creating a custom report or selecting this field as an extra dimension in the default Events – Overview.


Similar to tracking events, screen views are also tracked by using the  HitBuilders class.  Below you will see that I only have two methods rather than three but they are very similar.  The first method is used to send a Screen Name to each Tracker and the second method is the one that actually sends the event to the server.

In most cases your screen names will be simple.  For example: Home, Details, Events or whatever depending on what kind of app you are working on.  In the app I am currently working on, Phandroid News, I use this structure plus some dynamic data for certain screens.  In the end you just want to make sure you can easily see and use the data that you are tracking.  Below is an example that uses some dynamic data and later in this article you will see it come to life with actual real data.


One last HitBuilders subclass that I would like to show you is the TimingBuilder.  I use this lots of different ways to find out where my code needs improved.  Reducing a few seconds or even just a fraction of a second here and there can go a long way which will improve the overall feel and flow of your application.  You want to be selective on what timed events you are logging so in the end you can understand what code is taking the longest.  If you connect and use data from multiple servers, this is a great way to see which server is faster to deliver results.

Before I get ahead of myself, lets first start with the application level code that is similar to the previous tracking methods that we already covered.

As you can see… this is very similar to what I already shown you.  So let’s move on.

Tracking a TimingBuilder is a little more complex than what I previously showed you.  With tracking timing you are responsible for keeping track of the start and stop time which will be used to get the elapse time (current time – start time).  Once you have this calculated elapse time you would then send the hit to the server similar to the way I showed you to send the previous tracking methods above. To make this a little more centralized, I have created a utilities class called TimeElapseUtils.  I hope by sharing this it makes it easier for everyone to track time events and saves you precious development time.

In this utility class I have an object called  TimeTrack.  I use this object to store all the necessary data into a Map for each time event that I want to track.  In the  trackStart(...) method I pass a String that is used as a key and a new TimeTrack object which initializes with timeUnit, category, name and label fields.  When initiated I automatically set the startTime based on the timeUnit type.  Since I store this  TimeTrack object into a Map I can then reference the data at the time I call  trackStopwhich sends the needed information to the application level code above.

Let me show you a simple example how this would be called.  This is an example of tracking the time of an AsyncTask.  Obviously this is just one of many app flows that you could track and it wouldn’t matter if it is synchronous or asynchronous.  Keep in mind that the main Analytics Tracker will always use background threads to process your Hits.

Simple, right?  You can use my utility class to start and stop when you need to and everything automagically happens for you.

So far we covered my advanced setup for Google Analytics, how I send data to multiple Trackers, most of the HitBuilders subclasses, along with brief examples on how the tracking data is being sent.  Now before we get into viewing the end results I need to reiterate my point at the very beginning of this article that organization is VERY important.


I wasted a lot of time going back and forth trying to make all my data that I am tracking align in one end result.  In short, I eventually created a spreadsheet.  Since I am such a nice guy, I am going to share with you my organization spreadsheet.  It’s nothing special but it will get you started right away and prevent you from wasting time with trying to create the perfect spreadsheet rather than what you should be doing which is… writing code!

Analytics Spreadsheet Template
Click to open on Google Drive

Take that spreadsheet, save a copy and expand it to your needs.  This will allow you to see an overview of everything you are tracking before you start implementing the code.  Trust me, you want consistent data being tracked or it won’t even be worth your time.  Make sure you do check out each tab at the bottom of the spreadsheet, which each tab is setup for each  HitBuilders class that I covered.  The spreadsheet has some data already entered that matches exactly to what the sample source code tracks.

Tracking Results

It’s always easiest to learn from real world examples and it’s important that I show you data from my real world project.  First let’s take a look at what this example application is sending to the server.  This will help you understand all of the examples that I have shown you in this article and help you understand what my code is doing in the projects source code.

Events Overview

Now this is very easy to see what is going on because I only have one category and one action.  The label here is the free form field that you type in and if you would have left it blank, it actually sends the String “Blank”.  The key is when you have multiple categories and multiple actions that don’t complement each other at each hierarchical level, you will become very frustrated when you can’t easily interpret all that precious data that you’ve collected.  I can’t stress enough to use the linked spreadsheet above!  Your future self will thank you :)

Google Analytics - Mobile Top Events

App Speed

In the example project I have code to randomly created the name of the event that is timed.  I also have code to generate a random time from 1000-3000 milliseconds so we can see some data that fluxuates.  A real world example that you will see later, will show you tracking app startup time separated by each process.  Once you figure out the problematic process from using time tracking, you could break it into more level to track each step in this process to determine which part of the code you need to improve.

Google Analytics - Mobile App Speed

Real World Analytics – Phandroid News

Testing example analytical data is always fun but let me show you some real data from one of my most recent apps that I been working on called, Phandroid News.  Our goal was to make this data easy to read for anyone, not just me, the developer.  Sure, I could have tracked events with more developer terms but then the data would only be useful to me.  It’s not only important to know what data you want to track but also who the audience is to review the collected data.  If your audience can’t interpret the analytical data that you collected — well — you just wasted your time.

NOTE  For each portion of data that you are are sending to the server, I recommend that you use defined Strings so you can easily keep the values consistent and avoid typos.  In order to keep these string from changing for each users language, make sure that you define these in donotranslate.xml.  Another approach would be to just define each somewhere as static final String.

Most of this data is obvious and you will be able to see everything clearly but one detail I want to elaborate on is the Screens data.  I not only used traditional screen naming like Home, Settings but also use article titles as dynamic text that goes along with the screen name.  For example: Article – <name of article>.  This allows me to easily use an advanced filter of search for ‘Article – ‘ and the results are wonderful.  We can now see top opened articles from our mobile app.  This is just one example of many ways to track data but you need to find the best for your application.  

Realtime Overview

Google Analytics - Realtime Overview [Phandroid News]

App Speed

Google Analytics - App Speed [Phandroid News]

Behavior Flow

Google Analytics - Behavior Flow [Phandroid News]

App Overview

Google Analytics - App Overview [Phandroid News]


Google Analytics - Screens [Phandroid News]

Custom Dashboard

Google Analytics - Custom Dashboard [Phandroid News]

In summary I showed you the best practice for setting up an advanced Google Analytics tracking configuration. Below you will see the code for this tutorial, which is a nice and neat sample project hosted on GitHub. As I did not covered every HitBuilders subclass, I did however give you enough insight to connect the dots. I do look to expand this code in the near future and like always, I will document my work here. Thanks for reading and I hope that you have found this Analytics information useful!

  • walmyrcarvalho

    Awesome tutorial, thanks for sharing.

  • Donaldson Epignosis

    This is a life saver…. Thanks Steve.

    • Steve Albright

      Awesome, glad to hear! If you have any questions or requests for future updates feel free to let me know.

      • Donaldson Epignosis

        will do. Thank you

  • kencoder

    This is a good stuff!!! Thanks

  • Vanderson

    Thank you very much.