Android

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 and this is used to identify users uniquely by Apxor. Apart from this, you can log a custom user identifier that you use to uniquely identify users in your app.

This identifier would be very instrumental especially when exporting data of a certain campaign or survey to your analytics system to create a cohort and measure the results of the campaign.

Similarly, when you are importing data to Apxor from your system that your marketing/product / data science team has identified and wants to run campaigns specifically to them the custom user identifier will serve as the bridge to communicate between your systems and Apxor effectively.

Here is how you can set your user identifier for Apxor to recognise your users :

ApxorSDK.setUserIdentifier(<SOME_USER_ID>);

Here is how you can fetch the Apxor device identifier that is automatically captured and maintained by the SDK in case you want to record and map it to your data.

String deviceId = ApxorSDK.getDeviceId(applicationContext);j

Setting up campaign triggers, capturing data for targeting and goal tracking

The product/marketing or the growth team lists out the use cases with an idea of when to launch and to whom to launch. To do this we need to capture data in the form of events. Let us consider the following use case as an example :

App Events

In the above scenario, we want to trigger the campaign for users who have spent 'x' seconds and haven't tapped on a product. To understand that if the user has tapped the product we should log an event along with its attributes as follows to capture data:

Similarly if you want to send promotions to users who have viewed at least five products of the category shoes in the last three days or you want to measure how many people added an item to a cart from the campaign as a goal all this information is captured in the form of events.

These types of events are classified as app events - the data that is transferred to the servers at Apxor where you can segment users based on historic behaviour or measure your goals as specified above.

Here is how we track app events :

Attributes additionalInfo = new Attributes();
additionalInfo.putAttribute("ProductName", "MixerGrinder");
additionalInfo.putAttribute("ProductPrice", 2999);
ApxorSDK.logAppEvent("ProductClicked", additionalInfo);

Client Events

In the below scenario, let's assume you want to launch a survey when the soft back button is pressed asking the user for product feedback. In this, we don't need to capture the data of how many people pressed the back button which is useless and it bloats your event storage as it is a high-frequency event which increases your cost unnecessarily. This data point doesn't potentially answer any of your product questions and hence there is no ROI in storing data from this event.

So for such scenarios where we need the behavioral data to launch a campaign or to collect feedback, which doesn't provide ROI on storing for measuring goals, answering your product questions or segmenting your target audience, we log these events as Client Events which involves zero transfer of data and is used only to set up your triggers on behavioral information from the user.

Attributes additionalInfo = new Attributes();
additionalInfo.putAttribute("Screen", "com.example.app.SettingsActivity");
ApxorSDK.logClientEvent("SoftBackPressed", additionalInfo);

User Attributes

Personalizing and targetting by user persona

We can personalize the messaging copy in the experiences we build for the user or target based on his persona using information that is centric to individual users. Let us consider the following example where we know the user is an English with Gold membership.

This information helps to tailor content in English to that specific user and gives us the flexibility to different messaging to different membership tiers. This is how the information captured here is used for segmenting.

Similarly capturing attributes like Name can help to personalize your message copy where it reads Hi {username} can't find your product? where the username is replaced by the attribute value of the property from the nudges dashboard along with providing meaningful defaults in their absence.

This is how you log user information to Apxor :

Attributes userInfo = new Attributes();
userInfo.putAttribute("Name", "Prabhu");
userInfo.putAttribute("AcquistionSource", "Facebook");
userInfo.putAttribute("CampaignAttribution", "shoes-adset");
userInfo.putAttribute("UserGender", "Male");
userInfo.putAttribute("MembershipType", "Gold");
userInfo.putAttribute("AppLanguage", "English");
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);

Handle custom redirection using Key-Value pairs (Optional)

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) {

        }
      }
    });
  }
}

Track Screens

In the scenario discussed in this guide, how will we know if the user has spent thirty seconds on the home screen and did not click on the product? For this reason, it is important to use track the screens to set them up as triggers and also to capture the time spent on the screens.

By using the following API to track the screens in the app you can setup campaigns on inactivity or time spent on those screens:

ApxorSDK.trackScreen("HomeScreen");

Note

Make sure you use the ApxorSDK.trackScreen API in your activity's onResume method

Please ensure the following while tracking screens :

  • If your screen has different fragments then it is important to track all the fragments using the API after the screen is visible to your user

  • If you use Android's Navigation architecture component, you can use ApxorSDK.trackScreen API in NavController.OnDestinationChangedListener callback

  • If your activity has different tabs either at the top or bottom, you can call ApxorSDK.trackScreen API every time a tab gets selected as 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 or BottomNavigationView, you can refer to the examples described here

  • If you use Android's Navigation architecture component, you can use ApxorSDK.trackScreen API in NavController.OnDestinationChangedListener callback

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);

Tooltips in WebView

Note

Make sure you have the latest version of apxor-sdk-rtm plugin version >= 153

Many native applications feature WebViews 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 (Optional)

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 (Optional)

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 is onSuccess and onFailure. 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"));

Yeah! You are ready to create your first Campaign or Survey.

Last updated