Analytics for Android

Maven Central

Analytics for Android makes it dead simple to send your data to any tool without having to learn, test or implement a new API every time.

All of our client sources are open-source, so you can view Analytics for Android on Github, or check out our browser and server-side sources too.

Want to stay updated on releases? Subscribe to the release feed.

Analytics for Android only supports API 14 (Android 4.0) and higher. You should consider it too!

Getting Started

Step 1: Install the Library

The recommended way to install the library for Android is with a build system like Gradle. This makes it dead simple to upgrade versions and add integrations. The library is distributed via Maven Central. Simply add the analytics module to your build.gradle:

dependencies {
  compile ''

Packaging SDKs for Device-based Connection Modes

In the interest of keeping our SDK lightweight, the analytics artifact only installs the Segment integration. This means that all your data will be sent via Segment’s servers to any tools you’ve enabled with server-side-compatible integrations.

As described here, some integrations require or offer Device-based connection modes. In those cases, you’ll need to take some additional steps as shown in the source documentation here.

Now that the SDK is installed and setup, you’re ready to…

Step 2. Initialize the Client

We recommend initializing the client in your Application subclass.

// Create an analytics client with the given context and Segment write key.
Analytics analytics = new Analytics.Builder(context, YOUR_WRITE_KEY)
  .trackApplicationLifecycleEvents() // Enable this to record certain application events automatically!
  .recordScreenViews() // Enable this to record screen views automatically!

// Set the initialized instance as a globally accessible instance.


  • Automatically tracking lifecycle events (Application Opened, Application Installed, Application Updated) and is optional, but highly recommended to hit the ground running with core events!
  • This only installs the Segment integration. This means that all your data will be sent server side to tools. If you need to bundle additional integrations client side, you’ll need to take some additional steps as shown here.

Optional Customizing the Client

The entry point of the library is through the Analytics class. As you may have seen in the quickstart, here’s how you initialize the Analytics client with it’s defaults.

Analytics analytics = new Analytics.Builder(context, writeKey).build();

The Analytics.Builder class lets you customize settings for the Analytics client, including things like the flush interval and packaging Device-based integrations. Please refer to the Javadocs for details on customizable parameters.

We also maintain a global default instance which is initialized with defaults suitable to most implementations.

// You can also register your custom instance as a global singleton.

In general, we recommend using the Builder method as it provides the greatest flexibility. Keep in mind that you can call Analytics.setSingletonInstance only ONCE, so it’s best to stash the initialization code inside your custom Application class.

public class MyApp extends Application {
  @Override public void onCreate() {
    Analytics analytics = new Analytics.Builder(context, writeKey).build();

    // Safely call Analytics.with(context) from anywhere within your app!
    Analytics.with(context).track("Application Started");

Once you have initialized an Analytics client, you can safely call any of it’s tracking methods from any thread. These events are dispatched asynchronously to our servers and Device-based integrations.

Note: You should only ever initialize ONE instance of the Analytics client. These are expensive to create and throw away, and in most cases, you should stick to our singleton implementation to make using the SDK easier.

Step 3. Add Permissions

Ensure that the necessary permissions are declared in your application’s AndroidManifest.xml.

 <!-- Required for internet. -->
<uses-permission android:name="android.permission.INTERNET"/>


identify lets you tie a user to their actions and record traits about them. It includes a unique User ID and any optional traits you know about them.

We recommend calling identify a single time when the user’s account is first created, and only identifying again later when their traits change.

Example identify call:

Analytics.with(context).identify("a user's id", new Traits().putName("a user's name"), null);

We recommend calling identify a single time when the user’s account is first created, and only identifying again later when their traits change. We’ll remember the previous user id and merge the new traits with the old ones.

// Initially when you only know the user's name
Analytics.with(context).identify(new Traits().putName("Michael Bolton"));

// Sometime later in your app when the user gives you their email
Analytics.with(context).identify(new Traits().putEmail(""));

Hold up though! When you actually put that code in your Android app, you’ll need to replace all those hard-coded strings with details about the currently logged-in user.

The identify call has the following fields:

userId String,optionalThe database ID for this user.
traits Traits,optionalA map of traits about the user, such as their name, email, address, etc.
options Options, optionalExtra options for the call.

The identify call has the following fields:


track lets you record the actions your users perform. Every action triggers what we call an “event”, which can also have associated properties.

To get started, our SDK can automatically tracks a few key common events with our Native Mobile Spec, such as the Application Installed, Application Updated and Application Opened. Simply enable this option during initialization.

You’ll also want to track events that are indicators of success for your mobile app, like Signed Up, Item Purchased or Article Bookmarked. We recommend tracking just a few important events. You can always add more later!

Example track call:

Analytics analytics = new Analytics.Builder(context, writeKey)

Analytics.with(context).track("Product Viewed", new Properties().putValue("name", "Moto 360"));

This example track call tells us that your user just triggered the Product Viewed event with a name of “Moto 360.”

track event properties can be anything you want to record, for example:

Analytics.with(context).track("Purchased Item", new Properties().putValue("sku", "13d31").putRevenue(199.99));

The track call has the following fields:

name String,requiredA name for the tracked action.
properties Properties,optionalA map of properties for this action, e.g. revenue if the action was a purchase.
options Options,optionalExtra options for the call.

Find details on best practices in event naming as well as the track method payload in our Spec.


The screen method lets you you record whenever a user sees a screen of your mobile app, along with optional extra information about the page being viewed.

You’ll want to record a screen event an event whenever the user opens a screen in your app. This could be a view, fragment, dialog or activity depending on your app.

Not all services support screen, so when it’s not supported explicitly, the screen method tracks as an event with the same parameters.

Example screen call:

// category "Feed" and a property "Feed Length"
Analytics.with(context).screen("Feed", new Properties().putValue("Feed Length", "26"));

// no category, name "Photo Feed" and a property "Feed Length"
Analytics.with(context).screen(null, "Photo Feed", new Properties().putValue("Feed Length", "26"));

// category "Smartwatches", name "Purchase Screen", and a property "sku"
Analytics.with(context).screen("Smartwatches", "Purchase Screen", new Properties().putValue("sku", "13d31"));

The screen call has the following fields:

category String,optional*A category for the screen. Optional if name is provided.
name String,optional*A name for the screen. Optional if category is provided.
properties Properties,optionalA map of properties for this screen.
options Options,optionalExtra options for the call.

Find details on the screen payload in our Spec.


group lets you associate an identified user user with a group. A group could be a company, organization, account, project or team! It also lets you record custom traits about the group, like industry or number of employees.

This is useful for tools like Intercom, Preact and Totango, as it ties the user to a group of other users.

Example group call:

Analytics.with(context).group("a user's id", "a group id", new Traits().putEmployees(20));

The group call has the following fields:

userId String,requiredThe database ID for this user.
groupdId String,requiredThe database ID for this group.
traits Traits,optionalA map of traits about the group, such as the number of employees, industry, etc.
options Options,optionalExtra options for the call.

Find more details about group including the group payload in our Spec.


alias is how you associate one identity with another. This is an advanced method, but it is required to manage user identities successfully in some of our integrations.

In Mixpanel it’s used to associate an anonymous user with an identified user once they sign up. For KISSmetrics, if your user switches IDs, you can use ‘alias’ to rename the ‘userId’.

Example alias call:


The alias call has the following fields:

newId String,requiredThe new ID to track this user with.
options Options,optionalExtra options for the call.

For more details about alias, including the alias call payload, check out our Spec.

Note that the previousId will be the value passed in as the userId, which we cached after you make an identify call. We will pass that value as the previousId when you call alias and pass in a newId. If you have not called identify, the previousId will be the anonymousId.

Selecting Integrations

The alias, group, identify, page and track calls can all be passed an object of options that lets you turn certain integrations on or off. By default all integrations are enabled.

For instance, in the snippet below, the first event is sent to all integrations, but the second one is sent to all except Mixpanel.

// Sent to all integrations
Analytics.with(context).track("Viewed Item", new Properties());

// Sent to all integrations, except Mixpanel
Analytics.with(context).track("Purchased Item", new Properties(), new Options().setIntegration(BundledIntegrations.MIXPANEL, false));

If you have built your own instance of the client, you can also specify a default options object that will be used for each call. In the snippet below, NONE of the analytics events will be sent to Heap.

// Disable Heap integration
Options defaultOptions = new Options().setIntegration("Heap", false);

// Attach the options to our client
Analytics analytics = new Analytics.Builder(context, writeKey).defaultOptions(defaultOptions).build();
// Set the client as a global singleton so it can be called from anywhere

// Now any calls made with this Analytics client won't be sent to Heap
Analytics.with(context).track("Viewed Item", new Properties());

Notice that in the first snippet, we used an Enum to disable the integration, but in the second snippet, we used a String. In general, we recommend, using the Enum method for Device-based integrations (this way you get type safety, and don’t accidentally disable “GoogleAnalytics” instead of “Google Analytics”), and pass in a String for controlling the behavior of server side integrations.

Integration flags are case sensitive and match the integration’s name in the docs (i.e. “AdLearn Open Platform”, “”, “MailChimp”, etc.).

Note: Available at the business level, filtering track calls can be done right from the Segment UI on your source schema page. We recommend using the UI if possible since it’s a much simpler way of managing your filters and can be updated with no code changes on your side.


Context is a dictionary of extra information you can provide about a specific API call. You can add any custom data to the context dictionary that you’d like to have access to in the raw logs. Some keys in the context dictionary have semantic meaning and will be collected for you automatically, e.g. the information about the device the user is on.

AnalyticsContext analyticsContext = Analytics.with(context).getAnalyticsContext();

You can read more about these special fields.

If you’d prefer to opt out of automatic data collection, simply clear the context right after initializing the client. It’s important to do this BEFORE sending any events.

Analytics analytics = new Analytics.Builder(context, writeKey).defaultOptions(defaultOptions).build();
AnalyticsContext context = analytics.getContext();


You can retrieve the anonymousId set by the library by using:



If you run into any issues while using the Android library, we recommend turning on logging to help us trace the issue. The default singleton instance will have logging turned on if your application is in debug mode. If you’re using a custom instance, simply attach a LogLevel to the Builder.

Analytics analytics = new Analytics.Builder(context, writeKey).logLevel(LogLevel.VERBOSE);

You can choose to disable logging completely (LogLevel.NONE), turn on basic logging for the SDK (LogLevel.BASIC), turn on basic logging for Device-based integration (LogLevel.INFO), or simply log everything (LogLevel.VERBOSE). We recommend turn logging off in production modes of your app. Logging also helps you see how long integrations take to complete their calls and discover bottlenecks.

Proxy HTTP Calls

You can point the Android SDK to your own hosted proxy of the Segment API. This will run the HTTP traffic for the Segment API through the proxy.

Analytics analytics = new Analytics.Builder(this, ANALYTICS_WRITE_KEY) //
        .connectionFactory(new ConnectionFactory() {
          @Override protected HttpURLConnection openConnection(String url) throws IOException {
            String path = Uri.parse(url).getPath();
            // Replace YOUR_PROXY_HOST with the address of your proxy, e.g.
            return super.openConnection("YOUR_PROXY_HOST" + path);

Automatic Screen Tracking

Our SDK can automatically instrument screen calls. It uses the name of the activity declared in the manifest as the screen name.

Analytics analytics = new Analytics.Builder(context, writeKey)


Local device stats help you quickly see how many events you’ve sent us, the average time taken for bundled integrations to run, etc.

StatsSnapshot snapshot = Analytics.with(context).getSnapshot();

Bleeding Edge Releases

We publish stable releases every second Wednesday, when we tag and release the master branch.

After releasing, we also merge the dev branch merged into master. In general, code will be available on master for two weeks before being tagged as a stable release. During this perioud, master is published as a snapshot — the equivalent of bleeding edge releases. We recommend using the snapshot version to try out upcoming features and fixes that have not been published yet. Simply add the snapshots repo to your repository and Gradle will pull in the latest snapshot build.

repositories {
  maven { url '' }


Depending on the audience for your app (e.g. children) or the countries where you sell your app (e.g. the EU), you may need to offer the ability for users to opt-out of analytics data collection inside your app. You can turn off ALL integrations including Segment itself:

public void optOut(boolean optOut) {

Set the opt-out status for the current device and analytics client combination. This flag is persisted across device reboots, so you can simply call this once during your application (such as in a screen where a user can opt out of analytics tracking).

Sending Data to Integrations

There are two ways to send data to your analytics services through this library:

  1. Through the Segment servers
  2. Directly from the device using bundled SDK’s

Note: Refer to the specific integration’s docs to see if your tool must be bundled in the app or sent server-side.

Cloud-based Connection Modes

When an integration’s SDK is not packaged, but it is enabled via your dashboard, the request goes through the Segment REST API, and is routed to the service’s server-side API as described here.

Packaging Device-based Integration SDKs

By default, our analytics artifact packages no Device-based integrations.

We recommend using device-based integrations on a need-to-use basis to reduce the size of your application, and avoid running into the dreaded 65k method limit.

If you would like to package Device-based integrations, first add the dependencies you need. You can find these in our app when you open the integration for your source.

compile('') {
  transitive = true
compile('') {
  transitive = true

After adding the dependency, you must register the integration with our SDK.

Analytics analytics = new Analytics.Builder(context, writeKey)

Anonymizing IP

We collect IP address for client-side (iOS, Android, Analytics.js and Xamarin) events automatically.

If you don’t want us to record your tracked users’ IP in integrations and S3, you can set your event’s context.ip field to . Our server won’t record the IP address of the client for libraries if the context.ip field is already set.

Migrating to v4

Note: If you are using version 2 of the Android SDK, you’ll have to make few changes to get up and running with version 3.

In version 3, adding a Device-based integration looks like this:

compile('') {
  transitive = true

// Add other dependencies as you want here
compile('') {
  transitive = true
compile('') {
  transitive = true
compile('') {
  transitive = true

or, if you wanted to use all Device-based integrations:

compile('') {
  transitive = true

In version 4, the analytics-core artifact is not available any longer. It has been renamed to analytics (which previously packaged all Device-based integrations). Version 4 of analytics only includes the Segment integration. Which means, to package a Device-based integration, you must manually add that dependency.

compile ''

compile('') {
  transitive = true
compile('') {
  transitive = true

In addition to adding a dependency, you must point our SDK to the integration.

Analytics analytics = new Analytics.Builder(context, writeKey)


What is the latest version of the library?

The library is published to Maven Central where you can see all the published releases.

Where is the changelog for the library?

We publish a changelog in the Github repository, detailing the changes made in each release.

Can I use the library with Maven?

Yes! You can use our library with Maven or any custom build system since the core SDK is simply a JAR.


How big is the Segment SDK?

The core Segment SDK is extremely lightweight! It contains just under 1k methods, the JAR weighs in at 123kb and the dex size is 113kb.

How can I easily swap out debugging and production keys?

This is trivial if you’re using Gradle and build flavors. Simply provide an alternate analytics.xml for each configuration with different keys in each.

For other cases, you can also construct custom instances of the client, so you can pass in a different key for it. Set it as the singleton instance, and use the same API everywhere else.

class MyApp extends Application {
  @Override public void onCreate() {
    Analytics analytics;
    if(BuildConfig.DEBUG) {
      analytics = new Analytics.Builder(this, debugWriteKey);
    } else {
      analytics = new Analytics.Builder(this, releaseWriteKey);
    Analytics.setSingletonInstance(analytics); // Must be called before any calls to Analytics.with(context)

    // Now Analytics.with will return the custom instance
    Analytics.with(this).track("App Launched");

How does the library queue API calls?

Our library queues API calls and uploads them in batches so that we don’t drain your user’s battery life by making a network request for each event tracked.

As soon as you send as an event, we’ll save it to disk, and if queue size reaches your specified maximum queue size (which is 20 by default), we flush the queue and upload all the events in a single batch. Since the data is persisted right away, there is no data loss even if the app is killed, or the operating system crashes.

The queue behavior may differ for Device-based integrations. For instance, Mixpanel’s SDK queues events and then flushes them when the app goes to the background only.

This is why even if you see events in the debugger, the Device-based integration may not show them on their dashboards yet, simply because their mobile SDK may still have them queued. The opposite may also happen, that we have some events queued so they haven’t shown up in the debugger, but the Device-based integration has already sent the events to their servers.

Will my events be delivered even if the app is killed?

We use a persistent disk queue, so even when the app is killed, the events stay on disk. We’ll simply read them from disk and upload the events the next time the app starts. Our queue works on top of Tape, which is designed to even survive process and system crashes.

We save up to 1000 calls on disk, and these never expire.

I need to use the SDK on an older version of Android not supported by your library!

Our Android library has support for back to API level 14 (Android 4.0). You should consider it too! If you can’t do this for your own application, there are three options we’ve recommended to users:

  1. Use an older version of the library that does support your minimum requirements. Keep in mind that there won’t be any updates or bug fixes to those versions, but we do still have clients still using old versions of the library in production.
  2. Skip analytics for users on older devices - you can wrap calls to our SDK in a Build.VERSION check.
  3. Write your own SDK. You can still use most of the tools on Segment via our HTTP API. You can use either our Android or Java source to get a quick headstart.

How can I use an integration specific feature, e.g. Mixpanel’s push notifications?

If you’re using a Device-based Connection Mode for a mobile integration, you can always access features from that tool’s native SDK.

To make sure you use the same instance of these integrations as we do, you can register a listener that notifies you when the integrations are ready. This will be called synchronously if the integrations are notified, and asynchronously if the integrations aren’t yet ready.

analytics.onIntegrationReady("Crittercism", new Callback() {
  @Override public void onReady(Object instance) {
    // Crittercism uses static methods only, so the instance returned is null.
analytics.onIntegrationReady("Mixpanel", new Callback() {
  @Override public void onReady(Object instance) {
    MixpanelAPI mixpanelAPI = (MixpanelAPI) instance;

For the integrations that return Void, they simply use a shared instance. You can call into the SDK directly. With this API, you’re guaranteed that they’ve been initialized first, and if you ever decide to change the settings for the integration on our dashboard, they’ll be reflected here.

analytics.onIntegrationReady(BundledIntegration.FLURRY, new Callback() {
  @Override public void onReady(Object instance) {
    // Flurry uses static methods only, so the instance returned is null.

Why is my callback not being invoked?

If you’re using the integration callbacks described above, and don’t receive a callback, check your proguard configuration. Any easy way to verify that Proguard is the issue is to disable it completely for a run and see if the callbacks is invoked.

Why is Google Analytics not receiving crash reports?

This is a known bug and is being worked on by Google. We recommend using alternatives like Bugsnag or Crittercism in the meantime.

How should I configure Proguard?

For our SDK, you should add -keep class** { *; } to your proguard configuration. You should also look up any proguard configurations recommended by each of the Device-based integrations on their respective docs and websites.

How should I use Outbound’s push notifications?

Since Outbound isn’t a Device-based integration, you’ll have to set it up manually.

First, you’ll need to set up the GCM client as described in the instructions.

Our server’s will look for context.device.token key to send to Outbound. Once you have the registration ID from the step above, simply set it on the context. (This convenience method was added in versino 2.1.6). analytics.getContext().putDeviceToken(registrationId);

The entire code flow looks a bit like this:

String registrationId = loadRegistrationId(); // look up a cached value
if(registrationId == null) {
  registrationId = register(SENDER_ID); // using GoogleCloudMessaging
  save(registrationId); // save the registration ID

Migrate from v2 to v3

NOTE: Version 3 of the SDK is now replaced by version 4. See the section below on upgrading. If you are already using version 2 of the Android SDK, you’ll have to make few changes to get up and running with version 3.

In version 3, we’ve organized the integrations to be make the core SDK even leaner and smaller. This is what the old setup looked like:

compile('') {
  transitive = true

// Add other dependencies as you want here
compile ''
compile ''
compile files('libs/QuantcastAndroidSdk.jar')

In the new version, instead of adding the integrations directly, simply add our integration modules as a dependency instead. This also ensures that the version of the Device-based integration you’re using, matches the one we depend on.

compile('') {
  transitive = true

// Add other dependencies as you want here
compile('') {
  transitive = true
compile('') {
  transitive = true
compile('') {
  transitive = true

Earlier, you could control the debugging behaviour with a boolean flag. In version 3, this is replaced by the more powerful LogLevel Enum, that lets you not only control the logging behaviour of our SDK, but also for Device-based integrations.

Version 2 of the SDK also let you customize the behaviour of the SDK by providing resource values in XML. Version 3 ignores these custom options from XML to simplify behaviour and improve performance. The recommended way to customize the Analytics client is to use the Builder methods instead.

Do you support Phonegap/Cordova?

Yep! You can use our browserify’d analytics-node package just like any other client-side JavaScript library.

How do you handle Unique Identifiers?

A key component of any analytics platform is consistently and accurately identifying users. Some kind of ID must be assigned and persisted on the device so that user actions can be effectively studied. This is especially important for funnel conversion analysis and retention analysis.

Naturally the Analytics SDK needs a unique ID for each user. The very first time an app is launched, our SDK will generated a UUID and save it on disk. This is used as the anonymousId and stays constant for the user on the device. If you want to create a new user on the same device, call reset on the Analytics client.

Our SDK also collects the Advertising ID provided by Play Services. Make sure the Play Services Ads library is included as a dependency for your application. This is the ID that should be used for advertising purposes. This value will be set to context.device.advertisingId.

We also collect the Android ID as Some integrations rely on this field being the Android ID, so take care if you choose to override the default value.


No events in third-party integration

If you aren’t seeing data in the third-party integration, there are a few possibilities that may be the causing this.

First, verify that your integration is enabled! You might have used the wrong Segment source (often when switching between development and production), or somebody on your team might have turned it off.

If the events show up in the segment debugger, look at the raw json and find the integrations property. If the value is set to false, that means that the data is being sent from the device to the integration SDK, and not through Segment’s servers. This is expected if you elected to use a Device-based integration’s SDK with Segment’s during installation. If the integration is Cloud-based, you should be able to see any errors in our debugger itself.

If the integration is Device-based, enabled verbose logging, and this will show whether our SDK is calling the partner SDK methods as expected.

With Mixpanel as an example, you might see something like this in your logcat: 10-16 20:26:38.607 2046-2067/ V/Analytics-Mixpanel: MixpanelAPI.getInstance(context, 540f9234e0dfa14f843e59f1acdbafd8);.

This shows you exactly what method was invoked and the arguments it was invoked with!

If everything looks as expected, please contact the support team for the respective integration partner to ask them why calling the right methods on their SDK would be causing an issue.

If not, kindly enable debugging, play around with the app, save the logcat to a file with adb logcat >> log.txt and then contact us for help.

Still having issues?

Feel free to reach out to us at with the following information:

  • The version of our Android SDK you are using.
  • How you installed our SDK.
  • Is this a Device-based integration?
  • Your logs by enabling verbose logging sending the output of adb logcat).
  • Screenshots of the event in the Segment debugger.

We are happy to help!

If you have any questions or see anywhere we can improve our documentation, please let us know or kick off a conversation in the Segment Community!