APXOR Android API Guide
Initializing the Apxor SDK
To start tracking with the Apxor Android SDK, you must first initialize it with your project token. To initialize the SDK,
ApxorSDK.initialize(<APXOR_ID> , this.getApplicationContext());
Identifying Users
The Apxor SDK automatically captures device IDs which the Apxor backend uses to uniquely identify users.
If you want to, you can assign your own user IDs. This is particularly useful if you want to study a specific user with ease. To assign your own user ID, you can use
ApxorSDK.setUserIdentifier(<SOME_USER_ID>);
User Attributes
There is often additional user identifying information, such as name and email address, connected with the external IDs.
To add some more attributes that are specific to a particular user,
Attributes userInfo = new Attributes();
userInfo.putAttribute("age", 27);
userInfo.putAttribute("gender", "Male");
ApxorSDK.setUserCustomInfo(userInfo);
Session Attributes
A Session can be simply defined as user journey as he opens the app, until he closes the app. There can be various pieces of information that be very impactful when accumulated in a session. For example, location in a session can be useful to know exactly where, the user is utilizing the app most.
To add session attributes that are specific to a session,
ApxorSDK.setSessionCustomInfo("network", "4G");
Or if you have multiple key value pairs that need to be logged, you can simply put them in a hashmap like,
Attributes sessionInfo = new Attributes();
sessionInfo.putAttribute("network", "4G");
sessionInfo.putAttribute("city", "GAJ");
ApxorSDK.setSessionCustomInfo(sessionInfo);
Flatten Attributes
If you use Attributes.putAttributes
API and pass a JSON object like:
{
"key1": "a",
"key2": 12,
"key3": {
"A": "a",
"B": "b",
"C": {
"c": false
}
},
"key4": [1, 2, 3],
"key5": [
{
"a": "AA",
"b": 1
},
{
"a": "BB",
"d": 100
}
]
}
by default ApxorSDK will flatten the above JSON to:
{
"key1": "a",
"key2": 12,
"key3": "{\"A\": \"a\", \"B\": \"b\", \"C\": \"{\"c\": false}\"}",
"key4": [1, 2, 3],
"key5": ["{\"a\": \"AA\", \"b\": 1}", "{\"a\": \"BB\", \"d\": 100}"]
}
If you want to analyse data on nested JSON objects or array of objects like key3
and key5
, you have to use Attributes.flatten
API which will extract the keys upto two levels from the JSON and make them as first level keys. Like,
{
"key1": "a",
"key2": 12,
"key3_A": "a",
"key3_B": "b",
"key3_C": "{\"c\": false}",
"key4": [1, 2, 3],
"key5_a": ["AA", "BB"],
"key5_b": 1,
"key5_d": 100
}
Note:
If you use
flatten
API, ApxorSDK flattenJSONObject
s upto two levels.key3_C
is in third level and it's aJSONObject
. So, ApxorSDK converts it toString
by default.
Usage:
You can use this flatten
API while logging user or session attributes as well as for the attributes of app events and client events.
Attributes attributes = new Attributes();
attributes.flatten(yourJSONObject);
ApxorSDK.logAppEvent("ProductViewed", attributes);
Reporting Custom Errors
Custom errors describe situations like LOGIN_FAILED, NETWORK_CALL_FAILED and are to be treated differently compared to app events. So these are treated as errors and are shown on the issues page to let you know their impact.
A custom error takes the exception itself and some context (what? OR which?) to make it easy for you identify. To report a custom error,
Exception e = new Exception("LOGIN FAILED EXCEPTION");
HashMap<String, String> additionalInfo = new HashMap<>();
additionalInfo.put("email", "spock@vulcan.com");
additionalInfo.put("cause", "network failure");
ApxorSDK.reportCustomError("Null Value", additionalInfo, e);
App Events
App events make it easier to analyze user behavior and optimize your product and marketing around common business goals such as improving user retention or app usage. You can also add additional information for any event.
To track an event with the event name and properties.
Attributes additionalInfo = new Attributes();
additionalInfo.putAttribute("type", "Google");
additionalInfo.putAttribute("language", "Valyrian");
ApxorSDK.logAppEvent("Login", additionalInfo);
Aggregate Events
Events that are not required for an in-depth analysis but are useful as quantitative metrics are called Aggregate Events. Only their aggregate counts will be sent to Apxor to reduce unnecessary transfer and storage of data, minimising overhead and costs.
Example:
Measuring if an article is viewed by a user if it is visible in the view port (visible part of the screen) for five seconds can be logged as an aggregate event to count the impressions of a particular article.
Attributes additionalInfo = new Attributes();
additionalInfo.putAttribute("card_type", "Text");
additionalInfo.putAttribute("id", "46Juzcyx");
ApxorSDK.logAppEvent("Impression", additionalInfo, true);
Client Events
Events that are logged to reside on the client application are called client events, the data captured is not transferred to Apxor.
These are typically logged to capture behavioural observations and interactions to nudge a user.
Example:
Soft back button, user reaching end of page, etc.
Attributes additionalInfo = new Attributes();
additionalInfo.putAttribute("Screen", "com.example.app.SettingsActivity");
ApxorSDK.logClientEvent("SoftBackPressed", additionalInfo);
Handle custom redirection using Key-Value pairs
If your app wants to redirect users based on simple key-value pairs instead using Deeplink URLs or Activity, you can follow below approach
import android.app.Application;
import com.apxor.androidsdk.core.ApxorSDK;
import com.apxor.androidsdk.core.RedirectionListener;
import org.json.JSONArray;
public class MyApplication extends Application {
@Override
public void onCreate() {
// Register a redirection listener ONLY ONCE in your app
// If you register in multiple places, ONLY the last value will be available.
// Whenever you register a new one, it will override the existing listener
Apxor.setRedirectionListener(new RedirectionListener() {
@Override
public void onActionComplete(JSONArray keyValuePairs) {
int length = keyValuePairs.length();
/**
* [
* {
* "name": "YourKey",
* "value": "YourValue"
* },
* ....
* ]
*/
try {
for (int i = 0; i < length; i++) {
JSONObject pair = keyValuePairs.getJSONObject(i);
String key = pair.getString("name");
// Values are always String type. You need to convert based on your need
String value = pair.getString("value");
// Your logic continues from here
}
} catch (JSONException e) {
}
}
});
}
}
Set Current Screen Name
Apxor by default tracks activity changes within your app and we include the package name for activities like com.example.app.MainActivity
. You can set a name for your activity using ApxorSDK.
Note
Make sure you use the
ApxorSDK.setCurrentScreenName
API in your activity'sonResume
method
import com.apxor.androidsdk.core.ApxorSDK;
public class MyActivity extends AppCompatActivity {
@Override
public void onResume() {
ApxorSDK.setCurrentScreenName("Home");
}
}
Track Screens
From ApxorSDK core >= 2.6.7
, you can track the tabs inside your activity to understand the amount of time users spending in a particular tab.
Note
Make sure you use the
ApxorSDK.trackScreen
API in your activity'sonResume
method
Example
If your activity has different tabs either at top or bottom, you can call
ApxorSDK.trackScreen
API everytime a tab gets selectedThe standard approaches are shown below
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
ApxorSDK.trackScreen("Share");
// Your logic
break;
case R.id.action_settings:
ApxorSDK.trackScreen("Settings");
// Your logic
break;
//.. other cases
}
}
});
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
ApxorSDK.trackScreen(tab.getText().toString());
// Your logic
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
// Your logic
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
// Your logic
}
});
Working with Fragments
You might have used fragments within your application. From apxor-android-sdk-rtm
version 1.5.8
, Apxor Behavior Cues will behave accordingly to the fragment changes within your application.
If you use Fragments
, we always recommend you to use ApxorSDK.trackScren
API in all your fragments to see the expected behavior of Tooltips
and Coachmarks
. Ideally you must call/use this API only when the fragment is visible to the user.
Example usages of trackScreen API
- If you use
ViewPager
with tabbed layout orBottomNavigationView
, you can refer to the examples described here - If you use Android's Navigation architecture component, you can use
ApxorSDK.trackScreen
API inNavController.OnDestinationChangedListener
callback
Tooltips in WebView
Note
Make sure you have the latest version of
apxor-sdk-rtm
plugin version >= 153
Many native applications feature WebView
s to display descriptive content and much more.
Apxor Android SDK provides a way to show tooltips inside that WebView
to make the most of it.
Following are the steps in order to show tooltips in your WebView
.
Add a tag to the
WebView
(which is to be later provided in the dashboard) as shown.webView.setTag("MyWebView");
Attach Apxor SDK Javascript Interface as mentioned below.
// You must enable Javascript for the webview WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); // Attach Apxor SDK Javascript Interface webview.addJavascriptInterface(new ApxorJSInterface(), "Apxor");
That's it. All you have to do is, set some IDs for your HTML elements inside your web page and configure the same in dashboard along with WebView's tag.
Log Events inside WebView
It is suggested that you log events inside your WebView once the page is completely rendered using Apxor Javascript Interface methods. Based on these events, you can configure Tooltips.
Methods exposed from Apxor Javascript Interface
window.Apxor.logAppEvent(event_name[, event_props]); window.Apxor.logClientEvent(event_name[, event_props]);
Examples for logging App Event
Example:
Log an event on page load event.
... <head> ... <script> function logApxorEvent(eventName, attributes) { if (window.Apxor && window.Apxor.logAppEvent) { window.Apxor.logAppEvent(eventName, attributes); } } </script> </head> <body onload="logApxorEvent('PageLoaded')"> ... </body>
Example (React based web pages):
Log an event on componentDidMount.
componentDidMount() { if (window.Apxor && window.Apxor.logAppEvent) { window.Apxor.logAppEvent('LoginPageLoaded', null); } }
To get Apxor Device Identifier
Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID, use below
String deviceId = ApxorSDK.getDeviceId(applicationContext);
To get Apxor Attributes
Now you can use getAttributes
API to get the user and session attributes from ApxorSDK in a single API call.
Note:
This is an asynchronus call. So, you have to pass a callback. For that you can use
ApxorDataCallback
. There are two methods in this interface. One isonSuccess
andonFailure
. Both these methods will be called in a separate background thread.
ApxorSDK.getAttributes(
new String[]{ "custom_user_id", "email" },
new ApxorDataCallback() {
@Override
public void onSuccess(JSONObject props) {
if (props == null) {
return;
}
String userId = props.optString("custom_user_id");
String email = props.optString("email");
}
@Override
public void onFailure() {
Log.e(TAG, "Failed to get attributes");
}
}
);
Dynamic Script Text in actions
A new capability of writing dynamic text in actions (Tooltips & InApps) had been introduced in latest release of Apxor SDK plugins.
You can write a script (a new language that Apxor is created which somewhat looks like Javascript) instead of plain text to substitue user and session properties that you have already logged to Apxor SDK or you can substitute a text element from your application or hidden text that you set it as keyed tag (apx_view_tag).
The Apxor Language
The Apxor language looks similar to Javascript with some modifications.
We assume every dynamic param that you want to substitute in a text is a pre-defined variable that you can create upfront in the Script dialog that Apxor Dashboard provides to you.
We support following operators and keywords as part of our language specification
Unary Operators
!
(Negation)
Logical Operators
&&
(Logical AND)
||
(Logical OR)
Mathematical Operators
+
(Arithmetic Addition)
-
(Arithmetic Subtraction)
*
(Arithmetic Multiplication)
/
(Arithmetic Division)
%
(Arithmetic Modulo)
Comparison Operators
<
(Less than)
<=
(Less than or Equals)
>
(Greater than)
>=
(Greater than or Equals)
==
(Equality)
!=
(Not Equality)
contains
(Checks if a string contains another string)
Keywords
httpGet
,onSuccess
,onError
will be used to make a HTTP GET API call
format
will be used to format a string
if
,else
will be used to write conditional evaluation
true
,false
boolean keywords
toInt
will be helful to convert double/float values to integer
Examples
Note:
Assume the following variables are defined
UserName (User Property)
RewardPoints (User Property)
IsSubscribed (User Property)
Subscribed (API JSON response parameter
user.is_subscribed
)
- Simple formatting of string
format(
"Hello {}. We are exicted to give you {} reward points. You can see these points in Rewards section",
UserName,
toInt(RewardPoints)
);
- Conditional Dynamic Text
if (!IsSubscribed && RewardPoints < 500) {
format(
"Hello {}, you are just {} points away to get free subscription",
UserName,
500 - RewardPoints
);
} else {
format("Hello {}, You are already subscribed", UserName);
}
- API call
httpGet(format("https://your-server.com/your-api?userName={}", UserName))
.onSuccess(() => {
if (SubScribed) {
format("Hello {}, you are already subscribed", UserName);
} else {
format("Hello {}, you are not subscribed yet", UserName);
}
})
.onError(() => format("Something went wrong. Try again later"));