Android SDK

See our SDK documentation for a description of all available SDK methods.

Setup

  1. Download the jar and copy it into the "libs" folder in your Android project in Android Studio.

Alternatively, if you are using Maven in your project, the jar is available on Maven Central using the following configuration in your pom.xml:

<dependency>
  <groupId>io.rakam</groupId>
  <artifactId>android-sdk</artifactId>
  <version>2.7.8</version>
</dependency>

Or if you are using gradle in your project, include in your build.gradle file:

compile 'io.rakam:android-sdk:2.7.2.7.8'
  1. If you haven't already, add the INTERNET permission to your manifest file:
<uses-permission android:name="android.permission.INTERNET" />
  1. In every file that uses analytics, import Rakam at the top:
import Rakam;
  1. In the onCreate() of your main activity, initialize the SDK:
Rakam.getInstance().initialize(this, new URL("YOUR_PROJECT_API_URL"), 
  "YOUR_PROJECT_WRITE_KEY").enableForegroundTracking(getApplication());

Note: if your app has multiple entry points/exit points, you should make a Rakam.getInstance().initialize() at every onCreate() entry point.

  1. To track an event anywhere in the app, call:

    Rakam.getInstance().logEvent("EVENT_IDENTIFIER_HERE");
    
  2. If you want to use Google Advertising IDs, make sure to add Google Play Services to your project. This is required for integrating with third party attribution services

  3. If you are using Proguard, add these exceptions to proguard.pro for Google Play Advertising IDs and Rakam dependencies:

-keep class com.google.android.gms.ads.** { *; }
-dontwarn okio.**
  1. Events are saved locally. Uploads are batched to occur every 30 events and every 30 seconds. After calling logEvent() in your app, you will immediately see data appear on the Rakam website.

A demo application is available to show a simple integration.

Tracking Events

It's important to think about what types of events you care about as a developer. You should aim to track between 20 and 200 types of events on your site. Common event types are actions the user initiates (such as pressing a button) and events you want the user to complete (such as filling out a form, completing a level, or making a payment).

Here are some resources to help you with your instrumentation planning:

Having large amounts of distinct event types, event properties and user properties, however, can make visualizing and searching of the data very confusing. By default we only show the first:

  • 1000 distinct event types
  • 2000 distinct event properties
  • 1000 distinct user properties

Anything past the above thresholds will not be visualized. Note that the raw data is not impacted by this in any way, meaning you can still see the values in the raw data, but they will not be visualized on the platform. We have put in very conservative estimates for the event and property caps which we don’t expect to be exceeded in any practical use case. If you feel that your use case will go above those limits please reach out to [email protected].

Tracking Sessions

A session is a period of time that a user has the app in the foreground. Events that are logged within the same session will have the same session_id. Sessions are handled automatically now; you no longer have to manually call startSession() or endSession().

  • For Android API level 14+, a new session is created when the app comes back into the foreground after being out of the foreground for 5 minutes or more. If the app is in the background and an event is logged, then a new session is created if more than 5 minutes has passed since the app entered the background or when the last event was logged (whichever occurred last). Otherwise the background event logged will be part of the current session. (Note you can define your own session experation time by calling setMinTimeBetweenSessionsMillis(timeout), where the timeout input is in milliseconds.)

  • For Android API level 13 and below, foreground tracking is not available, so a new session is automatically started when an event is logged 30 minutes or more after the last logged event. If another event is logged within 30 minutes, it will extend the current session. (Note you can define your own session expiration time by calling setSessionTimeoutMillis(timeout), where the timeout input is in milliseconds. Also note, enableForegroundTracking(getApplication) is still safe to call for Android API level 13 and below, even though it is not available.)

Other Session Options:

  1. By default start and end session events are no longer sent. To re-enable add this line after initializing the SDK:
Rakam.getInstance().trackSessionEvents(true);
  1. You can also log events as out of session. Out of session events have a session_id of -1 and are not considered part of the current session, meaning they do not extend the current session. This might be useful for example if you are logging events triggered by push notifications. You can log events as out of session by setting input parameter outOfSession to true when calling logEvent():
Rakam.getInstance().logEvent("EVENT", null, true);

Getting the Session Id

You can use the helper method getSessionId to get the value of the current sessionId:

long sessionId = Rakam.getInstance().getSessionId();

Setting Custom User IDs

If your app has its own login system that you want to track users with, you can call setUserId() at any time:

Rakam.getInstance().setUserId("USER_ID_HERE");

You can also add a user ID as an argument to the initialize() call:

Rakam.getInstance().initialize(this, new URL("YOUR_PROJECT_API_URL"), "YOUR_PROJECT_WRITE_KEY", "USER_ID_HERE");

Setting Event Properties

You can attach additional data to any event by passing a JSONObject as the second argument to logEvent():

JSONObject eventProperties = new JSONObject();
try {
    eventProperties.put("KEY_GOES_HERE", "VALUE_GOES_HERE");
} catch (JSONException exception) {
}
Rakam.getInstance().logEvent("Sent Message", eventProperties);

You will need to add two JSONObject imports to the code:

import org.json.JSONException;
import org.json.JSONObject;

User Properties and User Property Operations

The SDK supports the operations set, setOnce, unset, and add on individual user properties. The operations are declared via a provided Identify interface. Multiple operations can be chained together in a single Identify object. The Identify object is then passed to the Rakam client to send to the server. The results of the operations will be visible immediately in the dashboard, and take effect for events logged after.

To use the Identify interface, you will first need to import the class:

import Identify;
  1. set: this sets the value of a user property.
Identify identify = new Identify().set('gender', 'female').set('age', 20);
Rakam.getInstance().identify(identify);
  1. setOnce: this sets the value of a user property only once. Subsequent setOnce operations on that user property will be ignored. In the following example, sign_up_date will be set once to 08/24/2015, and the following setOnce to 09/14/2015 will be ignored:
Identify identify1 = new Identify().setOnce('sign_up_date', '08/24/2015');
Rakam.getInstance().identify(identify1);

Identify identify2 = new Identify().setOnce('sign_up_date', '09/14/2015');
rakam.identify(identify2);
  1. unset: this will unset and remove a user property.
Identify identify = new Identify().unset('gender').unset('age');
Rakam.getInstance().identify(identify);
  1. add: this will increment a user property by some numerical value. If the user property does not have a value set yet, it will be initialized to 0 before being incremented.
Identify identify = new Identify().add('karma', 1).add('friends', 1);
Rakam.getInstance().identify(identify);
  1. append: this will append a value or values to a user property. If the user property does not have a value set yet, it will be initialized to an empty list before the new values are appended. If the user property has an existing value and it is not a list, it will be converted into a list with the new value appended.
Identify identify = new Identify().append("ab-tests", "new-user-test").append("some_list", new JSONArray().put(1).put("some_string"));
Rakam.getInstance().identify(identify);
  1. prepend: this will prepend a value or values to a user property. Prepend means inserting the value(s) at the front of a given list. If the user property does not have a value set yet, it will be initialized to an empty list before the new values are prepended. If the user property has an existing value and it is not a list, it will be converted into a list with the new value prepended.
Identify identify = new Identify().prepend("ab-tests", "new-user-test").prepend("some_list", new JSONArray().put(1).put("some_string"));
Rakam.getInstance().identify(identify);

Note: if a user property is used in multiple operations on the same Identify object, only the first operation will be saved, and the rest will be ignored. In this example, only the set operation will be saved, and the add and unset will be ignored:

Identify identify = new Identify().set('karma', 10).add('karma', 1).unset('karma');
Rakam.getInstance().identify(identify);

Arrays in User Properties

The SDK supports arrays in user properties. Any of the user property operations above (with the exception of add) can accept a JSONArray or any Java primitive array. You can directly set arrays, or use append to generate an array.

JSONArray colors = new JSONArray();
colors.put("rose").put("gold");
Identify identify = new Identify().set("colors", colors).append("ab-tests", "campaign_a").append("existing_list", new int[]{4,5});
Rakam.getInstance().identify(identify);

Setting Multiple Properties with setUserProperties

You may use setUserProperties shorthand to set multiple user properties at once. This method is simply a wrapper around Identify.set and identify.

JSONObject userProperties = new JSONObject();
try {
    userProperties.put("KEY_GOES_HERE", "VALUE_GOES_HERE");
    userProperties.put("OTHER_KEY_GOES_HERE", "OTHER_VALUE_GOES_HERE");
} catch (JSONException exception) {
}
Rakam.getInstance().setUserProperties(userProperties);

Clearing User Properties with clearUserProperties

You may use clearUserProperties to clear all user properties at once. Note: the result is irreversible!

Rakam.getInstance().clearUserProperties();

Tracking Revenue

The preferred method of tracking revenue for a user now is to use logRevenueV2() in conjunction with the provided Revenue interface. Revenue instances will store each revenue transaction and allow you to define several special revenue properties (such as revenueType, productId, etc) that are used in Rakam dashboard's Revenue tab. You can now also add event properties to the revenue event, via the eventProperties field. These Revenue instance objects are then passed into logRevenueV2 to send as revenue events to Rakam servers. This allows us to automatically display data relevant to revenue on the Rakam website, including average revenue per daily active user (ARPDAU), 1, 7, 14, 30, 60, and 90 day revenue, lifetime value (LTV) estimates, and revenue by advertising campaign cohort and daily/weekly/monthly cohorts.

To use the Revenue interface, you will first need to import the class:

import Revenue;

Each time a user generates revenue, you create a Revenue object and fill out the revenue properties:

Revenue revenue = new Revenue().setProductId("com.company.productId").setPrice(3.99).setQuantity(3);
Rakam.getInstance().logRevenueV2(revenue);

productId, and price are required fields. quantity defaults to 1 if unspecified. receipt and receiptSignature are required if you want to verify the revenue event. Each field has a corresponding set method (for example setProductId, setQuantity, etc). This table describes the different fields available:

NameTypeDescriptiondefault
productIdStringRequired: an identifier for the product (we recommend something like the Google Play Store product Id)null
quantityintRequired: the quantity of products purchased. Defaults to 1 if not specified. Revenue = quantity * price1
priceDoubleRequired: the price of the products purchased (can be negative). Revenue = quantity * pricenull
revenueTypeStringOptional: the type of revenue (ex: tax, refund, income)null
receiptStringOptional: required if you want to verify the revenue eventnull
receiptSignatureStringOptional: required if you want to verify the revenue eventnull
eventPropertiesJSONObjectOptional: a JSONObject of event properties to include in the revenue eventnull

Note: the price can be negative, which might be useful for tracking revenue lost, for example refunds or costs. Also note, you can set event properties on the revenue event just as you would with logEvent by passing in a JSONObject of string key value pairs. These event properties, however, will only appear in the Event Segmentation tab, not in the Revenue tab.

Revenue Verification

By default Revenue events recorded on the Android SDK appear in Rakam dashboards as unverified revenue events. To enable revenue verification, copy your Google Play License Public Key into the manage section of your app on Rakam. You must put a key for every single app in Rakam where you want revenue verification.

Then after a successful purchase transaction, add the purchase data and receipt signature to the Revenue object:

// for a purchase request onActivityResult
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

Revenue revenue = new Revenue().setProductId("com.company.productId").setQuantity(1);
revenue.setPrice(3.99).setReceipt(purchaseData, dataSignature);

Rakam.getInstance().logRevenueV2(revenue);

See the Google In App Billing Documentation for details on how to retrieve the purchase data and receipt signature.

Amazon Store Revenue Verification

For purchases on the Amazon Store, you should copy your Amazon Shared Secret into the manage section of your app on Rakam. After a successful purchase transaction, you should send the purchase token as the receipt and the user id as the receiptSignature:

// for a purchase request onActivityResult
String purchaseToken = purchaseResponse.getReceipt();
String userId = getUserIdResponse.getUserId();

Revenue revenue = new Revenue().setProductId("com.company.productId").setQuantity(1);
revenue.setPrice(3.99).setReceipt(purchaseToken, userId);

Rakam.getInstance().logRevenueV2(revenue);

Fine-grained location tracking

Rakam can access the Android location service (if possible) to add the specific coordinates (longitude and latitude) where an event is logged. This behaviour is enabled by default, but can be adjusted calling the following methods after initializing:

Rakam.getInstance().enableLocationListening();
Rakam.getInstance().disableLocationListening();

Even disabling the location listening, the events will have the "country" property filled. That property is retrieved from other sources (i.e. network or device locale).

Allowing Users to Opt Out

To stop all event and session logging for a user, call setOptOut:

Rakam.getInstance().setOptOut(true);

Logging can be restarted by calling setOptOut again with enabled set to false.
No events will be logged during any period opt out is enabled.

Advanced

If you want to use the source files directly, you can download them here. To include them in your project, extract the files, and then copy the five *.java files into your Android project.

This SDK automatically grabs useful data from the phone, including app version, phone model, operating system version, and carrier information. If your app has location permissions, the SDK will also grab the last known location of a user (this will not consume any extra battery, as it does not poll for a new location).

Setting Groups

Rakam supports assigning users to groups, and performing queries such as Count by Distinct on those groups. An example would be if you want to group your users based on what organization they are in by using an orgId. You can designate Joe to be in orgId 10, while Sue is in orgId 15. When performing an event segmentation query, you can then select Count by Distinct orgIds to query the number of different orgIds that have performed a specific event. As long as at least one member of that group has performed the specific event, that group will be included in the count. See our help article on Count By Distinct for more information.

When setting groups you need to define a groupType and groupName(s). In the above example, 'orgId' is a groupType, and the value 10 or 15 is the groupName. Another example of a groupType could be 'sport' with groupNames like 'tennis', 'baseball', etc.

You can use setGroup(groupType, groupName) to designate which groups a user belongs to. Note: this will also set the groupType: groupName as a user property. This will overwrite any existing groupName value set for that user's groupType, as well as the corresponding user property value. groupType is a string, and groupName can be either a string or an JSONArray of strings to indicate a user being in multiple groups (for example Joe is in orgId 10 and 16, so the groupName would be [10, 16]). It is important that you use JSONArrays to set multiple groups since primitive arrays do not serialize properly.

You can also call setGroup multiple times with different groupTypes to track multiple types of groups. You are allowed to track up to 5 different groupTypes per app. For example Sue is in orgId: 15, and she also plays sport: soccer. Now when querying, you can Count by Distinct on both orgId and sport (although as separate queries). Any additional groupTypes after the limit will be ignored from the Count By Distinct query UI, although they will still be saved as user properties.

Rakam.getInstance().setGroup("orgId", "15");
Rakam.getInstance().setGroup("sport", new JSONArray().put("tennis").put("soccer"));  // list values

You can also use logEvent with the groups argument to set event-level groups, meaning the group designation only applies for the specific event being logged and does not persist on the user (unless you explicitly set it with setGroup).

JSONObject eventProperties = new JSONObject().put("key", "value");
JSONObject groups = new JSONObject().put("orgId", 10);

Rakam.getInstance().logEvent("initialize_game", eventProperties, groups);

Custom Device Ids

By default, device IDs are a randomly generated UUID. If you would like to use Google's Advertising ID as the device ID, you can specify this by calling Rakam.getInstance().useAdvertisingIdForDeviceId() prior to initializing. You can retrieve the Device ID that Rakam uses with Rakam.getDeviceId(). This method can return null if a Device ID hasn't been generated yet.

If you have your own system for tracking device IDs and would like to set a custom device ID, you can do so with Rakam.getInstance().setDeviceId("CUSTOM_DEVICE_ID"). Note: this is not recommended unless you really know what you are doing. Make sure the device ID you set is sufficiently unique (we recommend something like a UUID - we use UUID.randomUUID().toString()) to prevent conflicts with other devices in our system.

SDK Logging

You can disable all logging done in the SDK by calling Rakam.getInstance().enableLogging(false). By default the logging level is Log.INFO, meaning info messages, errors, and asserts are logged, but verbose and debug messages are not. You can change the logging level, for example to enable debug messages you can do Rakam.getInstance().setLogLevel(Log.DEBUG).