# Introduction to Apxor

### Overview

Apxor is an in-product nudging platform that helps you create delightful experiences for your users.

By integrating Apxor, you can improve activation, adoption, engagement, and conversions by communicating to your users to take the desired action at the right time.

<figure><img src="/files/jpYrI08p6YRrVSINT4De" alt=""><figcaption></figcaption></figure>


# Getting Started with Apxor


# Adding a New App

Please follow the following steps to add a new app to your organisation on the Apxor nudges dashboard. Once an app is created copy it's application identifier that uniquely identifies your app during integration.

#### Step 1: Create an account with Apxor

Your organisational owner who is handling the integration should sign up on the [nudges dashboard](https://nudges.apxor.com/sign_up). This account will have the administrator privileges to invite developers to complete the integration / other users of the organisation with respective privileges.

Enter your name, work email, phone number, job title and company name on the sign-up page. The company name you enter here will be displayed as the Organisation Name in the Apxor Dashboard.

<figure><img src="/files/lAImgFRA6rTyOk5F8nEQ" alt=""><figcaption></figcaption></figure>

#### Step 2: Setting of password to the registered account

After completing the sign-up, a link to set his password will be sent to the registered email address.

<figure><img src="/files/aFdiR4AxTpTaRznDDNt0" alt=""><figcaption></figcaption></figure>

The link would redirect the organisational owner to create a password to access his account

<figure><img src="/files/wDBoM45vgcmLA23Fwv02" alt=""><figcaption></figcaption></figure>

#### Step 3: Sign in and access your organisation

Please sign in on the nudges dashboard with your account credentials to access your organisation

<figure><img src="/files/FTvbadpnuX3i86pIovwA" alt=""><figcaption></figcaption></figure>

Select your organisation to add a new app inside your organisational account

<figure><img src="/files/DlZHOesRoPsmAMq634mj" alt=""><figcaption></figcaption></figure>

#### Step 4: Add a new application to your organisation

Click on add application to add a new application to the Apxor dashboard.\ <br>

<figure><img src="/files/F7neIqlQ6WbXibEO0ECJ" alt=""><figcaption></figcaption></figure>

Enter your app name and app icon url to identify your app on the Apxor dashboard

<figure><img src="/files/vW5iP5OVcBxF1NLDFOUT" alt=""><figcaption></figcaption></figure>

#### Step 5: Copy the application identifier

Tap to copy the application identifier on the top right corner

<figure><img src="/files/zhuerbhiacJrkY3CZ3fV" alt=""><figcaption></figcaption></figure>

#### Step 6 : Continue with the integration process

Congratulations, you have successfully copied the application identifier that you can use in the integration process to uniquely identify your app with Apxor. Please continue with the integration process by clicking [here](/getting-started-with-apxor/sdk/android-x#things-to-keep-handy-before-starting-your-integration)

{% hint style="info" %}
**Note**

Once you create a new app,It usually takes 1-2 hours for review. Our Admin will send an email on approval. You can also email us at <sales@apxor.com> for any queries. Thank you.
{% endhint %}

#### Additional Information

Recommend the developer to ask for dashboard access to the organisational owner to provide accurate information of the app bundleId, FCM Server key and verify the integration.\
\
The organisational owner will have the privilege to add developer by clicking on **InviteDevelopers > Invite** and by entering the developer email id.

<figure><img src="/files/JTbDAOG4ZnGUenTPXsuU" alt=""><figcaption></figcaption></figure>


# Firebase Credentials (optional)

Directions on how to generate a Firebase Server API key for sending silent push notifications for uninstall tracking to measure your campaign outcomes. These are optional and only needed if you want to track the uninstalls.

#### What is a Firebase Server Key?

A Firebase Server Key and Firebase Sender ID are required in order to send push notifications to Android mobile app devices.

#### Step 1 : Create A Firebase Project

Sending push Notifications would require a Firebase Project. If you don't have one click `Add project` and follow the directions to setup your project.

If you already have an FCM project, please move to step 2

<figure><img src="/files/KE5hQl8mfMlYygWY9MUT" alt=""><figcaption></figcaption></figure>

#### Step 2 : Getting Your Firebase Cloud Messaging Token And Sender ID

Click the gear icon in the top left and select Project settings.

Select the Cloud Messaging tab.

Refresh the page on your Firebase Console and copy your Server key and Sender ID.

<figure><img src="/files/G6PeGw5OTpYcCLPLJvI1" alt=""><figcaption></figcaption></figure>

#### Step 3 : Configure Your Apxor Android Platform Settings

<figure><img src="/files/s1FgjkZuQzDC5QnNESSl" alt=""><figcaption></figcaption></figure>

#### Step 4 : Setting up uninstall tracking on Apxor

Please ensure to follow the [uninstall tracking steps here](/getting-started-with-apxor/sdk/android-x#enable-uninstall-tracking-for-your-users-optional) based on your firebase version during integration.


# SDK


# Android (x)

## Prerequisites

Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from the Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id:** Every Android app has a unique application ID that looks like `com.example.myapp`. This ID uniquely identifies the app on the device and also on the Google Play Store.

{% hint style="info" %}
**Note**

Please add <mark style="background-color:blue;">**.apxor**</mark> as a suffix to the bundle ID when adding on the Apxor Dashboard

eg. <mark style="background-color:blue;">**`com.example.myapp.apxor`**</mark>
{% endhint %}

[(Know more about bundle IDs here)](https://developer.android.com/studio/build/configure-app-module)

* **The list of events** to set up triggers and track goals, user properties that allow to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking))
* **Firebase Cloud Messaging (FCM) Server Key:** To track uninstalls, Apxor sends silent push notifications to measure your campaign outcomes.\
  \
  ([Read more on how to fetch Firebase credentials that are used to set uninstall tracking during integration here](/getting-started-with-apxor/firebase-credentials-optional))

**Understanding dependencies to add to your project**

<table><thead><tr><th width="258.3333333333333">Plugin Name</th><th width="252">Description</th><th>Example</th></tr></thead><tbody><tr><td>apxor-android-sdk-core</td><td>Core Plugin is used to track events for to measure their results and consists of essential information that controls other plugins.</td><td>How many of my users have clicked on the cart icon after showing them a nudge Sample Event : 'ViewCart'</td></tr><tr><td>apxor-android-sdk-qe</td><td>plugin is used to setup behavioural triggers for the campaigns which helps to setup campaign rules.</td><td>Show a campaign to users who land on the home screen and add an item to the cart.</td></tr><tr><td>apxor-android-sdk-rtm</td><td>plugin is used for the show experiences created from the design library using the Apxor dashboard.</td><td>Show a tooltip on the cart icon with messaging "Tap here to view items"</td></tr><tr><td>com.apxor.android:surveys</td><td>plugin is used to show surveys created using the Apxor dashboard.</td><td>An NPS survey that would ask the user to rate the app experience on a scale of 1-10.</td></tr><tr><td>com.apxor.android:wysiwyg</td><td>plugin is used to facilitate creation of campaigns by mirroring your mobile screen to identify the right UI element to show the campaign.</td><td>Casting your mobile screen to the dashboard and selecting the hamburger icon</td></tr></tbody></table>

## Integration and Initialization

### Step 1: Add Apxor Repository

Add Maven URL in project level `build.gradle` file

**`Path: <project>/build.gradle`**:

<pre class="language-java"><code class="lang-java">
allprojects {
<strong>    repositories {
</strong>        // ...
        maven {
           url "https://repo.apxor.com/artifactory/list/libs-release-android/"
        }
        // ...
    }
}
</code></pre>

<figure><img src="/files/Tuj8ho4phsLmB5qmCUEb" alt=""><figcaption></figcaption></figure>

### Step 2: Add dependencies

Add plugin dependencies to your application `build.gradle` file

**`Path: <project>/<app-module>/build.gradle`**:

[Check the latest release notes here.](/getting-started-with-apxor/release-notes#android)

#### 2.1 ApxorSDK dependencies (mandatory)

```groovy
dependencies {
//...

    // Event tracking and a must-have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.2.5@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.9@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.7.5@aar'
    implementation 'com.apxor.androidx:surveys:2.3.1@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.5@aar'
    
    // Add the below two dependencies to establish an SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
//...
}
```

#### 2.2 Add exoplayer in your app (optional)

<details>

<summary>Add exoplayer in your app</summary>

Exoplayer enables you to configure Picture In Picture videos from the Apxor dashboard; if you are already using the exoplayer in your app, this step is not needed; otherwise, add the following dependency in the application  `build.gradle` file. To use video pip templates, this is necessary.

<img src="/files/BMQoL6soL1X6E8GmUgTs" alt="" data-size="original">

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.6\@aar version onwards**</mark>

```gradle
dependencies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.5\@aar and below**</mark>

```gradle
dependencies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

#### 2.3 Enable uninstall tracking for your users (optional)

<details>

<summary>Enable uninstall tracking for your users</summary>

Apxor uses your Firebase server key to send silent push notifications to track uninstalls and measure the outcomes of your campaign. To enable this, please do the following:

<mark style="background-color:blue;">**For Firebase Version < 22.0.0**</mark>

```gradle
dependencies {
  // Add this to track uninstalls from the Apxor dashboard
  implementation('com.apxor.androidx:apxor-android-sdk-push:1.2.8@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

Please handle the notifications like the following:

```gradle
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Creating Notification Channel
        ApxorPushAPI.createNotificationChannel(this.getApplicationContext(), "Apxor", "Apxor", "Apxor");
        if (remoteMessage.getFrom().equals(YOUR_FCM_SENDER_ID)) {
            // Push Notification receiver with your Sender ID
        } else {
            // Check if Push Notification received from Apxor
            if (ApxorPushAPI.isApxorNotification(remoteMessage)) {
                ApxorPushAPI.handleNotification(remoteMessage, getApplicationContext());
            } else {
                // Silent or Data push notification, which you can send through Apxor dashboard
            }
        }
    }
}
```

<mark style="background-color:blue;">**For Firebase Version >= 22.0.0**</mark>

```gradle
dependencies {
  // Add this to track uninstalls from the Apxor dashboard
  implementation('com.apxor.androidx:apxor-android-sdk-push-v2:1.3.1@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

[Read here](/getting-started-with-apxor/firebase-credentials-optional) on how to get your Firebase sender ID and also FCM server key to share it with apxor to configure uninstall tracking.

</details>

#### 2.4 Install Referrer Dependency (optional)

<details>

<summary>Install Referrer Dependency (optional)</summary>

If added, we can provide install attribution.

```gradle
dependencies {

  // Add this to get the install attribution
  implementation "com.android.installreferrer:installreferrer:2.2"
  
}
```

</details>

### Step 3: Add the following in proguard-rules.pro

{% hint style="info" %}
**Note**

If you use proguard to obfuscate the classes, you have to add the following to ignore obfuscation for Apxor SDK classes
{% endhint %}

Configure the below rules in your `proguard-rules.pro` file

**`Path: <project>/<app-module>/proguard-rules.pro`**:

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

### Step 4: Disable Dexing Artifact Transformation

{% hint style="info" %}
**Note**

In Android Gradle Plugin 3.5.0, we use Gradle artefact transforms for desugaring and dexing, enabling greater parallelism and caching. This process depends on libraries having accurate Maven information since dependencies specified in POM files are used to set up the desugaring classpath. If we encounter issues with missing dependencies during desugaring, it's necessary to disable parallel transformation to facilitate the process by adding the following property:
{% endhint %}

Add the following to `gradle.properties` file

**`Path: <project>/<app-module>/gradle.properties`**:

```java
android.enableDexingArtifactTransform = false
```

### Step 5: Initialize ApxorSDK

To start tracking with the Apxor Android SDK, you must first initialize it.

{% hint style="warning" %}
**Make Sure to enter the AppID for `$APXOR_ID`**

You will need your Application Identifier for this. Here is how you can get the Apxor Application Identifier, as mentioned in the [Integration Essentials section](/getting-started-with-apxor/adding-a-new-app)
{% endhint %}

<details>

<summary>Auto Initialization (Recommended)</summary>

To Auto initialize SDK, add the following `meta-data` tag inside your `application` tag in your `AndroidManifest.xml` file. This will check for Apxor SDK, and if present, will initialize automatically.

**`Path: <project>/<app-module>/src/AndroidManifest.xml`**:

```java
<application>
//...
    <meta-data android:name="APXOR_APP_ID" android:value="$APXOR_ID"/>
//...
</application>
```

</details>

<details>

<summary>Manual Initialization</summary>

Alternatively, you can initialize it manually with your Apxor App ID. To initialize the SDK,

```java
ApxorSDK.initialize("$APXOR_ID" , this.getApplicationContext());
```

</details>

### You are all set: Verify your SDK integration

We have to verify two things as follows :

#### **SDK Initialization**

On running your Android project, search for the following log in logcat :

```java
ApxorSDK(v2**) successfully initialized for: APP_ID
```

<figure><img src="/files/YvXdm3C74F7yb5fcYmgP" alt=""><figcaption></figcaption></figure>

#### **Plugin Initialization**

By default, only error logs are enabled. To see debug logs for plugin initialization and to confirm tracking event triggers and user properties, Please run the below command in the terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="/files/sRoXlvsMhggAWYRwLrnC" alt=""><figcaption></figcaption></figure>

## Add-Ons

Now that you have completed the basic integration, you can proceed to set up event triggers, capture data for targeting, add slots for embed cards and stories, and personalize messaging. Include the following sections as needed.

### Identifying Users <a href="#identifying-users" id="identifying-users"></a>

{% hint style="info" %}
This section is **mandatory** if you intend to use **Segments and Cohorts.**
{% endhint %}

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 for 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 recognize your users :

```java
ApxorSDK.setUserIdentifier(<SOME_USER_ID>);
```

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

```java
String deviceId = ApxorSDK.getDeviceId(applicationContext);
```

### Log events and user data for Targeting, Triggering and goal Tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

The product/marketing or the growth team lists the use cases with an idea of when 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:

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

#### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 <mark style="background-color:yellow;">app events</mark> - the data that is transferred to the servers at Apxor, where you can segment users based on historical behaviour or measure your goals as specified above.

Here is how we track app events :

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

#### Client Events[**​**](http://localhost:3000/docs/android-sdk/Tracking#client-events) <a href="#client-events" id="client-events"></a>

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 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.<br>

So for such scenarios where we need the behavioural 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 <mark style="background-color:yellow;">Client Events</mark>, which involves zero transfer of data and is used only to set up your triggers on behavioural information from the user.

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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

#### User Attributes <a href="#user-attributes" id="user-attributes"></a>

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.&#x20;

Let us consider the following example where we know the user prefers <mark style="background-color:yellow;">English</mark> as a language and has a <mark style="background-color:yellow;">Gold</mark> membership. This information helps to tailor content in English to that specific user and gives us the flexibility to use different messaging for different membership tiers. This is how the information captured here is used for segmenting.<br>

Similarly, capturing attributes like <mark style="background-color:yellow;">Name</mark>, can you 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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```java
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 href="#session-attributes" id="session-attributes"></a>

A Session can be simply defined as a user's journey from when 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,

```java
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,

```java
Attributes sessionInfo = new Attributes();
sessionInfo.putAttribute("network", "4G");
sessionInfo.putAttribute("city", "GAJ");
ApxorSDK.setSessionCustomInfo(sessionInfo);
```

### Track Screens <a href="#track-screens" id="track-screens"></a>

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 track the screens to set them up as triggers and also to capture the time spent on the screens.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Please ensure the following if you have fragments:**

* If your screen has **different fragments,** then it is important to track all the fragments using the API once the screen is visible to your user
* If you use [Android's Navigation architecture component](https://developer.android.com/guide/navigation), 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:
  {% endhint %}

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

```java
ApxorSDK.trackScreen("HomeScreen");
```

{% hint style="info" %}
**Note**

Make sure you use the `ApxorSDK.trackScreen` API in your activity's `onResume` method
{% endhint %}

```java
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
        }
    }
});
```

```java
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
    }
});
```

### Nudges in WebView <a href="#tooltips-in-webview" id="tooltips-in-webview"></a>

#### Tooltips in WebView <a href="#tooltips-in-webview" id="tooltips-in-webview"></a>

{% hint style="info" %}
**Note**

Make sure you have `apxor-sdk-rtm` plugin version >= 1.5.3
{% endhint %}

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.

  ```java
  webView.setTag("MyWebView");
  ```
* Attach Apxor SDK JavaScript Interface as mentioned below.

  ```java
  // You must enable Javascript for the webview
  WebSettings settings = webView.getSettings();
  settings.setJavaScriptEnabled(true);

  // Attach Apxor SDK Javascript Interface
  webview.addJavascriptInterface(new ApxorJSInterface(), "Apxor");
  ```

{% hint style="success" %}
That's it. All you have to do is set some IDs for your HTML elements inside your web page and configure them in the dashboard along with WebView's tag.
{% endhint %}

#### Log Events inside WebView <a href="#log-events-inside-webview" id="log-events-inside-webview"></a>

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

  ```js
  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.

  ```html
  ...
  <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.

  ```js
  componentDidMount() {
      if (window.Apxor && window.Apxor.logAppEvent) {
          window.Apxor.logAppEvent('LoginPageLoaded', null);
      }
  }
  ```

### Embed and Story Slots

#### Add Embed Card Slot

{% hint style="warning" %}
**Note**

For using Embed Cards, the versions of the following plugins should be greater than or equal to the ones mentioned below

**Core: 3.1.0**

**qe: 1.7.5**

**rtm: 2.4.8**

**WYSIWYG: 1.5.6**
{% endhint %}

For using Apxor's Embed cards template, this step is necessary.

In all areas of the app where you may want to show an in-line widget, insert the following code in the XML

```xml
<com.apxor.androidsdk.plugins.realtimeui.ApxorWidget
        android:tag="<Tag>"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID. Ensure that you keep the ID unique across different IDs and across different ApxorWidget instances.

Alternatively, you can also add the view dynamically during runtime. Make sure the widget is in a place where it can occupy the entire width and height as per its requirement.

```java
ApxorWidget widget = new ApxorWidget(context,"<Tag>")
layout.addView(widget);
```

#### Add Story Slot

{% hint style="warning" %}
**Note**

For using Stories, the versions of the following plugins should be greater than or equal to the ones mentioned below

**Core: 3.1.0**

**qe: 1.7.5**

**rtm: 2.4.8**

**WYSIWYG: 1.5.6**
{% endhint %}

For using Apxor's Stories template, this step is necessary.

In all areas of the app where you may want to show an in-line widget, insert the following code in the XML

```xml
<com.apxor.androidsdk.plugins.realtimeui.stories.ApxorStoryWidget
        android:tag="<Tag>"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID. Ensure that you keep the ID unique across different IDs and across different ApxorWidget instances.

Alternatively, you can also add the view dynamically during runtime. Make sure the widget is in a place where it can occupy the entire width and height as per its requirement.

```java
ApxorStoryWidget widget = new ApxorStoryWidget(context,"<Tag>")
layout.addView(widget);
```

### Handle custom redirection using Key-Value pairs <a href="#handle-custom-redirection-using-key-value-pairs" id="handle-custom-redirection-using-key-value-pairs"></a>

If your app wants to redirect users based on simple key-value pairs instead of using Deeplink URLs or Activity, you can follow the below approach

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

        }
      }
    });
  }
}
```

### Miscellanious <a href="#reporting-custom-errors" id="reporting-custom-errors"></a>

#### Reporting Custom Errors <a href="#reporting-custom-errors" id="reporting-custom-errors"></a>

Custom errors describe situations like LOGIN\_FAILED and 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 to identify. To report a custom error,

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

#### To get Apxor Device Identifier <a href="#to-get-apxor-device-identifier" id="to-get-apxor-device-identifier"></a>

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID, use the below

```java
String deviceId = ApxorSDK.getDeviceId(applicationContext);
```

#### To get Apxor Attributes <a href="#to-get-apxor-attributes" id="to-get-apxor-attributes"></a>

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**.

```java
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");
    }
  }
);
```

## Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy).


# iOS SDK

#### Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.apple.com/documentation/appstoreconnectapi/bundle-ids)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](/getting-started-with-apxor/api-guides/ios))

{% hint style="info" %}
**Note**

If you are already using a separate analytics class where you are sending events to different platforms from a single place it is much faster to use our tracking guide to complete event logging to setup triggers and track goals.

In case you are logging events to third parties after each interaction, please use our [Third party API guide](broken://pages/6mI0HCleo5SS08RVwKwr) to migrate all the events that you are sending to one of the supported third parties as listed in the guide.
{% endhint %}

## Getting started with Apxor iOS

Apxor provides you easy to use plugins for your Actions. They are:

<table><thead><tr><th width="206.33333333333331">Plugin Name</th><th width="253">Description</th><th>Example</th></tr></thead><tbody><tr><td>Apxor-Core</td><td>The Core Plugin is responsible for the basic event tracking</td><td>How many of my users have clicked on the cart icon after showing them a nudge Sample Event : 'ViewCart'</td></tr><tr><td>APXSurveyPlugin</td><td>This Plugin helps you create contextual surveys to capture your users' feedback, ratings, etc.</td><td>An NPS survey that would ask the user to rate the app experience on a scale of 1-10.</td></tr><tr><td>APXRTAPlugin</td><td>This Plugin helps you create real time actions.</td><td>Show a tooltip on the cart icon with messaging "Tap here to view items"</td></tr><tr><td>APXWYSIWYGPlugin</td><td>The WYSIWYG Plugin allows you to preview your configured actions onto your device in real time</td><td>Casting your mobile screen to the dashboard and selecting the hamburger icon</td></tr><tr><td>APXPushPlugin</td><td>The Push Plugin allows you to track uninstalls and real-time serve/pause the nudges, while the app is opened</td><td>Show a campaign to users who land on the home screen and add an item to the cart.</td></tr></tbody></table>

[Check here for the latest release notes](/getting-started-with-apxor/release-notes#ios).

## Adding Apxor SDK to your project

{% tabs fullWidth="false" %}
{% tab title="Cocoa Pods  " %}
{% hint style="danger" %}

## Cocoa Pods has announched that going further there will no updates.&#x20;

Cocoa Pods will be moved to read only mode followed by archieve. Users should switch to SPM for any updates related to cocoa pods. \
\
Refer the blog :<https://blog.cocoapods.org/CocoaPods-Specs-Repo/>
{% endhint %}

* Install **CocoaPods**, if you don't already have it. CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over 95 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly.&#x20;
* If this is your first pod, run **`pod init`**. Add the following to the corresponding target in your Podfile and run **`pod install`**.

```groovy
use_frameworks!
pod 'Apxor-Core', '2.10.46'
pod 'Apxor-CE', '1.05.33'
pod 'Apxor-RTA', '1.09.54'
pod 'Apxor-WYSIWYG', '1.02.76'
pod 'Apxor-Survey', '1.04.25'
```

{% endtab %}

{% tab title="Swift Package Manager" %}
Use Swift Package Manager to install and manage Apxor dependencies.

1. In Xcode, with your app project open, navigate to **File** > **Add Packages.**

<figure><img src="/files/XwSmGsFKUd3OuuTScyKl" alt=""><figcaption></figcaption></figure>

2. When prompted, add the Apxor Apple platforms SDK repository:

```
https://github.com/apxor/ApxorSDK
```

<figure><img src="/files/OEtW7uyZVsdl4of48WKP" alt=""><figcaption></figcaption></figure>

3. Click on "**Add to Target**" and select your project.

{% hint style="warning" %}
**Note:** All the Package Product should have the same project selected. This ensures complete SDK integration.
{% endhint %}

<figure><img src="/files/Nb4op3FPxn6N4cXoLHZB" alt=""><figcaption></figcaption></figure>

> <p align="center">When finished, Xcode will automatically begin resolving and downloading your dependencies in the background.</p>

{% endtab %}

{% tab title="Manual" %}

| Plugin Name                                                                                                   | Latest Version                                              |
| ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| [ApxoriOSSDK-Core](https://repo.apxor.com/artifactory/libs-release-ios/core/21044/ApxoriOSSDK-Core-21044.zip) | The Core Plugin is responsible for the basic event tracking |

* Download the above and Unzip to find **`ApxorSDK.framework`** directory

### Adding Apxor SDK to your project

1. Add **`ApxorSDK.framework`** to your **"Frameworks, Libraries and Embedded Content"** list. (for xcode < 11, under **“Embedded Binaries”**)
2. Also add the **`libsqlite3.dylib`** (or **`libsqlite3.0.tbd`**) library to the same list.
3.

```
<figure><img src="/files/ifRI4C3D2xbM3YNwnMYp" alt=""><figcaption></figcaption></figure>
```

4. Under build settings tab, in **"Other Linker Flags"**, add **`-ObjC`** , if not already present.

<figure><img src="/files/3nOOyEXr8PHM65ZiJDlI" alt=""><figcaption></figcaption></figure>

### Add Apxor script

* Add the following in the **Run script** phase in your build phases.

```
# Script to strip unwanted architectures

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

find "$APP_PATH" -name '*[A][Pp][Xx]*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

EXTRACTED_ARCHS=()

for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done

echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"

echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

done
```

<figure><img src="/files/BzL4mubpv0o0nqsEKqTU" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/JYTgQFmoyuypipHi8RS6" alt=""><figcaption></figcaption></figure>

### Plugins Integration

* Add the libraries to your application's **"Frameworks, Libraries and Embedded Content"** list. (Click on the plugin name to download)
* Apxor provides you two easy to use plugins for your Actions. They are:

| Plugin Name                                                                                                      | Description                                                                                    |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [APXSurveyPlugin](https://repo.apxor.com/artifactory/libs-release-ios/survey/10424/ApxoriOSSDK-Survey-10424.zip) | This Plugin helps you create contextual surveys to capture your users' feedback, ratings, etc. |
| [APXRTAPlugin](http://repo.apxor.com/artifactory/libs-release-ios/rta/latest/ApxoriOSSDK-RTA.zip)                | This Plugin helps you create real time actions.                                                |

* Make sure to add the following dependency plugins as well,

| Plugin Name                                                                                                         | Description                                                                                    |
| ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [APXCEPlugin](https://repo.apxor.com/artifactory/libs-release-ios/ce/10531/ApxoriOSSDK-CE-10531.zip)                | The Secret Sauce                                                                               |
| [APXWYSIWYGPlugin](http://repo.apxor.com/artifactory/libs-release-ios/debug/wysiwyg/latest/ApxoriOSSDK-WYSIWYG.zip) | The WYSIWYG Plugin allows you to preview your configured actions onto your device in real time |
| {% endtab %}                                                                                                        |                                                                                                |
| {% endtabs %}                                                                                                       |                                                                                                |

## Initialize Apxor iOS SDK

### Auto initialize SDK (Recommended)

* To Auto initialize SDK (Recommended), add the following inside your **`application`** plist file.
* Open your application's **Info.plist** as source code.

<figure><img src="/files/A2eDZBOplAFoGRpOqnRa" alt=""><figcaption></figcaption></figure>

* Copy paste the below piece of code, to create an entry for ApxorSDK.

```groovy
<key>Apxor</key>
<dict>
    <key>Core</key>
    <string>YOUR_APP_ID</string>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

### Manually initialize SDK (Not Recommended)

* To manually initialize SDK, call **`ApxorSDK.initialize`** method in your **`Application`** class

```groovy
//...
#import "ApxorSDK/ApxorSDK.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [ApxorSDK initializeApxorWithID:@"<YOUR_APP_ID>"];
    // ... your code
}
```

* And open your application's **Info.plist** as source code.

<figure><img src="/files/A2eDZBOplAFoGRpOqnRa" alt=""><figcaption></figcaption></figure>

* Copy paste the below piece of code, to create an entry for ApxorSDK.

```groovy
<key>Apxor</key>
<dict>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

{% hint style="info" %}
**Note**

To get your app ID, please email us at <mark style="color:blue;">**<contact@apxor.com>**</mark>
{% endhint %}

## Configuring Test Device

* First, you need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.
* If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

### Configure URL Scheme

* To configure URL scheme, goto your project settings, select **`Targets`**. Click on the **`Info`** tab.
* Select the **`URL Types`**, and click on the **`+`** button to add a new URL Scheme.
* Add a new URL Scheme with your **`bundle identifier`** as the value.
* Your bundle identifer will be in the format, **`com.xxxx.xxxx`**
* Use the image below for reference.

<figure><img src="/files/h0DXDpIUwnWJcE5UUtIf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your **bundle identifier** that was provided in the dashboard while registering with us. Also, the app must have same **bundle identifier.**
{% endhint %}

### Handling the deep link

<details>

<summary>Using AppDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`AppDelegate`** file, in the function **`application(_:open:options:)`**, add the following code at the beginning,

```swift
// ObjC
NSString *urlStr = url.absoluteString;
if ([urlStr containsString:@"add-test-device"]) {
  [ApxorSDK handleDeeplink:url];
}
```

```objectivec
// Swift
/*
  Apxor's code to handle deeplinks
  */
let urlStr = url.absoluteString
if (urlStr.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url)
}
```

* This will ensure the Apxor specific deep links are handle by our SDK.

</details>

<details>

<summary>Using SceneDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`SceneDelegate`** file, add the following code at the beginning,

```objectivec
// ObjC
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
  for(UIOpenURLContext *x in URLContexts) {
    NSURL *url = x.URL;
    if([[url absoluteString] containsString:@"add-test-device"])
    {
      [ApxorSDK handleDeeplink:url];
    }
    break;
  }
}
```

```swift
// Swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  let url = URLContexts.first?.url
  let urlStr = url?.absoluteString
  if (urlStr!.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url!)
  }
}
```

</details>

## Configuring Push Notifications

* To use the push notifications feature, make sure the following lines exist in your application plist file under Apxor section.

```
<key>APXPushPlugin</key>
<true/>
```

* To configure iOS Push notification via Apxor dashboard, you'd need to upload APNs Auth Key file along with it's ID (key ID), your Team ID, and your application's Bundle ID.
* The APNs Auth Key is the best way to configure pushes, as you don't need to regenerate a certificate every year and also, this key can be used to configure Push notifications to sever of your applications (under the same apple developer account)
* Things required to configure iOS Push notification:
* Auth Key file
  * Key ID (usuallly the name of the Auth Key file)
  * Team ID (the 10 digit alphanumeric key)
  * Your app’s bundle ID (in the format com.abc.xyz)
  * See here on how to get these, Push notifications
* Once you get those details, add the below code in your application's **`AppDelegate`** file in the **`application`** **`didRegisterForRemoteNotificationsWithDeviceToken`** function.

```
import APXPushPlugin

let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
APXPushPlugin.setPushDeviceToken(token)
```

```
[APXPushPlugin setPushDeviceToken:token];
```

* The token can be passed in either the **`NSData`** or **`NSString`** format

<figure><img src="/files/ar6RPB8we81YamczxL27" alt=""><figcaption></figcaption></figure>

* If you haven't already used the code to Ask User for notifications permission, add the following function in your **`AppDelegate`** file.

```
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  // your existing code ...

  registerForPushNotifications()

  // ...
}

func registerForPushNotifications() {
  UNUserNotificationCenter.current()
    .requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] granted, error in
      print("Permission granted: \(granted)")
      guard granted else { return }
      self?.getNotificationSettings()
    }
}

func getNotificationSettings() {
  UNUserNotificationCenter.current().getNotificationSettings { settings in
    print("Notification settings: \(settings)")
    guard settings.authorizationStatus == .authorized else { return }
    DispatchQueue.main.async {
      UIApplication.shared.registerForRemoteNotifications()
    }
  }
}
```

## Embed Slot

{% hint style="info" %}
**Note**

For using Apxor Embedded Cards the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

For using Apxor's immersive template embedded cards, this step is necessary.

In all areas of the app where you may want to show an in-line widget, insert the following code in the view controller:

```swift
// Swift

let EmbedCard = APXRTAPlugin.initEmbedCard(withId: <Tag>)!

// you can add it in a UIStackView (recommended)
let stackView = UIStackView()
stackView.addArrangedSubview(EmbedCard)

// add your other existing views if any
stackView.addArrangedSubview(existingView1)
.
.

// if you want to add it in a UIView
let sampleView = UIView()
sampleView.addSubview(EmbedCard)

// add constraints (optional)
EmbedCard.translatesAutoresizingMaskIntoConstraints = false

EmbedCard.topAnchor.constraint(equalTo: sampleView.topAnchor).isActive = true
EmbedCard.leadingAnchor.constraint(equalTo: sampleView.leadingAnchor).isActive = true
EmbedCard.bottomAnchor.constraint(equalTo: sampleView.bottomAnchor).isActive = true
EmbedCard.trailingAnchor.constraint(equalTo: sampleView.trailingAnchor).isActive = true
```

```objectivec
// Objective-C

APXEmbedCard *embedCard = [APXRTAPlugin initEmbedCardWithId: <Tag>];

// you can add it in a UIStackView (recommended)
UIStackView *stackView = [[UIStackView alloc] init];
[stackView addArrangedSubview:embedCard];

// add your other existing views if any
[stackView addArrangedSubview:existingView1];
.
.

// if you want to add it in a UIView
UIView *sampleView = [[UIView alloc] init];
[sampleView addSubview:embedCard];

// add constraints (optional)
embedCard.translatesAutoresizingMaskIntoConstraints = NO;

[NSLayoutConstraint activateConstraints:@[
    [embedCard.topAnchor constraintEqualToAnchor:sampleView.topAnchor],
    [embedCard.leadingAnchor constraintEqualToAnchor:sampleView.leadingAnchor],
    [embedCard.bottomAnchor constraintEqualToAnchor:sampleView.bottomAnchor],
    [embedCard.trailingAnchor constraintEqualToAnchor:sampleView.trailingAnchor]
]];

```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID (any positive Integer). Ensure that you keep the ID unique across different IDs and across different Embed Card instances.

## Story Slot

{% hint style="info" %}
**Note**

For using Apxor Stories the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

In all areas of the app where you may want to show an in-line widget, insert the following code in the view controller:

```swift
// Swift

let StoryWidget = APXRTAPlugin.initStories(withId: <Tag>)!

// you can add it in a UIStackView (recommended)
let stackView = UIStackView()
stackView.addArrangedSubview(StoryWidget)

// add your other existing views if any
stackView.addArrangedSubview(existingView1)
.
.

// if you want to add it in a UIView
let sampleView = UIView()
sampleView.addSubview(StoryWidget)

// add constraints (optional)
StoryWidget.translatesAutoresizingMaskIntoConstraints = false

StoryWidget.topAnchor.constraint(equalTo: sampleView.topAnchor).isActive = true
StoryWidget.leadingAnchor.constraint(equalTo: sampleView.leadingAnchor).isActive = true
StoryWidget.bottomAnchor.constraint(equalTo: sampleView.bottomAnchor).isActive = true
StoryWidget.trailingAnchor.constraint(equalTo: sampleView.trailingAnchor).isActive = true
```

```objectivec
// Objective-C

APXStoryGroup *storyWidget = [APXRTAPlugin initStoriesWithId:<Tag>];

// you can add it in a UIStackView (recommended)
UIStackView *stackView = [[UIStackView alloc] init];
[stackView addArrangedSubview:storyWidget];

// add your other existing views if any
[stackView addArrangedSubview:existingView1];
.
.

// if you want to add it in a UIView
UIView *sampleView = [[UIView alloc] init];
[sampleView addSubview:storyWidget];

// add constraints (optional)
storyWidget.translatesAutoresizingMaskIntoConstraints = NO;

[NSLayoutConstraint activateConstraints:@[
    [storyWidget.topAnchor constraintEqualToAnchor:sampleView.topAnchor],
    [storyWidget.leadingAnchor constraintEqualToAnchor:sampleView.leadingAnchor],
    [storyWidget.bottomAnchor constraintEqualToAnchor:sampleView.bottomAnchor],
    [storyWidget.trailingAnchor constraintEqualToAnchor:sampleView.trailingAnchor]
]];

```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID (any positive Integer). Ensure that you keep the ID unique across different IDs and across different Stories instances.

## Ensuring Apxor SDK is initialized successfully

* Lookout for the following log

<figure><img src="/files/lZ7MDzf7ZBl4IbnUyCRW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/jNo4ltENh343LgxdAxyz" alt=""><figcaption></figcaption></figure>

[Click here for guide](/getting-started-with-apxor/api-guides/ios) to log user properties, events and event properties.

## Add-Ons

Now that you have completed the basic integration, you can proceed to set up event triggers, capture data for targeting, add slots for embed cards and stories, and personalize messaging. Include the following sections as needed.

### Initializing the SDK

To start tracking with the Apxor iOS SDK, you must first initialize it. To initialize the SDK,

```objectivec
// ObjC
[ApxorSDK initializeApxorSDK];
```

```swift
// Swift
ApxorSDK.initializeApxorSDK()
```

### Identifying the Users

ApxorSDK uses Identifier for Advertisers (IFA) to uniquely identify users. In cases where IFA is not available, we use Identifier for Vendors (IFV) for the same. 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 specially 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 want 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 :

```objectivec
// ObjC
[ApxorSDK setUserIdentifier:@"1729"];
```

```swift
// Swift
ApxorSDK.setUserIdentifier("CustomUserIdentifier")
```

### Setting up campaign triggers, capturing data for targetting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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 behavior or measure your goals as specified above.

To track an event with the event name and properties.

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"Select Language" forKey:@"event_type"];
[info setValue:@"Valyrian" forKey:@"event_type"];
[ApxorSDK logAppEventForEvent:@"LANG_SELECT" withInfo:info];
```

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

```swift
// Swift
let eventDict = ["event_type":"Select Language", "event_type":"Valyrian"] as [String : AnyObject]
ApxorSDK.logAppEvent(withName: "EventName", info: eventDict)
```

### User Attributes

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"spock@vulcan.com" forKey:@"email"];
[ApxorSDK setUserCustomInfo:info];
```

```swift
// Swift
let userInfo = ["email": "spock@vulcan.com"] as [String : AnyObject]
ApxorSDK.setUserCustomInfo(userInfo)
```

### Session Attributes

A Session can be simply defined as a user journey as he opens the app, until he closes the app. There can be various pieces of information that can be very impactful when accumulated in a session. For example, location in a session can be useful to know precisely where the user is utilizing the app most.

To add session attributes that are specific to a session,

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"In a galaxy far far away" forKey:@"location"];
[ApxorSDK setSessionCustomInfo:info];
```

```swift
// Swift
let userInfo = ["location": "In a galaxy far far away"] as [String : AnyObject]
ApxorSDK.setSessionCustomInfo(userInfo)
```

### 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.<br>

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.

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 behavioral observations and interactions to nudge a user.

> Example:
>
> Soft back button, user reaching end of page, etc.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"com.example.app.SettingsViewController" forKey:@"Screen"];
[ApxorSDK logClientEventWithName:@"SoftBackPressed" info:info];
```

```swift
// Swift
let eventDict = ["Screen":"com.example.app.SettingsViewController"] as [String : AnyObject]
ApxorSDK.logClientEvent(withName: "SoftBackPressed", info: eventDict)
```

### Track Screens <a href="#track-screens" id="track-screens"></a>

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

ApxorSDK automatically captures screens and their names for most view controllers. In some cases where TabBarController is used, the OS won't be providing any notifications to capture the screens automatically.

For these cases, we encourage you to log screen events using the following API. Make sure to log the API inside the **viewWillAppear** function.

```objectivec
// ObjC
- (void)viewWillAppear:(BOOL)animated {

    [ApxorSDK logScreenWithName:@"FirstViewController"];
    /*
      ... your code here ...
     */
}
```

```swift
// Swift
override func viewWillAppear(animated: Bool) {

    ApxorSDK.logScreenWithName("FirstViewController")
    /*
      ... your code here ...
    */
}
```

### 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 to identify. To report a custom error,

```objectivec
// ObjC
NSException* myException = [NSException
                            exceptionWithName:@"FileNotFoundException"
                            reason:@"File Not Found on System"
                            userInfo:nil];
[ApxorSDK reportCustomError:myException withContext:@"customException"];
```

```swift
// Swift
let errorInfo = ["reason": "File Not Found on System"]  as [String : AnyObject]
var customError = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
ApxorSDK.reportCustomError(customError, withInfo: errorInfo)
```

### Custom Fonts

ApxorSDK supports two types of fonts namely, .ttf(TrueType fonts) and .otf(OpenType fonts). Custom fonts can be used in ApxorSDK's real time actions in two simple steps.

#### Adding custom fonts to your application

* Fonts of your choice and selection are to be added in the **`Project's`** **`Supporting files`** section

<figure><img src="/files/w8jLWT5vMd02WGI74Kqv" alt=""><figcaption></figcaption></figure>

* Edit the Info.plist file to add the font names in the **`Fonts provided by application`**

<figure><img src="/files/L8eOcjMpAti22U2GwKpE" alt=""><figcaption></figcaption></figure>

* Ensure the fonts are available in, **`Build phases`** --> **`Copy Bundle resources`**

<figure><img src="/files/EMf1gCrw2poTBAXZWbkq" alt=""><figcaption></figcaption></figure>

#### While configuring the campaigns in the dashboard

* Enable custom fonts
* Enter the same exact font file name along with the extenstion (.ttf or .otf)

<figure><img src="/files/6XEfFlBlAwEIaPGeiyNQ" alt=""><figcaption></figcaption></figure>

You're all set! 🎉

> **Note**
>
> Font properties like Bold, Italic cannot be used in the dashboard for custom fonts. The exact font file with those properties has to be added in your application.

#### 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

```
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  // Your code here
  // ...
  NotificationCenter.default.addObserver(self, selector: #selector(self.onRedirectionClicked(notification:)), name: Notification.Name("APXRedirectionNotification"), object: nil)
}

@objc func onRedirectionClicked(notification: NSNotification) {
  if let kvPairs = notification.userInfo!["info"] {
      print(kvPairs)
      // ...
      // use kvPairs 
      // ...
  }
}
```

```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Your code here
  // ...
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRedirectionClicked:) name:@"APXRedirectionNotification" object:nil];
}

- (void) onRedirectionClicked:(NSNotification *) notification
{
  NSLog(@"kvPairs: %@", notification.userInfo["info"]);
  // ...
  // use kvPairs 
  // ...
}
```

### To get Apxor Device Identifier

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID,

```objc
NSString *deviceId = [ApxorSDK getDeviceID];
```

> **Note**
>
> If the deviceID is nil, please retry after a few seconds.

### Log Events inside WebView <a href="#log-events-inside-webview" id="log-events-inside-webview"></a>

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

  ```js
  window.webkit.messageHandlers.logAppEvent.postMessage({"name": "...", "info": "..."});
  window.webkit.messageHandlers.logClientEvent.postMessage({"name": "...", "info": "..."});
  ```

  > **Note**
  >
  > Make sure the keys of the dictionary in postMessage are "name" and "info", do not change them.
* Examples for logging App Event

  > Example:
  >
  > Log an event on page load event.

  ```html
  ...
  <head>
    ...
    <script>
      function logApxorEvent(eventName, attributes) {
        if (window.webkit) {
          window.webkit.messageHandlers.logAppEvent.postMessage({"name": eventName, "info": attributes});
        }
      }
    </script>
  </head>
  <body onload="logApxorEvent('PageLoaded')">
    ...
  </body>
  ```

  > Example (React based web pages):
  >
  > Log an event on componentDidMount.

  ```js
  componentDidMount() {
      if (window.webkit) {
          window.webkit.messageHandlers.logAppEvent.postMessage({"name": 'LoginPageLoaded'});
      }
  }
  ```

### Actions in WebView

Many native applications feature WebViews to display descriptive content and much more. Apxor iOS SDK provides a way to show real-time actions inside that WebView to make the most of it.

Following are the steps in order to show real-time actions in your WebView.

* Add a tag to the webview (which is to be later provided in the dashboard) as shown.

  ```objectivec
  // ObjC
  [self.webview setTag:007];
  ```

  <pre class="language-swift"><code class="lang-swift"><strong>// Swift
  </strong><strong>webview.tag = 007;
  </strong></code></pre>
* You have to init the APXWKScriptHandler and call registerEventsAndScripts method to make sure any the calls made in the webview are taken care by the native SDK. It's as follows,

  * If you don't already have a bridging header, [checkout how to create a bridging header.](https://developer.apple.com/documentation/swift/importing-objective-c-into-swift)
  * Add the following in the bridging header file.

  ```ObjectiveC
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ```

  * Now, add the following to the init method of your webview

  ```
  let apxHandler: APXWKScriptHandler = APXWKScriptHandler.init(handlerFor: webView)
  apxHandler.registerEventsAndScripts()
  ```
* Here's how to do the same thing in objective-C.

  * Make sure there's a proper WKUserContentController set to your WkWebView, if not please init it and use that config to initialise your WKWebView.

  ```ObjectiveC
  WKUserContentController *controller = [[WKUserContentController alloc] init];
  WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  config.userContentController = controller;
  ```

  ```ObjectiveC
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ...
  // add apxor's script handler
  APXWKScriptHandler *scriptHandler = [[APXWKScriptHandler alloc] initWithHandlerForWebView:_webView];
  [scriptHandler registerEventsAndScripts];
  ```
* Also, make sure there’s an id for the web element that you want to show tooltip on.

<figure><img src="/files/AQ7OUJTGvaX95EPPbrgF" alt=""><figcaption></figcaption></figure>

* In the above example, the element button has an attribute id = change\_button, which will used to identify that particular element.

### 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 <a href="#the-apxor-language" id="the-apxor-language"></a>

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

```javascript
format(
  "Hello {}. We are exicted to give you {} reward points. You can see these points in Rewards section",
  UserName,
  toInt(RewardPoints)
);
```

* Conditional Dynamic Text

```javascript
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

```javascript
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](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# iOS SDK (Swift UI)

#### Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.apple.com/documentation/appstoreconnectapi/bundle-ids)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](/getting-started-with-apxor/api-guides/ios))

{% hint style="info" %}
**Note**

If you are already using a separate analytics class where you are sending events to different platforms from a single place it is much faster to use our tracking guide to complete event logging to setup triggers and track goals.

In case you are logging events to third parties after each interaction, please use our [Third party API guide](broken://pages/6mI0HCleo5SS08RVwKwr) to migrate all the events that you are sending to one of the supported third parties as listed in the guide.
{% endhint %}

## Getting started with Apxor iOS

Apxor provides you easy to use plugins for your Actions. They are:

<table><thead><tr><th width="206.33333333333331">Plugin Name</th><th width="253">Description</th><th>Example</th></tr></thead><tbody><tr><td>Apxor-Core</td><td>The Core Plugin is responsible for the basic event tracking</td><td>How many of my users have clicked on the cart icon after showing them a nudge Sample Event : 'ViewCart'</td></tr><tr><td>APXSurveyPlugin</td><td>This Plugin helps you create contextual surveys to capture your users' feedback, ratings, etc.</td><td>An NPS survey that would ask the user to rate the app experience on a scale of 1-10.</td></tr><tr><td>APXRTAPlugin</td><td>This Plugin helps you create real time actions.</td><td>Show a tooltip on the cart icon with messaging "Tap here to view items"</td></tr><tr><td>APXWYSIWYGPlugin</td><td>The WYSIWYG Plugin allows you to preview your configured actions onto your device in real time</td><td>Casting your mobile screen to the dashboard and selecting the hamburger icon</td></tr><tr><td>APXPushPlugin</td><td>The Push Plugin allows you to track uninstalls and real-time serve/pause the nudges, while the app is opened</td><td>Show a campaign to users who land on the home screen and add an item to the cart.</td></tr></tbody></table>

[Check here for the latest release notes](/getting-started-with-apxor/release-notes#ios).

## Adding Apxor SDK to your project

* Install **CocoaPods**, if you don't already have it. CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over 95 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly. If you don't want to use CocoaPods, you can install ApxorSDK [manually](broken://pages/bhR8Q35Ngc3SXVRHpxul).
* If this is your first pod, run **`pod init`**. Add the following to the corresponding target in your Podfile and run **`pod install`**.

```
use_frameworks!
pod 'Apxor-Core', '2.10.43'
pod 'Apxor-CE', '1.05.31'
pod 'Apxor-Push', '1.01.04'
pod 'Apxor-RTA', '1.09.54'
pod 'Apxor-WYSIWYG', '1.02.74'
pod 'Apxor-Survey', '1.04.25'
pod 'Apxor-SwiftUI', '1.01.01'
```

## Initialize Apxor iOS SDK

### Auto initialize SDK (Recommended)

* To Auto initialize SDK (Recommended), add the following inside your **`application`** plist file.
* Open your application's **Info.plist** as source code.

<figure><img src="/files/A2eDZBOplAFoGRpOqnRa" alt=""><figcaption></figcaption></figure>

* Copy paste the below piece of code, to create an entry for ApxorSDK.

```
<key>Apxor</key>
<dict>
    <key>Core</key>
    <string>YOUR_APP_ID</string>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

### Manually initialize SDK (Not Recommended)

* To manually initialize SDK, call **`ApxorSDK.initialize`** method in your **`Application`** class

```
//...
#import "ApxorSDK/ApxorSDK.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [ApxorSDK initializeApxorWithID:@"<YOUR_APP_ID>"];
    // ... your code
}
```

* And open your application's **Info.plist** as source code.

<figure><img src="/files/A2eDZBOplAFoGRpOqnRa" alt=""><figcaption></figcaption></figure>

* Copy paste the below piece of code, to create an entry for ApxorSDK.

```
<key>Apxor</key>
<dict>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

{% hint style="info" %}
**Note**

To get your app ID, please email us at <mark style="color:blue;">**<contact@apxor.com>**</mark>
{% endhint %}

### Initialize Apxor SwiftUI SDK

```swift
import APXSwiftUIPlugin

ContentView()
    .onAppear {
    initializeApxorSwiftUISDK(status: true)
}

```

{% hint style="info" %}
**Note**

To get your app ID, please email us at <mark style="color:blue;">**<contact@apxor.com>**</mark>
{% endhint %}

## Configuring IDs for View (Mandatory for inlines)

```swift
import APXSwiftUIPlugin

Text("Hello, world!")
    .APXLabel(viewId: "text", screen: "ScreenName")
```

## Configuring Test Device

* First, you need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.
* If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

### Configure URL Scheme

* To configure URL scheme, goto your project settings, select **`Targets`**. Click on the **`Info`** tab.
* Select the **`URL Types`**, and click on the **`+`** button to add a new URL Scheme.
* Add a new URL Scheme with your **`bundle identifier`** as the value.
* Your bundle identifer will be in the format, **`com.xxxx.xxxx`**
* Use the image below for reference.

<figure><img src="/files/h0DXDpIUwnWJcE5UUtIf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your **bundle identifier** that was provided in the dashboard while registering with us. Also, the app must have same **bundle identifier.**
{% endhint %}

### Handling the deep link

```swift
@main
struct YourApplication: App {
    var body: some Scene {
        return WindowGroup {
            TabView {
                YourView().tabItem {
                    Image("Icon")
                    Text("Text")
                }
            }
            .onOpenURL { urlString in
                if(urlString.absoluteString.contains("add-test-device")) {
                    ApxorSDK .handleDeeplink(urlString)
                }
            }
        }
    }
```

## Log Screens using the following api in Swift UI

```swift
ApxorSDK.logScreen(withName: "screen_name");
```

## Configuring Push Notifications

* To use the push notifications feature, make sure the following lines exist in your application plist file under Apxor section.

```
<key>APXPushPlugin</key>
<true/>
```

* To configure iOS Push notification via Apxor dashboard, you'd need to upload APNs Auth Key file along with it's ID (key ID), your Team ID, and your application's Bundle ID.
* The APNs Auth Key is the best way to configure pushes, as you don't need to regenerate a certificate every year and also, this key can be used to configure Push notifications to sever of your applications (under the same apple developer account)
* Things required to configure iOS Push notification:
* Auth Key file
  * Key ID (usuallly the name of the Auth Key file)
  * Team ID (the 10 digit alphanumeric key)
  * Your app’s bundle ID (in the format com.abc.xyz)
  * See here on how to get these, Push notifications
* Once you get those details, add the below code in your application's **`AppDelegate`** file in the **`application`** **`didRegisterForRemoteNotificationsWithDeviceToken`** function.

```swift
import APXPushPlugin

let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
APXPushPlugin.setPushDeviceToken(token)
```

```objectivec
[APXPushPlugin setPushDeviceToken:token];
```

* The token can be passed in either the **`NSData`** or **`NSString`** format

<figure><img src="/files/ar6RPB8we81YamczxL27" alt=""><figcaption></figcaption></figure>

* If you haven't already used the code to Ask User for notifications permission, add the following function in your **`AppDelegate`** file.

```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  // your existing code ...

  registerForPushNotifications()

  // ...
}

func registerForPushNotifications() {
  UNUserNotificationCenter.current()
    .requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] granted, error in
      print("Permission granted: \(granted)")
      guard granted else { return }
      self?.getNotificationSettings()
    }
}

func getNotificationSettings() {
  UNUserNotificationCenter.current().getNotificationSettings { settings in
    print("Notification settings: \(settings)")
    guard settings.authorizationStatus == .authorized else { return }
    DispatchQueue.main.async {
      UIApplication.shared.registerForRemoteNotifications()
    }
  }
}
```

## Ensuring Apxor SDK is initialized successfully

* Lookout for the following log

<figure><img src="/files/lZ7MDzf7ZBl4IbnUyCRW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/jNo4ltENh343LgxdAxyz" alt=""><figcaption></figcaption></figure>

[Click here for guide](/getting-started-with-apxor/api-guides/ios) to log user properties, events and event properties.


# Web npm based

### Apxor Web SDK Integration

[Check here the latest release notes.](/getting-started-with-apxor/release-notes#web)

### Add and Initialize Apxor SDK and Plugins <a href="#initialize-plugins" id="initialize-plugins"></a>

You can find the description and default values for Initialization options [here](/getting-started-with-apxor/api-guides/web#initialization-options)

* Run the following command in your terminal to add Apxor SDK and plugins into your Website

```bash
npm install --save apxor apxor-qe apxor-rtm
```

* Add the following import statements in application root component or page to make sure that these two packages will be bundled when you build your Website

```javascript
import Apxor from "apxor"; //ES6
import CE from "apxor-qe";
import ApxorRTM from "apxor-rtm";
```

* Add the following values in `Initialization option's` `plugin` and `deps` array

```javascript
Apxor.init("YOUR_SITE_ID", {
  // ...
  plugins: ["ApxorRTM"],
  deps: [ApxorRTM, CE],
  version: "<YOUR_WEBSITE_VERSION>", // Optional (If provided, use semantic version eg. "1.4.4")
  // ...
});
```

{% hint style="info" %}
**Note**

Contact <support@apxor.com> to get your unique SITE\_ID
{% endhint %}

### [Tracking Events and Pages](/getting-started-with-apxor/sdk/web-npm-based/tracking-events-and-pages-for-web) <a href="#api-guide" id="api-guide"></a>

## Add-Ons

### Initializing the Apxor SDK

To start tracking with the Apxor SDK, you must first initialize it with your project token. To initialize the SDK,

```javascript
import Apxor from "apxor"; // ES6

Apxor.init("YOUR_SITE_ID", {
  // Initialization options
});
```

#### Initialization options <a href="#initialization-options" id="initialization-options"></a>

* **honorDNT**: *boolean* \[false]

  If this flag is set to `TRUE` and users enable the `doNotTrack` in their browser settings, the SDK won't be initialized. Default Value is `FALSE`
* **idle\_time\_out**: *number(seconds)* \[3600]

  Tells SDK that when to create new session when users are idle for the configured amount of time. Default value is `3600 seconds (1 hour)`
* **plugins**: \[]

  Indicates what plugins needs to be initialized when SDK initializes. Default value is `[]`
* **deps**: \[]

  To make sure the packages to be bundled when you build your application. Default value is `[]`
* **version**: *string* \[ALL]

  Helps you to undestand the events based on a specific version that you set. Default value is `ALL`

> Note:
>
> Contact <support@apxor.com> to get your unique SITE\_ID

***

### Identifying Users <a href="#userid" id="userid"></a>

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 recognize your users :

```javascript
Apxor.setUserId(String);
```

Example:

```javascript
Apxor.setUserId("user@example.com");
```

***

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### App Events <a href="#app-events" id="app-events"></a>

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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 behavior or measure your goals as specified above.

Here is how we track app events:

```javascript
Apxor.logEvent(eventName, eventProperties, forceReport);
```

Example:

```javascript
Apxor.logEvent("ADD_TO_CART", {
  userId: "user@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

#### Immediate Reporting of an event <a href="#immediate-reporting-of-an-event" id="immediate-reporting-of-an-event"></a>

forceReport is an optional parameter with default value false sent to Apxor.logEvent API. Send forceReport as true if the event has to be immediately reported to Apxor. Use it only in specific cases. For example if the event has to be logged just before the browser refresh, use the forceReport flag.

```javascript
Apxor.logEvent(
  "BEFORE_REFRESH",
  {
    userId: "user@example.com",
    value: 123,
  },
  true
);
```

### Client Events <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

> Example:
>
> Soft back button, user reaching end of page, etc.

```javascript
let additionalInfo = {
  page: "/index.html",
};
Apxor.logClientEvent("SoftBackPressed", additionalInfo);
```

### Event tracking via Google Tag Manager (GTM) <a href="#event-tracking-via-google-tag-manager-gtm" id="event-tracking-via-google-tag-manager-gtm"></a>

You can also place the above function as a Custom HTML Tag inside GTM. This Tag can be fired once per event and triggered on the elements where you wish to track website events. The event attributes can be picked up from GTM Data Layer.

![](/files/LJhK7rIziyTsYAaZwZtq)

### User Properties <a href="#user-properties" id="user-properties"></a>

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
Apxor.setUserProperties({
  userProperty1: "value1",
  userProperty2: "value2",
});
```

Example:

```javascript
Apxor.setUserProperties({
  gender: "Male",
  age: 24,
  isPaidUser: true,
  creditsLeft: 250,
});
```

***

### Session Properties <a href="#session-properties" id="session-properties"></a>

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.

Usage:

```javascript
Apxor.setSessionProperties({
  property1: "value1",
  property2: "value2",
});
```

Example:

```javascript
Apxor.setSessionProperties({
  language: "en",
  location: "Hyderabad",
});
```

***

### PageView <a href="#pageview" id="pageview"></a>

You can log a page view event when users navigate through your website

Usage:

```javascript
Apxor.logPageView(String); //String URL pathname
```

Example:

```javascript
Apxor.logPageView("/about.html");
```

***

### Get Client Id <a href="#get-client-id" id="get-client-id"></a>

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID, use below

Example:

```javascript
const clientId = Apxor.getClientId();
```

***

### Start New Session <a href="#start-new-session" id="start-new-session"></a>

Starts new session if there is no active session. If a session is already in progress, it acts as a no-op

```javascript
Apxor.startNewSession();
```

***

### End Session <a href="#end-session" id="end-session"></a>

Ends the active session if any active session in progress. After this call, none of the Apxor APIs work, except **startNewSession()** API.

```javascript
Apxor.endSession();
```

***

### Handle Deeplink Redirection <a href="#handle-deeplink-redirection" id="handle-deeplink-redirection"></a>

For single page websites built with React/Angular/Vue, you need to handle the internal redirection on your own by using the `setRedirectionHandler` method.

#### Example <a href="#example" id="example"></a>

```javascript
Apxor.setRedirectionHandler((url) => {
  // Interpret the URL and redirect user to the specific URL
});
```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)

### Additional features API Guide <a href="#api-guide" id="api-guide"></a>

[Click here for guides](/getting-started-with-apxor/api-guides/web) to log user properties, events and event properties.


# Tracking Events and Pages for Web

## Track Events

Once you have integrated the ApxorSDK into your web application, log into the Apxor dashboard and click on **Track Events** under the Nudges section in the left menu.&#x20;

* On the events listing page, you can see all the events logged, if any.
* Click on the **Start Tracking** CTA in the top right corner to track a new event.

  <figure><img src="/files/miPCphzRpmsQ9myefplx" alt=""><figcaption></figcaption></figure>
* On the pop-up that appears, enter the URL of your integrated web application. Click on **Launch** to open your web application in a new tab. For mWeb events, click on **Generate QR**. Once the QR is displayed on the pop-up, scan using your mobile device and open the link.

  <figure><img src="/files/jEV7zGnR2Q0TStW7OOea" alt=""><figcaption></figcaption></figure>
* In the top center of your web application, you'll see an **Apxor Widget** titled **Track Events**. Click on it and then click on **Start Tracking**.

  <figure><img src="/files/pdUWZBkI7gBkISxtB1DA" alt=""><figcaption></figcaption></figure>
* Click on **Define Event** in the right panel after clicking Start Tracking.

  <figure><img src="/files/mqiE4a3eBwe9R7ud2j7B" alt=""><figcaption></figcaption></figure>
* After clicking **Define Event**, hover over the UI element for which you want to log the event. The UI element will be highlighted with a Red Border as you go over it.

  <figure><img src="/files/uvl0zNv5Ns7kz4pi380Q" alt=""><figcaption></figcaption></figure>
* Click on the **UI element** once you see the Red Border as per your requirement. Press **Esc** if you don't want to select an UI element and exit from the hovering mode.
* Enter the details of the event in the right panel.

  <figure><img src="/files/amfwYR2awsFjUj56xaAR" alt=""><figcaption></figcaption></figure>

  * **Name** (Mandatory): The unique name you want to assign for this event.
    * e.g. ContactUs\_Clicked
  * **Description** (Optional): The description for this event
    * e.g. This event will be logged when the user clicks on the Contact US CTA
  * **Type**: Select when to log this event, **Click, Double Click** or **Right Click**. Select whether the event should be an App Event or a Client Event.
  * **Element Identifier**: The element identifier will be auto-populated.
  * **Pages**:
    * **Only on this Page**: Log this event for the CTA on this page only
    * **For all the Pages**: Log this event for this CTA on all the pages where it is present.
    * **On Pages that match**: Enter the standard URL for the required pages and replace the dynamic part with a star(\*) mark.

Click on **Stop Tracking** in the widget to turn off the widget.

## Track Pages

Once you have integrated the ApxorSDK into your web application, log into the Apxor dashboard and click on **Track Pages** under the Nudges section in the left menu.&#x20;

* On the Page Listing page, you can see all the pages logged, if any.
* Click on the **Start Tracking** CTA in the top right corner to track a new page.

  <figure><img src="/files/UdEPKn5Gb3xE3k4a8cjb" alt=""><figcaption></figcaption></figure>
* On the pop-up that appears, enter the URL of your integrated web application. Click on **Launch** to open your web application in a new tab. For mWeb pages, click on **Generate QR**. Once the QR is displayed on the pop-up, scan using your mobile device and open the link.

  <figure><img src="/files/jEV7zGnR2Q0TStW7OOea" alt=""><figcaption></figcaption></figure>
* In the top center of your web application, you'll see an **Apxor Widget** titled **Track Pages**. Click on it and then click on **Start Tracking**.

  <figure><img src="/files/y4PqRQgySs4aqjLcypM7" alt=""><figcaption></figcaption></figure>
* Click on **Define Page** in the right panel after clicking Start Tracking.

  <figure><img src="/files/u63fLsvgbNqpETWvtdZC" alt=""><figcaption></figcaption></figure>
* After clicking **Define Page**, Enter the details of the event in the right panel.

  <figure><img src="/files/zcNRTW5AQ36GDxuLxI1e" alt=""><figcaption></figcaption></figure>

  * **Name** (Mandatory): The unique name you want to assign for this page.
    * e.g. HomePage\_Launched
  * **Description** (Optional): The description for this page
    * e.g. This page launch event will be logged when the lands on home page
  * **Type**: Select whether the event should be an App Event or a Client Event.
  * **URL**:
    * **Only on this Page**: Log this event for this page only
    * **For all the Pages**: Log this event for all the pages
    * **On Pages that match**: Enter the standard URL for the required pages and replace the dynamic part with a star(\*) mark.

Click on **Stop Tracking** in the widget to turn off the widget.


# Web URL based

### Apxor Web SDK Integration

[Check here the latest release notes.](/getting-started-with-apxor/release-notes#web)

To add Apxor SDK into your Website, add the following scripts to your html files

```html
<script type="text/javascript" defer src="https://unpkg.com/apxor@latest"></script>
<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-qe@latest"
> 
</script>

<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-rtm@latest"
>
</script>
```

#### SDK Initialization <a href="#sdk-initialization" id="sdk-initialization"></a>

To initialize Apxor add the below script

```html
<script>
 
  const _d = new Date();
  (function (a, p, x, o, r) {
    Apxor = a.Apxor || { _q: [], _st: _d };
    [
      "init",
      "setUserId",
      "setUserProperties",
      "setSessionProperties",
      "logPageView",
      "logEvent",
      "logClientEvent",
      "setAppVersion",
      "getClientId",
      "getSessionId",
      "startNewSession",
      "endSession",
      "flattenJSON",
      "setRedirectionHandler",
    ].forEach(function (m) {
      Apxor[m] = function () {
        this._q.push({ m: m, args: arguments });
      };
    });
   })(window, document, "script");
 
 
    Apxor.init(
      "YOUR_SITE_ID",
      {
        idle_time_out: 1800,
        plugins: ["ApxorRTM"],
      },
      
      function success(data) {
        console.log("APXOR SDK Initialized");
      },
      function error() {
        console.log("APXOR SDK not initialized");
      });
   
</script>
```

You can find the description and default values for Initialization options [here](/getting-started-with-apxor/api-guides/web#initialization-options)

> Note:
>
> Contact <support@apxor.com> to get your unique SITE\_ID

### [Tracking Events and Pages](/getting-started-with-apxor/sdk/web-url-based/tracking-events-and-pages-for-web) <a href="#api-guide" id="api-guide"></a>

## Add-Ons

### Initializing the Apxor SDK

To start tracking with the Apxor SDK, you must first initialize it with your project token. To initialize the SDK,

```javascript
import Apxor from "apxor"; // ES6

Apxor.init("YOUR_SITE_ID", {
  // Initialization options
});
```

#### Initialization options <a href="#initialization-options" id="initialization-options"></a>

* **honorDNT**: *boolean* \[false]

  If this flag is set to `TRUE` and users enable the `doNotTrack` in their browser settings, the SDK won't be initialized. Default Value is `FALSE`
* **idle\_time\_out**: *number(seconds)* \[3600]

  Tells SDK that when to create new session when users are idle for the configured amount of time. Default value is `3600 seconds (1 hour)`
* **plugins**: \[]

  Indicates what plugins needs to be initialized when SDK initializes. Default value is `[]`
* **deps**: \[]

  To make sure the packages to be bundled when you build your application. Default value is `[]`
* **version**: *string* \[ALL]

  Helps you to undestand the events based on a specific version that you set. Default value is `ALL`

> Note:
>
> Contact <support@apxor.com> to get your unique SITE\_ID

***

### Identifying Users <a href="#userid" id="userid"></a>

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 recognize your users :

```javascript
Apxor.setUserId(String);
```

Example:

```javascript
Apxor.setUserId("user@example.com");
```

***

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### App Events <a href="#app-events" id="app-events"></a>

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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 behavior or measure your goals as specified above.

Here is how we track app events:

```javascript
Apxor.logEvent(eventName, eventProperties, forceReport);
```

Example:

```javascript
Apxor.logEvent("ADD_TO_CART", {
  userId: "user@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

#### Immediate Reporting of an event <a href="#immediate-reporting-of-an-event" id="immediate-reporting-of-an-event"></a>

forceReport is an optional parameter with default value false sent to Apxor.logEvent API. Send forceReport as true if the event has to be immediately reported to Apxor. Use it only in specific cases. For example if the event has to be logged just before the browser refresh, use the forceReport flag.

```javascript
Apxor.logEvent(
  "BEFORE_REFRESH",
  {
    userId: "user@example.com",
    value: 123,
  },
  true
);
```

### Client Events <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

> Example:
>
> Soft back button, user reaching end of page, etc.

```javascript
let additionalInfo = {
  page: "/index.html",
};
Apxor.logClientEvent("SoftBackPressed", additionalInfo);
```

### Event tracking via Google Tag Manager (GTM) <a href="#event-tracking-via-google-tag-manager-gtm" id="event-tracking-via-google-tag-manager-gtm"></a>

You can also place the above function as a Custom HTML Tag inside GTM. This Tag can be fired once per event and triggered on the elements where you wish to track website events. The event attributes can be picked up from GTM Data Layer.

![](/files/LJhK7rIziyTsYAaZwZtq)

### User Properties <a href="#user-properties" id="user-properties"></a>

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
Apxor.setUserProperties({
  userProperty1: "value1",
  userProperty2: "value2",
});
```

Example:

```javascript
Apxor.setUserProperties({
  gender: "Male",
  age: 24,
  isPaidUser: true,
  creditsLeft: 250,
});
```

***

### Session Properties <a href="#session-properties" id="session-properties"></a>

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.

Usage:

```javascript
Apxor.setSessionProperties({
  property1: "value1",
  property2: "value2",
});
```

Example:

```javascript
Apxor.setSessionProperties({
  language: "en",
  location: "Hyderabad",
});
```

***

### PageView <a href="#pageview" id="pageview"></a>

You can log a page view event when users navigate through your website

Usage:

```javascript
Apxor.logPageView(String); //String URL pathname
```

Example:

```javascript
Apxor.logPageView("/about.html");
```

***

### Get Client Id <a href="#get-client-id" id="get-client-id"></a>

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID, use below

Example:

```javascript
const clientId = Apxor.getClientId();
```

***

### Start New Session <a href="#start-new-session" id="start-new-session"></a>

Starts new session if there is no active session. If a session is already in progress, it acts as a no-op

```javascript
Apxor.startNewSession();
```

***

### End Session <a href="#end-session" id="end-session"></a>

Ends the active session if any active session in progress. After this call, none of the Apxor APIs work, except **startNewSession()** API.

```javascript
Apxor.endSession();
```

***

### Handle Deeplink Redirection <a href="#handle-deeplink-redirection" id="handle-deeplink-redirection"></a>

For single page websites built with React/Angular/Vue, you need to handle the internal redirection on your own by using the `setRedirectionHandler` method.

#### Example <a href="#example" id="example"></a>

```javascript
Apxor.setRedirectionHandler((url) => {
  // Interpret the URL and redirect user to the specific URL
});
```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)

### Additional features API Guide <a href="#api-guide" id="api-guide"></a>

[Click here for guides](/getting-started-with-apxor/api-guides/web) to log user properties, events and event properties.


# Tracking Events and Pages for Web

## Track Events

Once you have integrated the ApxorSDK into your web application, log into the Apxor dashboard and click on **Track Events** under the Nudges section in the left menu.&#x20;

* On the events listing page, you can see all the events logged, if any.
* Click on the **Start Tracking** CTA in the top right corner to track a new event.

  <figure><img src="/files/miPCphzRpmsQ9myefplx" alt=""><figcaption></figcaption></figure>
* On the pop-up that appears, enter the URL of your integrated web application. Click on **Launch** to open your web application in a new tab. For mWeb events, click on **Generate QR**. Once the QR is displayed on the pop-up, scan using your mobile device and open the link.

  <figure><img src="/files/jEV7zGnR2Q0TStW7OOea" alt=""><figcaption></figcaption></figure>
* In the top center of your web application, you'll see an **Apxor Widget** titled **Track Events**. Click on it and then click on **Start Tracking**.

  <figure><img src="/files/pdUWZBkI7gBkISxtB1DA" alt=""><figcaption></figcaption></figure>
* Click on **Define Event** in the right panel after clicking Start Tracking.

  <figure><img src="/files/mqiE4a3eBwe9R7ud2j7B" alt=""><figcaption></figcaption></figure>
* After clicking **Define Event**, hover over the UI element for which you want to log the event. The UI element will be highlighted with a Red Border as you go over it.

  <figure><img src="/files/uvl0zNv5Ns7kz4pi380Q" alt=""><figcaption></figcaption></figure>
* Click on the **UI element** once you see the Red Border as per your requirement. Press **Esc** if you don't want to select an UI element and exit from the hovering mode.
* Enter the details of the event in the right panel.

  <figure><img src="/files/amfwYR2awsFjUj56xaAR" alt=""><figcaption></figcaption></figure>

  * **Name** (Mandatory): The unique name you want to assign for this event.
    * e.g. ContactUs\_Clicked
  * **Description** (Optional): The description for this event
    * e.g. This event will be logged when the user clicks on the Contact US CTA
  * **Type**: Select when to log this event, **Click, Double Click** or **Right Click**. Select whether the event should be an App Event or a Client Event.
  * **Element Identifier**: The element identifier will be auto-populated.
  * **Pages**:
    * **Only on this Page**: Log this event for the CTA on this page only
    * **For all the Pages**: Log this event for this CTA on all the pages where it is present.
    * **On Pages that match**: Enter the standard URL for the required pages and replace the dynamic part with a star(\*) mark.

Click on **Stop Tracking** in the widget to turn off the widget.

## Track Pages

Once you have integrated the ApxorSDK into your web application, log into the Apxor dashboard and click on **Track Pages** under the Nudges section in the left menu.&#x20;

* On the Page Listing page, you can see all the pages logged, if any.
* Click on the **Start Tracking** CTA in the top right corner to track a new page.

  <figure><img src="/files/UdEPKn5Gb3xE3k4a8cjb" alt=""><figcaption></figcaption></figure>
* On the pop-up that appears, enter the URL of your integrated web application. Click on **Launch** to open your web application in a new tab. For mWeb pages, click on **Generate QR**. Once the QR is displayed on the pop-up, scan using your mobile device and open the link.

  <figure><img src="/files/jEV7zGnR2Q0TStW7OOea" alt=""><figcaption></figcaption></figure>
* In the top center of your web application, you'll see an **Apxor Widget** titled **Track Pages**. Click on it and then click on **Start Tracking**.

  <figure><img src="/files/y4PqRQgySs4aqjLcypM7" alt=""><figcaption></figcaption></figure>
* Click on **Define Page** in the right panel after clicking Start Tracking.

  <figure><img src="/files/u63fLsvgbNqpETWvtdZC" alt=""><figcaption></figcaption></figure>
* After clicking **Define Page**, Enter the details of the event in the right panel.

  <figure><img src="/files/zcNRTW5AQ36GDxuLxI1e" alt=""><figcaption></figcaption></figure>

  * **Name** (Mandatory): The unique name you want to assign for this page.
    * e.g. HomePage\_Launched
  * **Description** (Optional): The description for this page
    * e.g. This page launch event will be logged when the lands on home page
  * **Type**: Select whether the event should be an App Event or a Client Event.
  * **URL**:
    * **Only on this Page**: Log this event for this page only
    * **For all the Pages**: Log this event for all the pages
    * **On Pages that match**: Enter the standard URL for the required pages and replace the dynamic part with a star(\*) mark.

Click on **Stop Tracking** in the widget to turn off the widget.


# React Native

## Prerequisites

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.android.com/studio/build/configure-app-module)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](/getting-started-with-apxor/api-guides/react-native))

## React Native Integration

[Check here the latest release notes.](/getting-started-with-apxor/release-notes#react-native)

<details>

<summary>For React Native version 0.60.0 and higher</summary>

Run the following commands

```bash
$ yarn add react-native-apxor-sdk react-native-apxor-rtm-plugin
```

* `react-native-apxor-sdk` is to track events and navigatiocodens
* `react-native-apxor-rtm-plugin` helps to create and display Walkthrough messages

</details>

<details>

<summary>For React Native version 0.59.0 and lower</summary>

Run the following commands

```shell
$ npm install react-native-apxor-sdk react-native-apxor-rtm-plugin --save
```

```shell
$ react-native link react-native-apxor-sdk react-native-apxor-rtm-plugin
```

1. Open `android/app/src/main/java/[...]/MainActivity.java`

   * Add following imports statements at the top of the file

   ```js
     import com.apxor.reactnativesdk.RNApxorSDKPackage;
     import com.apxor.reactnativesdk.RNApxorRTMPackage;
   ```

   ```java
   @Override
   protected List<ReactPackage> getPackages() {
       return Arrays.<ReactPackage>asList(
               new MainReactPackage(),
               ...
               new RNApxorSDKPackage(), <- ApxorSDK Package
               new RNApxorRTMPackage(), <- ApxorSDK RTM Plugin Package
               ...
       );
   }
   ```
2. Append the following lines to `android/settings.gradle`:

   ```groovy
   include ':react-native-apxor-sdk'
   project(':react-native-apxor-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-apxor-sdk/android')
   include ':react-native-apxor-rtm-plugin'
   project(':react-native-apxor-rtm-plugin').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-apxor-rtm-plugin/android')
   ```

</details>

## Android Integration <a href="#android-integration" id="android-integration"></a>

### Step 1: Add Apxor Repository

Add Maven URL in root/project level `build.gradle`

**`Path: <project>/build.graddle` :**

```js
// Top-level build file where you can add configuration options 
// common to all sub-projects/modules.

buildscript {
    allprojects {
        repositories {
            maven {
                url "https://repo.apxor.com/artifactory/list/libs-release-android/"
            }
        }
    }
    // ....
}
```

### Step 2: Add dependencies

Add the following into the build.gradle file in app-level

**`Path: <project>/<app-module>/build.gradle`**:

#### **2.1 ApxorSDK dependencies (mandatory)**

```groovy
dependencies {
//...

    // Event tracking and a must-have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.2.5@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.9@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.7.5@aar'
    implementation 'com.apxor.androidx:surveys:2.3.1@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.5@aar'
    
    // Add the below two dependencies to establish an SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
//...
}
```

#### **2.2 Add exoplayer in your app (optional)**

<details>

<summary>Add exoplayer in your app</summary>

Exoplayer enables you to configure Picture In Picture videos from the Apxor dashboard; if you are already using the exoplayer in your app, this step is not needed; otherwise, add the following dependency in the application  `build.gradle` file. To use video pip templates, this is necessary.

<img src="/files/BMQoL6soL1X6E8GmUgTs" alt="" data-size="original">

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.6\@aar version onwards**</mark>

```gradle
dependencies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.5\@aar and below**</mark>

```gradle
dependencies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

#### **2.3 Enable uninstall tracking for your users (optional)**

<details>

<summary>Enable uninstall tracking for your users</summary>

Apxor uses your Firebase server key to send silent push notifications to track uninstalls and measure the outcomes of your campaign. To enable this, please do the following:

<mark style="background-color:blue;">**For Firebase Version < 22.0.0**</mark>

```gradle
dependencies {
  // Add this to track uninstalls from the Apxor dashboard
  implementation 'com.google.firebase:firebase-messaging:20.1.0'
  implementation('com.apxor.androidx:apxor-android-sdk-push:1.2.8@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

Please handle the notifications like the following:

```gradle
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Creating Notification Channel
        ApxorPushAPI.createNotificationChannel(this.getApplicationContext(), "Apxor", "Apxor", "Apxor");
        if (remoteMessage.getFrom().equals(YOUR_FCM_SENDER_ID)) {
            // Push Notification receiver with your Sender ID
        } else {
            // Check if Push Notification received from Apxor
            if (ApxorPushAPI.isApxorNotification(remoteMessage)) {
                ApxorPushAPI.handleNotification(remoteMessage, getApplicationContext());
            } else {
                // Silent or Data push notification, which you can send through Apxor dashboard
            }
        }
    }
}
```

<mark style="background-color:blue;">**For Firebase Version >= 22.0.0**</mark>

```gradle
dependencies {
  // Add this to track uninstalls from the Apxor dashboard
  implementation('com.apxor.androidx:apxor-android-sdk-push-v2:1.3.1@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

[Read here](/getting-started-with-apxor/firebase-credentials-optional) on how to get your Firebase sender ID and also FCM server key to share it with apxor to configure uninstall tracking.

</details>

After completing the expandable section, integrate Apxor Push with @react-native-firebase

Add the following block wherever you have `AppRegistry.registerComponent(appName, () => App);`. Ideally, it's located in your `src/index.js` or `src/index.tsx`.

```javascript
import messaging from "@react-native-firebase/messaging";
import RNApxorSDK from "react-native-apxor-sdk";

messaging().setBackgroundMessageHandler(async (remoteMessage) => {
  if (!RNApxorSDK.handlePushNotification(remoteMessage)) {
    // To ignore silent push notifications
    if (!remoteMessage.data && !remoteMessage.notification) {
      return;
    }
    console.log("You need to handle this push notification");
  }
});

AppRegistry.registerComponent(appName, () => App);
```

### Step 3: Add the following in proguard-rules.pro

{% hint style="info" %}
**Note**

If you use proguard to obfuscate the classes, you have to add the following to ignore obfuscation for Apxor SDK classes
{% endhint %}

Configure the below rules in your `proguard-rules.pro` file

**`Path: <project>/<app-module>/gradle.properties`**:

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

{% hint style="info" %}
**Note:**

If you use `androidx` libraries, add the following property in `gradle.properties` file

```properties
android.enableJetifier = true
```

{% endhint %}

### Step 4: Disable Dexing Artifact Transformation

{% hint style="info" %}
**Note**

In Android Gradle Plugin 3.5.0, we use Gradle artefact transforms for desugaring and dexing, enabling greater parallelism and caching. This process depends on libraries having accurate Maven information since dependencies specified in POM files are used to set up the desugaring classpath. If we encounter issues with missing dependencies during desugaring, it's necessary to disable parallel transformation to facilitate the process by adding the following property:
{% endhint %}

Add the following to `gradle.properties` file

**`Path: <project>/<app-module>/gradle.properties`**:

```java
android.enableDexingArtifactTransform = false
```

### Step 5: Initialize Apxor Android SDK <a href="#initialize-apxor-android-sdk" id="initialize-apxor-android-sdk"></a>

* Add following `meta-data` tag inside your `application` tag in your `AndroidManifest.xml` file

  ```xml
  <application>
      <!-- You must replace your app-id in android:value attribute -->
      <meta-data android:name="APXOR_APP_ID" android:value="APP_ID" />
  </application>
  ```

{% hint style="info" %}
Click here to [Add New App](/getting-started-with-apxor/adding-a-new-app) and [how to get the app id](/getting-started-with-apxor/adding-a-new-app#step-5-copy-the-application-identifier)
{% endhint %}

### You are all set: Verify your SDK integration <a href="#ensuring-apxorsdk-is-initialised-successfully" id="ensuring-apxorsdk-is-initialised-successfully"></a>

We have to verify for two things as follows :

#### **SDK Initialization**

On running your android project lookout for the following log in logcat :

```java
ApxorSDK(v3**) successfully initialized for: APP_ID
```

<figure><img src="/files/7hLMlroJFuHWhmh7schm" alt=""><figcaption></figcaption></figure>

#### **Plugin Initialization**

By default, only error logs are enabled. To see debug logs for plugin initialization and to confirm tracking event triggers, user properties. Please run the below command in terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="/files/sRoXlvsMhggAWYRwLrnC" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Apxor uploads data only when the app is minimized to the background. If you are running from Android Studio (emulators or devices), do not stop the app, just press on the "home" button in order for data to be uploaded.
{% endhint %}

## iOS Integration <a href="#ios-integration" id="ios-integration"></a>

### Step 1: Initialize Apxor iOS SDK

<details>

<summary>Auto initialize SDK (Recommended)</summary>

1. Add the following inside your **`application`** plist file.
2. Open your application's **Info.plist** as source code.

<img src="/files/A2eDZBOplAFoGRpOqnRa" alt="" data-size="original">

3. Copy paste the below piece of code, to create an entry for ApxorSDK

```
<key>Apxor</key>
<dict>
    <key>Core</key>
    <string>YOUR_APP_ID</string>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
    // other plugins which you are using
</dict>
```

4. To add the **APXWYSIWYGPlugin**, add the following to your application's `.podspec` file:

```
pod 'Apxor-WYSIWYG', '1.02.73'
```

</details>

{% hint style="info" %}
**Note**

* If you are unable to find our plugins in your pods, then do<mark style="background-color:orange;">**`pod update`**</mark>
  {% endhint %}

<details>

<summary>Manually initialize SDK</summary>

1. Call **`ApxorSDK.initialize`** method in your **`Application`** class

```
//...
#import "ApxorSDK/ApxorSDK.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [ApxorSDK initializeApxorWithID:@"<YOUR_APP_ID>"];
    // ... your code
}
```

2. Open your application's **Info.plist** as source code.

<img src="/files/A2eDZBOplAFoGRpOqnRa" alt="" data-size="original">

3. Copy paste the below piece of code, to create an entry for ApxorSDK.

```
<key>Apxor</key>
<dict>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
    // other plugins which you are using
</dict>
```

</details>

{% hint style="info" %}
**Note**

To get your app ID, please email us at <mark style="color:blue;">**<contact@apxor.com>**</mark> or contact your assigned CSM
{% endhint %}

## Configuring Test Device

* First, you need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.
* If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

### Configure URL Scheme

* To configure URL scheme, go to your project settings, select **`Targets`**. Click on the **`Info`** tab.
* Select the **`URL Types`**, and click on the **`+`** button to add a new URL Scheme.
* Add a new URL Scheme with your **`bundle identifier`** as the value.
* Your bundle identifier will be in the format, **`com.xxxx.xxxx`**
* Use the image below for reference.

<figure><img src="/files/h0DXDpIUwnWJcE5UUtIf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your **bundle identifier** that was provided in the dashboard while registering with us. Also, the app must have same **bundle identifier.**
{% endhint %}

### Handling the deep link

<details>

<summary>Using AppDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`AppDelegate`** file, in the function **`application(_:open:options:)`**, add the following code at the beginning,

```swift
// ObjC
NSString *urlStr = url.absoluteString;
if ([urlStr containsString:@"add-test-device"]) {
  [ApxorSDK handleDeeplink:url];
}
```

```objectivec
// Swift
/*
  Apxor's code to handle deeplinks
  */
let urlStr = url.absoluteString
if (urlStr.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url)
}
```

* This will ensure the Apxor specific deep links are handle by our SDK.

</details>

<details>

<summary>Using SceneDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`SceneDelegate`** file, add the following code at the beginning,

```objectivec
// ObjC
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
  for(UIOpenURLContext *x in URLContexts) {
    NSURL *url = x.URL;
    if([[url absoluteString] containsString:@"add-test-device"])
    {
      [ApxorSDK handleDeeplink:url];
    }
    break;
  }
}
```

```swift
// Swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  let url = URLContexts.first?.url
  let urlStr = url?.absoluteString
  if (urlStr!.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url!)
  }
}
```

</details>

### You are all set: Verify your SDK Integration

Lookout for the following log

<figure><img src="/files/lZ7MDzf7ZBl4IbnUyCRW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/jNo4ltENh343LgxdAxyz" alt=""><figcaption></figcaption></figure>

## Add-Ons

### APIs

Add the following import statement in every component where you use Apxor APIs

```java
import RNApxorSDK from "react-native-apxor-sdk";
```

### Identifying Users <a href="#userid" id="userid"></a>

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 recognize your users :

```javascript
// Syntax
RNApxorSDK.setUserIdentifier("STRING");

// Example
RNApxorSDK.setUserIdentifier("<unique_user_id>");
```

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 :

```javascript
// Syntax
RNApxorSDK.logAppEvent(event_name, properties);

// Example
RNApxorSDK.logAppEvent("ADD_TO_CART", {
  userId: "johnwick@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

### User Attributes <a href="#user-attributes" id="user-attributes"></a>

#### Personalizing and targetting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
// Syntax
RNApxorSDK.setUserCustomInfo(properties);

// Example
RNApxorSDK.setUserCustomInfo({
  Age: 10,
  Name: "John Wick",
});
```

### Client Events[**​**](http://localhost:3000/docs/android-sdk/Tracking#client-events) <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

```javascript
// Syntax
RNApxorSDK.logClientEvent(event_name, properties);

// Example
RNApxorSDK.logClientEvent("ADD_TO_CART", {
  userId: "johnwick@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

### Handle custom redirection using Key-Value pairs <a href="#handle-custom-redirection-using-key-value-pairs" id="handle-custom-redirection-using-key-value-pairs"></a>

If your app wants to redirect users based on simple key-value pairs instead using Deeplink URLs or Activity, you can follow below approach

```java
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 Screen

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

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

```java
RNApxorSDK.trackScreen("HomeScreen");
```

### Track Navigation <a href="#track-navigation" id="track-navigation"></a>

**If you are already using a navigation library like&#x20;**<mark style="background-color:yellow;">**`@react-navigation`**</mark>**,  please follow below mentioned steps for Apxor SDK to automatically track screen navigation**

```typescript
import { useNavigationContainerRef } from "@react-navigation/native"

const navigationRef = useNavigationContainerRef()

return (
  <NavigationContainer
    ref={navigationRef}
    onReady={() => {
      const currentRoute = navigationRef?.current?.getCurrentRoute()
      if (currentRoute) {
        RNApxorSDK.trackScreen(currentRoute.name)
      }
    }}
    onStateChange={() => {
      const currentRoute = navigationRef?.current?.getCurrentRoute()
      if (currentRoute) {
        RNApxorSDK.trackScreen(currentRoute.name)
      }
    }}
  >
   // your screens and navigators
  </NavigationContainer>
)

```

{% hint style="info" %}
**Note**

1. You will need it on both `onReady` and `onStateChange` as the SDK needs to log navigation events on the initial app launch and also on futher navigations between screens.
2. The `NavigationContainer` need **not** be straight from `@react-navigation`. It can be from any 3rd party wrapper around `NavigationContainer` (like BugSnag)
   {% endhint %}

**Otherwise use the following API to track navigations on every screen/route change**

```java
// Syntax
RNApxorSDK.logNavigationEvent(screen_name);

// Example
RNApxorSDK.logNavigationEvent("LoginScreen");
```

#### Handle Deeplinks <a href="#handle-deeplinks" id="handle-deeplinks"></a>

Follow the instructions given in [here](https://reactnative.dev/docs/linking) to enable deeplinks in your application.

Whenever Apxor React Native SDK sends the deeplink URL to the app, the following callback will be executed and you have to interpret the URL and navigate the user to the necessary page or tab.

Add the following code snippet in your root component to handle deeplink URLs

```javascript
import { Linking } from "react-native";

function YourRootComponent(props) {
  // Use `componentDidMount` for Class components
  useEffect(() => {
    Linking.addEventListener("url", (event) => {
      const { url } = event;

      // Your custom function which interprets the URL
      // and redirect users to the necessary page or tab
      handleDeeplinkURL(url);
    });
  }, []);
}
```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# Cordova

## Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.android.com/studio/build/configure-app-module)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](/getting-started-with-apxor/api-guides/cordova))

## Cordova Integration

### Step 1: Getting started

Run the following command in your terminal from the project folder. This command will fetch the apxor plugins for you.

```bash
cordova plugin add cordova-plugin-apxor-sdk
```

### Step 2: Handle deeplink redirection

Use `registerDeeplinkHandler` to listen on deeplink redirection from Apxor SDK and handle redirection logic (including external redirection) within application logic as follows

```dart
ApxorSDK.registerDeeplinkHandler((deeplinkUrl) => {
  // Whenever redirection happens from InApp notification buttons,
  // this callback will be executed.

  switch (deeplinkUrl) {
    case "scheme://about":
      // Redirect to About Component
      break;
    default:
      // Check if it's external URL and redirect to Browser
      break;
    // and so on
  }
});
```

## Android Integration

### Step 1: Add dependencies

Add plugin dependencies to your application `build.gradle` file

**`Path: <project>/<app-module>/build.gradle`**:

[Check the latest release notes here.](/getting-started-with-apxor/release-notes#android)

#### 1.1 ApxorSDK dependencies (mandatory)

```groovy
dependencies {
//...

    // Event tracking and a must-have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.2.5@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.9@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.7.5@aar'
    implementation 'com.apxor.androidx:surveys:2.3.0@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.5@aar'
    
    // Add the below two dependencies to establish an SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
//...
}
```

#### 1.2 Add exoplayer in your app (optional)

<details>

<summary>Add exoplayer in your app</summary>

Exoplayer enables you to configure Picture In Picture videos from the Apxor dashboard; if you are already using the exoplayer in your app, this step is not needed; otherwise, add the following dependency in the application  `build.gradle` file. To use video pip templates, this is necessary.

<img src="/files/BMQoL6soL1X6E8GmUgTs" alt="" data-size="original">

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.6\@aar version onwards**</mark>

```gradle
dependencies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

<mark style="background-color:blue;">**For com.apxor.androidx:apxor-android-sdk-rtm:2.3.5\@aar and below**</mark>

```gradle
dependencies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

### Step 2: Add Proguard Rules <a href="#android-integration" id="android-integration"></a>

{% hint style="info" %}
**Note**

If you use proguard to obfuscate the classes, you have to add the following to ignore obfuscation for Apxor SDK classes
{% endhint %}

Configure the below rules in your `proguard-rules.pro` file

**`Path: <project>/<app-module>/gradle.properties`**:

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

{% hint style="info" %}

**Note:**

If you use `androidx` libraries, add the following property in `gradle.properties` file

```properties
android.enableJetifier = true
```

{% endhint %}

### Step 2: Initialize Apxor Android SDK <a href="#initialize-apxor-android-sdk" id="initialize-apxor-android-sdk"></a>

* To **Auto initialize** SDK (Recommended), add following `meta-data` tag inside your `application` tag in your `AndroidManifest.xml` file

  ```xml
  <application>
      <!-- You must replace your app in android:value attribute -->
      <meta-data android:name="APXOR_APP_ID" android:value="APP_ID" />
  </application>
  ```
* To manually initialize SDK, call `ApxorSDK.initialize` method in your `Application` class

  ```java
  //...
  import com.apxor.androidsdk.core.ApxorSDK;

  public class MyApplication extends Application {
      @Override
      public void onCreate() {
          // ...
          ApxorSDK.initialize(<YOUR_APP_ID>, this.getApplicationContext());
      }
  }
  ```

{% hint style="info" %}
Click here to [Add New App](/getting-started-with-apxor/adding-a-new-app) and [how to get the app id](/getting-started-with-apxor/adding-a-new-app#step-5-copy-the-application-identifier)
{% endhint %}

### Step 3: Enable uninstall tracking for your users \[Optional] <a href="#to-track-uninstalls" id="to-track-uninstalls"></a>

{% hint style="info" %}
**Note**

* If you would like to track uninstalls, you must include `apxor-android-sdk-push` dependency in `app/build.gradle` file and corresponding JSON object in `assets/plugins.json` file
* Apxor sends silent push notifications to track uninstalls. Please make sure you handle push notifications which will be sent with your SENDER\_ID and ignore all notifications other than your SENDER\_ID
  {% endhint %}

Apxor uses your firebase server key to send silent push notifications to track uninstalls in order to measure outcomes of your campaign. To enable this please do the following :

**Path : `app/build.gradle`**

<details>

<summary><em><strong><code>firebase-messaging</code></strong><strong> </strong><strong>version >=</strong><strong> </strong><strong><code>22.0.0</code></strong></em></summary>

* Add the following dependency in your `app/build.gradle`

  ```groovy
  dependencies {
    // Add this to track uninstalls and send push notifications from Apxor dashboard
    implementation('com.apxor.androidx:apxor-android-sdk-push-v2:1.2.7@aar') {
      exclude group: 'com.google.firebase'
    }
  }
  ```
* Add the following in `plugins.json` file

  ```json
  {
    "plugins": [
      {
        "name": "push",
        "class": "com.apxor.androidsdk.plugins.push.v2.PushPlugin"
      }
    ]
  }
  ```

</details>

<details>

<summary><em><strong><code>firebase-messaging</code></strong><strong> </strong><strong>version</strong><strong> </strong><strong><code>&#x3C; 22.0.0</code></strong></em></summary>

* Add the following dependency in your `app/build.gradle`

  ```groovy
  dependencies {
    // Add this to track uninstalls and send push notifications from Apxor dashboard
    implementation('com.apxor.androidx:apxor-android-sdk-push:1.2.7@aar') {
      exclude group: 'com.google.firebase'
    }
  }
  ```
* If you are not using `FirebaseMessagingService`, you can skip this step. Otherwise, add the following

  ```java
  public class MyFirebaseMessagingService extends FirebaseMessagingService {
      @Override
      public void onMessageReceived(RemoteMessage remoteMessage) {
          // Creating Notification Channel
          ApxorPushAPI.createNotificationChannel(this.getApplicationContext(), "Apxor", "Apxor", "Apxor");
          if (remoteMessage.getFrom().equals(YOUR_FCM_SENDER_ID)) {
              // Push Notification receiver with your Sender Id
          } else {
              // Check if Push Notification received from Apxor
              if (ApxorPushAPI.isApxorNotification(remoteMessage)) {
                  ApxorPushAPI.handleNotification(remoteMessage, getApplicationContext());
              } else {
                  // Silent or Data push notification which you can send through Apxor dashboard
              }
          }
      }
  }
  ```
* Add the following in `plugins.json` file

  ```json
  {
    "plugins": [
      {
        "name": "push",
        "class": "com.apxor.androidsdk.plugins.push.PushPlugin"
      }
    ]
  }
  ```

[Read here](/getting-started-with-apxor/firebase-credentials-optional) on how to get your firebase sender ID and also FCM server key to share it with apxor to configure uninstall tracking.

</details>

### Step 4: To view tooltips, Coachmark and Badges <a href="#to-view-tooltips" id="to-view-tooltips"></a>

{% hint style="info" %}
**Note**

To anchor a tooltip or coachmark or badge to any UI element, this step is mandatory.

If you will only use In-app messages, this step can be skipped.
{% endhint %}

In your `MainActivity` `onCreate` method you must set the tag for the `WebView` as follows to view the tooltips.

```java
public class MainActivity extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Your logic goes here

        appView.getView().setTag("MyWebView");
    }
}
```

### Step 5: Ensuring ApxorSDK is initialised successfully <a href="#ensuring-apxorsdk-is-initialised-successfully" id="ensuring-apxorsdk-is-initialised-successfully"></a>

We have to verify for two things as follows :

**SDK Initialisation**

On running your android project lookout for the following log in logcat :

```java
ApxorSDK(v3**) successfully initialized for: APP_ID
```

<figure><img src="/files/7hLMlroJFuHWhmh7schm" alt=""><figcaption></figcaption></figure>

**Plugin Initialisation**

By default, only error logs are enabled. To see debug logs for plugin initialisation and to confirm tracking event triggers, user properties. Please run the below command in terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="/files/sRoXlvsMhggAWYRwLrnC" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Apxor uploads data only when the app is minimized to the background. If you are running from Android Studio (emulators or devices), do not stop the app, just press on the "home" button in order for data to be uploaded.
{% endhint %}

### Step 6: Log data to set up triggers and measure goals

Now as we are done with basic integration, we can go ahead to setup event triggers, capture data for targeting and to personalize messaging.

[Please follow the guide here](/getting-started-with-apxor/api-guides/cordova) to log user properties, events and event properties.

## iOS integration <a href="#ios-integration" id="ios-integration"></a>

### Initialize Apxor iOS SDK <a href="#initialize-apxor-ios-sdk" id="initialize-apxor-ios-sdk"></a>

* To **Auto initialize** SDK, add the following inside your `application` plist file.
* Open your application's **Info.plist** as source code.

  <figure><img src="https://docs.apxor.com/docs/assets/SDKs/open_as_source_code.png" alt=""><figcaption></figcaption></figure>
* Copy paste the below piece of code, to create an entry for ApxorSDK.

```xml
  <key>Apxor</key>
  <dict>
      <key>Core</key>
      <string>{YOUR_APP_ID}</string>
      <key>APXSurveyPlugin</key>
      <true/>
      <key>APXRTAPlugin</key>
      <true/>
      <key>APXWYSIWYGPlugin</key>
      <true/>
  </dict>
```

### Configuring Test Device

* First, you need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.
* If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

### Configuring URL Scheme

* To configure URL scheme, goto your project settings, select **`Targets`**. Click on the **`Info`** tab.
* Select the **`URL Types`**, and click on the **`+`** button to add a new URL Scheme.
* Add a new URL Scheme with your **`bundle identifier`** as the value.
* Your bundle identifer will be in the format, **`com.xxxx.xxxx`**
* Use the image below for reference.

<figure><img src="/files/h0DXDpIUwnWJcE5UUtIf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your **bundle identifier** that was provided in the dashboard while registering with us. Also, the app must have same **bundle identifier.**
{% endhint %}

### Handling the deep link

<details>

<summary>Using AppDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`AppDelegate`** file, in the function **`application(_:open:options:)`**, add the following code at the beginning,

```swift
// ObjC
NSString *urlStr = url.absoluteString;
if ([urlStr containsString:@"add-test-device"]) {
  [ApxorSDK handleDeeplink:url];
}
```

```objectivec
// Swift
/*
  Apxor's code to handle deeplinks
  */
let urlStr = url.absoluteString
if (urlStr.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url)
}
```

* This will ensure the Apxor specific deep links are handle by our SDK.

</details>

<details>

<summary>Using SceneDelegate</summary>

* You'd need to enable Apxor to handle Apxor specific deeplinks.
* In your application's **`SceneDelegate`** file, add the following code at the beginning,

```objectivec
// ObjC
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
  for(UIOpenURLContext *x in URLContexts) {
    NSURL *url = x.URL;
    if([[url absoluteString] containsString:@"add-test-device"])
    {
      [ApxorSDK handleDeeplink:url];
    }
    break;
  }
}
```

```swift
// Swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  let url = URLContexts.first?.url
  let urlStr = url?.absoluteString
  if (urlStr!.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url!)
  }
}
```

</details>

### To show tooltips <a href="#to-show-tooltips" id="to-show-tooltips"></a>

* In your `MainViewController` (the ViewController extending the `CDVViewController`) `init` method you must set the tag for the `WebView` as follows to view the tooltips.

```objc
  // ...
  if (self.webView != null) {
    [self.webView setTag:123];
    NSLog(@"My webview is: %@", self.webView);
  } else {
    NSLog(@"Error in setting TAG to webview");
  }
  // ...
```

{% hint style="info" %}
**Note**

Ensure your webview isn't null and the TAG is set correctly.
{% endhint %}

* You have to init the APXWKScriptHandler and call registerEventsAndScripts method to make sure any the calls made in the webview are taken care by the native SDK. It's as follows,

  * If you don't already have a bridging header, [checkout how to create a bridging header.](https://developer.apple.com/documentation/swift/importing-objective-c-into-swift)
  * Add the following in the bridging header file.

  ```dart
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ```

  * Now, add the following to the init method of your webview

  ```dart
  let apxHandler: APXWKScriptHandler = APXWKScriptHandler.init(handlerFor: webView)
  apxHandler.registerEventsAndScripts()
  ```
* Here's how to do the same thing in objective-C.

  * Make sure there's a proper WKUserContentController set to your WkWebView, if not please init it and use that config to initialise your WKWebView.

  ```dart
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ```

  ```ObjectiveC
  ...
  // add apxor's script handler
  APXWKScriptHandler *scriptHandler = [[APXWKScriptHandler alloc] initWithHandlerForWebView:_webView];
  [scriptHandler registerEventsAndScripts];
  ```

### Ensuring ApxoriOSSDK is initialised successfully <a href="#ensuring-apxoriossdk-is-initialised-successfully" id="ensuring-apxoriossdk-is-initialised-successfully"></a>

* Lookout for the following log in `console output`,

  ```
   ApxoriOSSDK (2XX) : initialized!
  ```

{% hint style="info" %}
**Note**

Apxor uploads data only when the app is minimized to the background. If you are running from XCode (emulators or devices), do not stop the app, just press on the "home" button in order for data to be uploaded.
{% endhint %}

### Additional features API Guide <a href="#api-guide" id="api-guide"></a>

[Click here for guides](/getting-started-with-apxor/api-guides/cordova) to log user properties, events and event properties.


# Flutter

## Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.android.com/studio/build/configure-app-module)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](/getting-started-with-apxor/api-guides/flutter))

## Getting Started

{% hint style="info" %}
**Prerequisites**

Flutter SDK supported version is >= 3.0.1.
{% endhint %}

### Set TAGs for Widgets

In order to display actions on Widgets, you can set tags for widgets using `ValueKey` with `String` as a value to it. It is highly recommended to set TAGs for Widgets which are Scrollable or contains multiple child widgets.

```dart
return TextButton(
  child: const Text('Sign In'),
  key: const ValueKey("Sign-in"), // Add ValueKey with String
  onPressed: () {
    // Sign in
  },
);
```

## Flutter Integration

### Step 1: Add Apxor SDK

Add `apxor_flutter` dependency in `pubspec.yaml`

```yaml
dependencies:
  apxor_flutter:
    git: https://github.com/apxor/apxor-flutter-sdk.git
```

### Step 2: Wrap Main Widget with Apxor Wrapper

```javascript
import 'package:apxor_flutter/apxor.dart';
import 'package:apxor_flutter/observer.dart';
@override
  Widget build(BuildContext context) {
	return ApxorFlutter.createWidget(MaterialApp(
              	…
        ),
);
}
```

### Step 3: Tracking Screens

<details>

<summary>If you are using Navigator in your Application</summary>

<pre class="language-javascript"><code class="lang-javascript">return Navigator(
      observers: [ApxNavigationObserver()],
<strong>      …
</strong>      );

</code></pre>

</details>

<details>

<summary>You are not using Navigator in your Application</summary>

add ApxNavigationObserver wherever routes are defined

```javascript
@override
  Widget build(BuildContext context) {
    return ApxorFlutter.createWidget(
      MaterialApp(
        navigatorObservers: [ApxNavigationObserver()],
	  routes: {
		…
		}
	  …
	),
    )
 }
```

</details>

#### **Passing Context for screen**

To avoid getting the elements from previous screens add the following in build method

```javascript
Widget build(BuildContext context) {
    ApxorFlutter.setContext("{Enter you route name here}", context);
}
```

### Step 4: Handle deeplink redirection

Use `setDeeplinkListener` to listen on deeplink redirection from Apxor SDK and handle redirection logic (including external redirection) within application logic as follows

```dart
ApxorFlutter.setDeeplinkListener((url) {
  // interpret the URL and handle redirection within the application
  _routeState.go(url!);

  // Or, to an external URL which will be opened in Browser
});
```

### Step 5: Redirection using Key-Value Pair (Optional)

Use `setKeyValueListener` to listen on key-value redirection from Apxor SDK and handle redirection logic (including external redirection) within application logic as follows

```dart
ApxorFlutter.setKeyValueListener((data) {
  // data --> [ {"name" :"route ", "value":"\ActionsView"} ]
  // Ex: 
  // "name" and "value" are Keys
  // "route" and "\ActionsView" are Values
});
```

## Android Integration

### Step 0: Add Apxor Repository

Add Maven URL in project level `build.gradle` file.

**`Path: <project>/android/build.gradle`**:

```java

allprojects {
    repositories {
        // ...
        maven {
           url "https://repo.apxor.com/artifactory/list/libs-release-android/"
        }
        // ...
    }
}
```

### Step 1: Add Dependencies to your build.gradle file

**`Path: <project>/android/app/build.gradle`**:

```groovy
dependencies {
//...

    // Event tracking and a must-have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.2.5@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.9@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.7.5@aar'
    implementation 'com.apxor.androidx:surveys:2.3.0@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.5@aar'
    
    // Add the below two dependencies to establish an SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
//...
}
```

### Step 2: Plugins Integration

Create `plugins.json` file in `assets` folder.&#x20;

**`Path: android/app/src/main/assets/plugins.json`**

```json
{
  "plugins": [
    {
      "name": "rtm",
      "class": "com.apxor.androidsdk.plugins.realtimeui.ApxorRealtimeUIPlugin"
    },
    {
      "name": "push-v2",
      "class": "com.apxor.androidsdk.plugins.push.v2.PushPlugin"
    },
    {
      "name": "wysiwyg",
      "class": "com.apxor.androidsdk.plugins.wysiwyg.WYSIWYGPlugin"
    },
    {
      "name": "surveys",
      "class": "com.apxor.androidsdk.plugins.survey.SurveyPlugin"
    },
  ]
}
```

### Step 3: Initialize ApxorSDK

Add `meta-data` tag in `AndroidManifest.xml` file with your unique `APP_ID` as a value. You need to replace `YOUR_APP_ID` with your actual App Id. [Click here](/getting-started-with-apxor/adding-a-new-app#step-5-copy-the-application-identifier) to know how to get app-id.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.apxor.flutter_example">
  <application ...>
      <meta-data android:name="APXOR_APP_ID" android:value="YOUR_APP_ID" />
    </application>
</manifest>
```

### Step 4: Add Proguard Rules

{% hint style="info" %}
**Note**

This is a mandatory step
{% endhint %}

If you do not have a `proguard-rules.pro` file in android folder then create one and configure the below rules in that `proguard-rules.pro` file. If you already have a `proguard-rules.pro` file in android folder then just configure the below rules in the existing file.

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

Add the following in **`<project>/android/app/build.gradle`**

```gradle
buildTypes {
       release {
           signingConfig signingConfigs.release
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }
```

### Step 5: Add exoplayer in your app (optional) <a href="#step-4-add-exoplayer-in-your-app-optional" id="step-4-add-exoplayer-in-your-app-optional"></a>

Exoplayer enables to configure Picture In Picture videos from Apxor dashboard and typically increases the app size by \~1Mb, if you are already using exoplayer in your app this step is not needed else add the following dependency in the application `build.gradle` file

**`Path: <project>/<app-module>/build.gradle`**:

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.6@aar version onwards</summary>

Copy

```
dependendies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

</details>

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.5@aar and below</summary>

Copy

```
dependendies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

<figure><img src="https://guides.apxor.com/~gitbook/image?url=https:%2F%2F300211688-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FQuYbJ9bg7CFtrBaVp9pB%252Fuploads%252FFVZvw6QsR1eWvpNnhqyP%252FInappVideo.png%3Falt=media%26token=43091ace-c788-43de-a3d1-a49f2b23523a&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=57b0a967195f1a2b6905d436f5d76ca5d2605d92cb8fc05e6fb18a243a76d660" alt=""><figcaption></figcaption></figure>

### Step 6: Disable Dexing Artifact Transformation \[optional]

This step is needed only if you use Apxor's Video InApp messages.

{% hint style="info" %}
**Note**

In the Android Gradle Plugin 3.5.0, we desugar & dex using Gradle artifact tranforms, which allow more parallelism and caching. This mechanism relies on libraries having the correct Maven information, because we use dependencies specified in POM files to set up the desugaring classpath. In cases we are unable to see all dependencies when desugaring a class it is required to disable parallel transformation to faciliate the process by adding the property as mentioned below.
{% endhint %}

Add the following in gradle.properties

**`Path: <project>/<app-module>/gradle.properties`**:

```java
android.enableDexingArtifactTransform = false
```

### Step 7: Ensuring ApxorSDK is initialised successfully

We have to verify for two things as follows :

**SDK Initialisation**

On running your android project lookout for the following log in logcat :

```java
ApxorSDK(v2**) successfully initialized for: APP_ID
```

<figure><img src="/files/7hLMlroJFuHWhmh7schm" alt=""><figcaption></figcaption></figure>

**Plugin Initialisation**

By default, only error logs are enabled. To see debug logs for plugin initialisation and to confirm tracking event triggers, user properties. Please run the below command in terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="/files/sRoXlvsMhggAWYRwLrnC" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Apxor uploads data only when the app is minimized to the background. If you are running from Android Studio (emulators or devices), do not stop the app, just press on the "home" button in order for data to be uploaded.
{% endhint %}

### Step 8: Log data to set up triggers and measure goals

Now as we are done with basic integration, we can go ahead to setup event triggers, capture data for targeting and to personalize messaging.

[Click here for guides](/getting-started-with-apxor/api-guides/flutter) to log user properties, events and event properties.

## iOS Integration

### Step 1: Auto initialize SDK

To Auto initialize SDK (Recommended), add the following inside your application plist file.

Open your application's Info.plist as source code.Open Plist as Source Code

<figure><img src="/files/A2eDZBOplAFoGRpOqnRa" alt=""><figcaption></figcaption></figure>

Copy paste the below piece of code, to create an entry for ApxorSDK.

```json
<key>Apxor</key>
<dict>
    <key>Core</key>
    <string>YOUR_APP_ID</string>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

{% hint style="info" %}
**Note**

* If you are unable to find our plugins in your pods after flutter run, then do<mark style="background-color:orange;">**`pod update`**</mark>
  {% endhint %}

### Step 2: Configuring Test Device

You need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.

If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

#### Configuring URL Scheme

To configure URL scheme:

1. go to your project settings
2. select Targets
3. Click on the Info tab
4. Select the URL Types, and click on the + button to add a new URL Scheme
5. Add a new URL Scheme with your bundle identifier as the value

<figure><img src="/files/LYdl0DYk5bXD2h3WiyCZ" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your bundle identifier that was provided in the dashboard while registering with us. Also, the app must have the same bundle identifier.
{% endhint %}

### Step 3: Handling the deep link

Enable Apxor to handle Apxor specific deeplinks.

In your application's **AppDelegate** file, in the function application(\_:open:options:), add the following code at the beginning,

```objectivec
// ObjC
NSString *urlStr = url.absoluteString;
if ([urlStr containsString:@"add-test-device"]) {
  [ApxorSDK handleDeeplink:url];
}
```

```swift
// Swift
let urlStr = url.absoluteString
if (urlStr.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url)
}
```

### Step 4: Log data to set up triggers and measure goals

Now as we are done with basic integration, we can go ahead to setup event triggers, capture data for targeting and to personalize messaging.

[Click here for guides](/getting-started-with-apxor/api-guides/flutter) to log user properties, events and event properties.

### Embed Slot

{% hint style="info" %}
**Note**

For using Apxor Embedded Cards the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

In all areas of the app where you may want to show an in-line widget, insert the following code

```
const ApxorEmbedWidget(valueKey: <Tag>)
```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID (any positive Integer). Ensure that you keep the ID unique across different IDs and across different ApxorEmbedWidget instances.

### Story Slot

{% hint style="info" %}
**Note**

For using Apxor Stories the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

In all areas of the app where you may want to show stories, insert the following code

```
const ApxorStoryWidget(id: <ID>)
```

Replace <mark style="color:blue;">\<ID></mark> with any unique integer(any positive Integer). Ensure that you keep the ID unique across different ApxorStoryWidget instances.

## Web Integration

### Step 1: Add integration scripts and Initialize Apxor&#x20;

Add the following integration scripts to your **index.html** file in the **head tag**(project/web/index.html)

Add your <mark style="background-color:purple;">**site ID**</mark> and <mark style="background-color:purple;">**app version**</mark> in the code below&#x20;

```html
<!-- Start of Integrating APXOR Web SDK -->

<!-- Initializing Apxor Core -->
<script type="text/javascript" defer src="https://unpkg.com/apxor"></script>

<!-- Initializing Apxor QE -->
<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-qe"
> 
</script>
<!-- Initializing Apxor RTM -->
<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-rtm"
>
</script>

<!-- Initialization step -->
<script>
 
  const _d = new Date();
  (function (a, p, x, o, r) {
    Apxor = a.Apxor || { _q: [], _st: _d };
    [
      "init",
      "setUserId",
      "setUserProperties",
      "setSessionProperties",
      "logPageView",
      "logEvent",
      "logClientEvent",
      "setAppVersion",
      "getClientId",
      "getSessionId",
      "startNewSession",
      "endSession",
      "flattenJSON",
      "setRedirectionHandler",
      "setIsFlutter",
      "registerApxorFlutterHelper",
      "setWYSIWYGCookieForFlutter"
    ].forEach(function (m) {
      Apxor[m] = function () {
        this._q.push({ m: m, args: arguments });
      };
    });
   })(window, document, "script");
   
   Apxor.init(
      "YOUR_SITE_ID",
      {
        idle_time_out: 1800,
        plugins: ["ApxorRTM"],
        Version: <Your_App_Version>,
      },
      
      function success(data) {
        console.log("APXOR SDK Initialized");
      },
      function error() {
        console.log("APXOR SDK not initialized");
      });
      
</script>
```


# Jetpack Compose

Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every android app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the google play store.

{% hint style="info" %}
**Note**

Please add <mark style="background-color:blue;">**.apxor**</mark> as suffix to the bundle id&#x20;

eg.&#x20;

&#x20; **`com.example.myapp.apxor`**
{% endhint %}

[(Know more about bundle ids here)](https://developer.android.com/studio/build/configure-app-module)

* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](broken://pages/l2KXXBeVSa1fIQTAMxr7))
* **Firebase Cloud Messaging (FCM) Server Key :** For tracking uninstalls, Apxor sends silent push notifications to measure your campaign outcomes.\
  \
  ([Read more on how to fetch firebase credentials that are used to setup uninstall tracking during integration here](/getting-started-with-apxor/firebase-credentials-optional))

**Understanding dependencies to add to your project**

<table><thead><tr><th width="258.3333333333333">Plugin Name</th><th width="252">Description</th><th>Example</th></tr></thead><tbody><tr><td>apxor-android-sdk-core</td><td>Core Plugin is used to track events for to measure their results and consists of essential information that controls other plugins.</td><td>How many of my users have clicked on the cart icon after showing them a nudge Sample Event : 'ViewCart'</td></tr><tr><td>apxor-android-sdk-qe</td><td>plugin is used to setup behavioural triggers for the campaigns which helps to setup campaign rules.</td><td>Show a campaign to users who land on the home screen and add an item to the cart.</td></tr><tr><td>apxor-android-sdk-rtm</td><td>plugin is used for the show experiences created from the design library using the Apxor dashboard.</td><td>Show a tooltip on the cart icon with messaging "Tap here to view items"</td></tr><tr><td>surveys</td><td>plugin is used to show surveys created using the Apxor dashboard.</td><td>An NPS survey that would ask the user to rate the app experience on a scale of 1-10.</td></tr><tr><td>wysiwyg</td><td>plugin is used to facilitate creation of campaigns by mirroring your mobile screen to identify the right UI element to show the campaign.</td><td>Casting your mobile screen to the dashboard and selecting the hamburger icon</td></tr><tr><td>apxor-jetpack-compose</td><td>plugin is used to find and extract view ids</td><td>Displaying a tooltip on one of the UI element "Subscribe" </td></tr></tbody></table>

### Step 1: Add Apxor Repository

Add Maven URL in project level `build.gradle` file to load the `plugins.json` file you  will create in Step 3.

**`Path: <project>/build.gradle`**:

```java

allprojects {
    repositories {
        // ...
        maven {
           url "https://repo.apxor.com/artifactory/list/libs-release-android/"
        }
        // ...
    }
}
```

<figure><img src="/files/Tuj8ho4phsLmB5qmCUEb" alt=""><figcaption></figcaption></figure>

### Step 2: Add ApxorSDK

Add plugin dependencies to your application `build.gradle` file

**`Path: <project>/<app-module>/build.gradle`**:

[Check the latest release notes here.](/getting-started-with-apxor/release-notes#android)

<details>

<summary>AndroidX</summary>

```java
dependencies {
//...

    // Event tracking and a must have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.1.9@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.4@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.6.3@aar'
    implementation 'com.apxor.androidx:surveys:2.2.6@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.3@aar'
    
    // Add the below two dependencies to establish SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
    //Jetpack compose plugin
    implementation 'com.apxor.androidx:apxor-jetpack-compose:1.0.2@aar

    // Add this to track uninstalls from Apxor dashboard
    implementation('com.apxor.androidx:apxor-android-sdk-push-v2:1.3.1@aar') 
    {
    exclude group: 'com.google.firebase'
    }
    
//...
}
```

</details>

### Step 3: Create Apxor Configuration File

Create an `assets folder` in android `app module` and create the `plugins.json` that contains the below code.

This is used to initialise the dependencies that are used while adding Apxor SDK in the third step.

**`Path: src/main/assets/plugins.json`**:

<details>

<summary>AndroidX</summary>

```java
{
  "plugins": [
    {
      "name": "rtm",
      "class": "com.apxor.androidsdk.plugins.realtimeui.ApxorRealtimeUIPlugin"
    },
    {
      "name": "push-v2",
      "class": "com.apxor.androidsdk.plugins.push.v2.PushPlugin"
    },
    {
      "name": "surveys",
      "class": "com.apxor.androidsdk.plugins.survey.SurveyPlugin"
    },
    {
      "name": "wysiwyg",
      "class": "com.apxor.androidsdk.plugins.wysiwyg.WYSIWYGPlugin"
    }
  ]
}

```

</details>

### Step 4: Add exoplayer in your app (optional)

Exoplayer enables to configure Picture In Picture videos from Apxor dashboard and typically increases the app size by \~1Mb, if you are already using exoplayer in your app this step is not needed else add the following dependency in the application  `build.gradle` file

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.6@aar version onwards</summary>

```gradle
dependendies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

</details>

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.5@aar and below</summary>

```gradle
dependendies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

<figure><img src="/files/BMQoL6soL1X6E8GmUgTs" alt=""><figcaption></figcaption></figure>

### Step 5: Disable Dexing Artifact Transformation

{% hint style="info" %}
**Note**

In the Android Gradle Plugin 3.5.0, we desugar & dex using Gradle artifact tranforms, which allow more parallelism and caching. This mechanism relies on libraries having the correct Maven information, because we use dependencies specified in POM files to set up the desugaring classpath. In cases we are unable to see all dependencies when desugaring a class it is required to disable parallel transformation to faciliate the process by adding the property as mentioned below.
{% endhint %}

Add the following properties `gradle.properties` file

**`Path: <project>/<app-module>/gradle.properties`**:

```java
android.enableDexingArtifactTransform = false
```

### Step 6: Add the following in proguard-rules.pro

{% hint style="info" %}
**Note**

If you use proguard to obfuscate the classes, you have to add the following to ignore obfuscation for Apxor SDK classes
{% endhint %}

Configure the below rules in your `proguard-rules.pro` file

**`Path: <project>/<app-module>/proguard-rules.pro`**:

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

### Step 7: Configuring IDs for View (Mandotory for inlines)

For jetpack compose view component, add an <mark style="color:purple;">**apxorLabel**</mark> modifier. Add the import statement in all the files and the <mark style="color:purple;">**apxorLabel**</mark> to all the view ids where you want to display coachmarks, tooltips and badges.

```kotlin
import com.apxor.androidsdk.plugins.apxor_android_sdk_jc.Modifier

Text(text = "Hello world!", modifier = Modifier.apxorLabel(name)) 
```

{% hint style="info" %}
**Note**

You will not be able to point UI elements (eg. Tooltips, Coachmarks) on any jetpack compose view without an apxorLabel.
{% endhint %}

### Step 7: Enable uninstall tracking for your users

{% hint style="info" %}
**Note**

Apxor does not support `firebase-messaging >= 22.0` while using the push plugin that helps track uninstalls. If your applpication is using `firebase-messaging >=22.0` please remove `android-sdk-push` during integration
{% endhint %}

Apxor uses your firebase server key to send silent push notifications to track uninstalls in order to measure outcomes of your campaign. To enable this please do the following :

**Path : `app/build.gradle`**

<details>

<summary>Firebase Version >= 22.0.0</summary>

```java
dependencies {
  // Add this to track uninstalls from Apxor dashboard
  implementation('com.apxor.androidx:apxor-android-sdk-push-v2:1.2.8@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

If you are using **Firebase version >= 22.0.0** please replace the push plugin in your `assets/plugins.json` with the following

**Replace the following**

**`Path: src/main/assets/plugins.json`**:

```java

{
  "plugins": [
    {
      "name": "push",
      "class": "com.apxor.androidsdk.plugins.push.PushPlugin"
    },
}

```

**With This**

```java

{
  "plugins": [
    {
      "name": "push",
      "class": "com.apxor.androidsdk.plugins.push.v2.PushPlugin"
    },
}
```

</details>

<details>

<summary>Firebase Version &#x3C; 22.0.0</summary>

```java
dependencies {
  // Add this to track uninstalls from Apxor dashboard
  implementation('com.apxor.androidx:apxor-android-sdk-push:1.2.8@aar') {
    exclude group: 'com.google.firebase'
  }
}
```

If you are using **Firebase version <22.0.0** firebase messaging service please handle the notifications like the following :

```java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Creating Notification Channel
        ApxorPushAPI.createNotificationChannel(this.getApplicationContext(), "Apxor", "Apxor", "Apxor");
        if (remoteMessage.getFrom().equals(YOUR_FCM_SENDER_ID)) {
            // Push Notification receiver with your Sender Id
        } else {
            // Check if Push Notification received from Apxor
            if (ApxorPushAPI.isApxorNotification(remoteMessage)) {
                ApxorPushAPI.handleNotification(remoteMessage, getApplicationContext());
            } else {
                // Silent or Data push notification which you can send through Apxor dashboard
            }
        }
    }
}
```

[Read here](/getting-started-with-apxor/firebase-credentials-optional) on how to get your firebase sender ID and also FCM server key to share it with apxor to configure uninstall tracking.

</details>

### Step 8: Initialize SDK

To Auto initialize SDK (Recommended), add following `meta-data` tag inside your `application` tag in your `AndroidManifest.xml` file

**`Path: <project>/<app-module>/src/AndroidManifest.xml`**:

```java
<application>
//...
    <meta-data android:name="APXOR_APP_ID" android:value="Enter Apxor Application Identifier generated in the dashboard"/>
//...
</application>
```

Here is how you can get the Apxor Application Identifier as mentioned in the [Integration Essentials section](/getting-started-with-apxor/adding-a-new-app)

### Step 9: Yay, Verify your SDK integration

We have to verify for two things as follows :

**SDK Initialisation**

On running your android project lookout for the following log in logcat :

```java
ApxorSDK(v2**) successfully initialized for: APP_ID
```

<figure><img src="/files/YvXdm3C74F7yb5fcYmgP" alt=""><figcaption></figcaption></figure>

**Plugin Initialisation**

By default, only error logs are enabled. To see debug logs for plugin initialisation and to confirm tracking event triggers, user properties. Please run the below command in terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="/files/sRoXlvsMhggAWYRwLrnC" alt=""><figcaption></figcaption></figure>


# API Guides


# iOS

### Initializing the SDK

To start tracking with the Apxor iOS SDK, you must first initialize it. To initialize the SDK,

```objectivec
// ObjC
[ApxorSDK initializeApxorSDK];
```

```swift
// Swift
ApxorSDK.initializeApxorSDK()
```

### Identifying the Users

ApxorSDK uses Identifier for Advertisers (IFA) to uniquely identify users. In cases where IFA is not available, we use Identifier for Vendors (IFV) for the same. 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 specially 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 want 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 :

```objectivec
// ObjC
[ApxorSDK setUserIdentifier:@"1729"];
```

```swift
// Swift
ApxorSDK.setUserIdentifier("CustomUserIdentifier")
```

### Setting up campaign triggers, capturing data for targetting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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 behavior or measure your goals as specified above.

To track an event with the event name and properties.

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"Select Language" forKey:@"event_type"];
[info setValue:@"Valyrian" forKey:@"event_type"];
[ApxorSDK logAppEventForEvent:@"LANG_SELECT" withInfo:info];
```

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

```swift
// Swift
let eventDict = ["event_type":"Select Language", "event_type":"Valyrian"] as [String : AnyObject]
ApxorSDK.logAppEvent(withName: "EventName", info: eventDict)
```

### User Attributes

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"spock@vulcan.com" forKey:@"email"];
[ApxorSDK setUserCustomInfo:info];
```

```swift
// Swift
let userInfo = ["email": "spock@vulcan.com"] as [String : AnyObject]
ApxorSDK.setUserCustomInfo(userInfo)
```

### Session Attributes

A Session can be simply defined as a user journey as he opens the app, until he closes the app. There can be various pieces of information that can be very impactful when accumulated in a session. For example, location in a session can be useful to know precisely where the user is utilizing the app most.

To add session attributes that are specific to a session,

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"In a galaxy far far away" forKey:@"location"];
[ApxorSDK setSessionCustomInfo:info];
```

```swift
// Swift
let userInfo = ["location": "In a galaxy far far away"] as [String : AnyObject]
ApxorSDK.setSessionCustomInfo(userInfo)
```

### 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.<br>

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.

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 behavioral observations and interactions to nudge a user.

> Example:
>
> Soft back button, user reaching end of page, etc.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

```objectivec
// ObjC
NSDictionary *info = [[NSDictionary alloc] init];
[info setValue:@"com.example.app.SettingsViewController" forKey:@"Screen"];
[ApxorSDK logClientEventWithName:@"SoftBackPressed" info:info];
```

```swift
// Swift
let eventDict = ["Screen":"com.example.app.SettingsViewController"] as [String : AnyObject]
ApxorSDK.logClientEvent(withName: "SoftBackPressed", info: eventDict)
```

### Track Screens <a href="#track-screens" id="track-screens"></a>

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

ApxorSDK automatically captures screens and their names for most view controllers. In some cases where TabBarController is used, the OS won't be providing any notifications to capture the screens automatically.

For these cases, we encourage you to log screen events using the following API. Make sure to log the API inside the **viewWillAppear** function.

```objectivec
// ObjC
- (void)viewWillAppear:(BOOL)animated {

    [ApxorSDK logScreenWithName:@"FirstViewController"];
    /*
      ... your code here ...
     */
}
```

```swift
// Swift
override func viewWillAppear(animated: Bool) {

    ApxorSDK.logScreenWithName("FirstViewController")
    /*
      ... your code here ...
    */
}
```

### 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 to identify. To report a custom error,

```objectivec
// ObjC
NSException* myException = [NSException
                            exceptionWithName:@"FileNotFoundException"
                            reason:@"File Not Found on System"
                            userInfo:nil];
[ApxorSDK reportCustomError:myException withContext:@"customException"];
```

```swift
// Swift
let errorInfo = ["reason": "File Not Found on System"]  as [String : AnyObject]
var customError = NSError(domain:"", code:httpResponse.statusCode, userInfo:nil)
ApxorSDK.reportCustomError(customError, withInfo: errorInfo)
```

### Custom Fonts

ApxorSDK supports two types of fonts namely, .ttf(TrueType fonts) and .otf(OpenType fonts). Custom fonts can be used in ApxorSDK's real time actions in two simple steps.

#### Adding custom fonts to your application

* Fonts of your choice and selection are to be added in the **`Project's`** **`Supporting files`** section

<figure><img src="/files/w8jLWT5vMd02WGI74Kqv" alt=""><figcaption></figcaption></figure>

* Edit the Info.plist file to add the font names in the **`Fonts provided by application`**

<figure><img src="/files/L8eOcjMpAti22U2GwKpE" alt=""><figcaption></figcaption></figure>

* Ensure the fonts are available in, **`Build phases`** --> **`Copy Bundle resources`**

<figure><img src="/files/EMf1gCrw2poTBAXZWbkq" alt=""><figcaption></figcaption></figure>

#### While configuring the campaigns in the dashboard

* Enable custom fonts
* Enter the same exact font file name along with the extenstion (.ttf or .otf)

<figure><img src="/files/6XEfFlBlAwEIaPGeiyNQ" alt=""><figcaption></figcaption></figure>

You're all set! 🎉

> **Note**
>
> Font properties like Bold, Italic cannot be used in the dashboard for custom fonts. The exact font file with those properties has to be added in your application.

#### 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

```
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  // Your code here
  // ...
  NotificationCenter.default.addObserver(self, selector: #selector(self.onRedirectionClicked(notification:)), name: Notification.Name("APXRedirectionNotification"), object: nil)
}

@objc func onRedirectionClicked(notification: NSNotification) {
  if let kvPairs = notification.userInfo!["info"] {
      print(kvPairs)
      // ...
      // use kvPairs 
      // ...
  }
}
```

```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Your code here
  // ...
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRedirectionClicked:) name:@"APXRedirectionNotification" object:nil];
}

- (void) onRedirectionClicked:(NSNotification *) notification
{
  NSLog(@"kvPairs: %@", notification.userInfo["info"]);
  // ...
  // use kvPairs 
  // ...
}
```

### To get Apxor Device Identifier

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID,

```objc
NSString *deviceId = [ApxorSDK getDeviceID];
```

> **Note**
>
> If the deviceID is nil, please retry after a few seconds.

### Log Events inside WebView <a href="#log-events-inside-webview" id="log-events-inside-webview"></a>

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

  ```js
  window.webkit.messageHandlers.logAppEvent.postMessage({"name": "...", "info": "..."});
  window.webkit.messageHandlers.logClientEvent.postMessage({"name": "...", "info": "..."});
  ```

  > **Note**
  >
  > Make sure the keys of the dictionary in postMessage are "name" and "info", do not change them.
* Examples for logging App Event

  > Example:
  >
  > Log an event on page load event.

  ```html
  ...
  <head>
    ...
    <script>
      function logApxorEvent(eventName, attributes) {
        if (window.webkit) {
          window.webkit.messageHandlers.logAppEvent.postMessage({"name": eventName, "info": attributes});
        }
      }
    </script>
  </head>
  <body onload="logApxorEvent('PageLoaded')">
    ...
  </body>
  ```

  > Example (React based web pages):
  >
  > Log an event on componentDidMount.

  ```js
  componentDidMount() {
      if (window.webkit) {
          window.webkit.messageHandlers.logAppEvent.postMessage({"name": 'LoginPageLoaded'});
      }
  }
  ```

### Actions in WebView

Many native applications feature WebViews to display descriptive content and much more. Apxor iOS SDK provides a way to show real-time actions inside that WebView to make the most of it.

Following are the steps in order to show real-time actions in your WebView.

* Add a tag to the webview (which is to be later provided in the dashboard) as shown.

  ```objectivec
  // ObjC
  [self.webview setTag:007];
  ```

  <pre class="language-swift"><code class="lang-swift"><strong>// Swift
  </strong><strong>webview.tag = 007;
  </strong></code></pre>
* You have to init the APXWKScriptHandler and call registerEventsAndScripts method to make sure any the calls made in the webview are taken care by the native SDK. It's as follows,

  * If you don't already have a bridging header, [checkout how to create a bridging header.](https://developer.apple.com/documentation/swift/importing-objective-c-into-swift)
  * Add the following in the bridging header file.

  ```ObjectiveC
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ```

  * Now, add the following to the init method of your webview

  ```
  let apxHandler: APXWKScriptHandler = APXWKScriptHandler.init(handlerFor: webView)
  apxHandler.registerEventsAndScripts()
  ```
* Here's how to do the same thing in objective-C.

  * Make sure there's a proper WKUserContentController set to your WkWebView, if not please init it and use that config to initialise your WKWebView.

  ```ObjectiveC
  WKUserContentController *controller = [[WKUserContentController alloc] init];
  WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  config.userContentController = controller;
  ```

  ```ObjectiveC
  #import "APXRTAPlugin/APXWKScriptHandler.h"
  ...
  // add apxor's script handler
  APXWKScriptHandler *scriptHandler = [[APXWKScriptHandler alloc] initWithHandlerForWebView:_webView];
  [scriptHandler registerEventsAndScripts];
  ```
* Also, make sure there’s an id for the web element that you want to show tooltip on.

<figure><img src="/files/AQ7OUJTGvaX95EPPbrgF" alt=""><figcaption></figcaption></figure>

* In the above example, the element button has an attribute id = change\_button, which will used to identify that particular element.

### 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 <a href="#the-apxor-language" id="the-apxor-language"></a>

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

```javascript
format(
  "Hello {}. We are exicted to give you {} reward points. You can see these points in Rewards section",
  UserName,
  toInt(RewardPoints)
);
```

* Conditional Dynamic Text

```javascript
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

```javascript
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](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# Web

### Initializing the Apxor SDK

To start tracking with the Apxor SDK, you must first initialize it with your project token. To initialize the SDK,

```javascript
import Apxor from "apxor"; // ES6

Apxor.init("YOUR_SITE_ID", {
  // Initialization options
});
```

#### Initialization options <a href="#initialization-options" id="initialization-options"></a>

* **honorDNT**: *boolean* \[false]

  If this flag is set to `TRUE` and users enable the `doNotTrack` in their browser settings, the SDK won't be initialized. Default Value is `FALSE`
* **idle\_time\_out**: *number(seconds)* \[3600]

  Tells SDK that when to create new session when users are idle for the configured amount of time. Default value is `3600 seconds (1 hour)`
* **plugins**: \[]

  Indicates what plugins needs to be initialized when SDK initializes. Default value is `[]`
* **deps**: \[]

  To make sure the packages to be bundled when you build your application. Default value is `[]`
* **version**: *string* \[ALL]

  Helps you to undestand the events based on a specific version that you set. Default value is `ALL`

> Note:
>
> Contact <support@apxor.com> to get your unique SITE\_ID

***

### Identifying Users <a href="#userid" id="userid"></a>

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 recognize your users :

```javascript
Apxor.setUserId(String);
```

Example:

```javascript
Apxor.setUserId("user@example.com");
```

***

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### App Events <a href="#app-events" id="app-events"></a>

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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 behavior or measure your goals as specified above.

Here is how we track app events:

```javascript
Apxor.logEvent(eventName, eventProperties, forceReport);
```

Example:

```javascript
Apxor.logEvent("ADD_TO_CART", {
  userId: "user@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

#### Immediate Reporting of an event <a href="#immediate-reporting-of-an-event" id="immediate-reporting-of-an-event"></a>

forceReport is an optional parameter with default value false sent to Apxor.logEvent API. Send forceReport as true if the event has to be immediately reported to Apxor. Use it only in specific cases. For example if the event has to be logged just before the browser refresh, use the forceReport flag.

```javascript
Apxor.logEvent(
  "BEFORE_REFRESH",
  {
    userId: "user@example.com",
    value: 123,
  },
  true
);
```

### Client Events <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

> Example:
>
> Soft back button, user reaching end of page, etc.

```javascript
let additionalInfo = {
  page: "/index.html",
};
Apxor.logClientEvent("SoftBackPressed", additionalInfo);
```

### Event tracking via Google Tag Manager (GTM) <a href="#event-tracking-via-google-tag-manager-gtm" id="event-tracking-via-google-tag-manager-gtm"></a>

You can also place the above function as a Custom HTML Tag inside GTM. This Tag can be fired once per event and triggered on the elements where you wish to track website events. The event attributes can be picked up from GTM Data Layer.

![](/files/LJhK7rIziyTsYAaZwZtq)

### User Properties <a href="#user-properties" id="user-properties"></a>

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
Apxor.setUserProperties({
  userProperty1: "value1",
  userProperty2: "value2",
});
```

Example:

```javascript
Apxor.setUserProperties({
  gender: "Male",
  age: 24,
  isPaidUser: true,
  creditsLeft: 250,
});
```

***

### Session Properties <a href="#session-properties" id="session-properties"></a>

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.

Usage:

```javascript
Apxor.setSessionProperties({
  property1: "value1",
  property2: "value2",
});
```

Example:

```javascript
Apxor.setSessionProperties({
  language: "en",
  location: "Hyderabad",
});
```

***

### PageView <a href="#pageview" id="pageview"></a>

You can log a page view event when users navigate through your website

Usage:

```javascript
Apxor.logPageView(String); //String URL pathname
```

Example:

```javascript
Apxor.logPageView("/about.html");
```

***

### Get Client Id <a href="#get-client-id" id="get-client-id"></a>

Apxor SDK maintains a unique ID for every user. To get the Apxor Device ID, use below

Example:

```javascript
const clientId = Apxor.getClientId();
```

***

### Start New Session <a href="#start-new-session" id="start-new-session"></a>

Starts new session if there is no active session. If a session is already in progress, it acts as a no-op

```javascript
Apxor.startNewSession();
```

***

### End Session <a href="#end-session" id="end-session"></a>

Ends the active session if any active session in progress. After this call, none of the Apxor APIs work, except **startNewSession()** API.

```javascript
Apxor.endSession();
```

***

### Handle Deeplink Redirection <a href="#handle-deeplink-redirection" id="handle-deeplink-redirection"></a>

For single page websites built with React/Angular/Vue, you need to handle the internal redirection on your own by using the `setRedirectionHandler` method.

#### Example <a href="#example" id="example"></a>

```javascript
Apxor.setRedirectionHandler((url) => {
  // Interpret the URL and redirect user to the specific URL
});
```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# React Native

### APIs

Add the following import statement in every component where you use Apxor APIs

```java
import RNApxorSDK from "react-native-apxor-sdk";
```

### Identifying Users <a href="#userid" id="userid"></a>

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 recognize your users :

```javascript
// Syntax
RNApxorSDK.setUserIdentifier("STRING");

// Example
RNApxorSDK.setUserIdentifier("<unique_user_id>");
```

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 :

```javascript
// Syntax
RNApxorSDK.logAppEvent(event_name, properties);

// Example
RNApxorSDK.logAppEvent("ADD_TO_CART", {
  userId: "johnwick@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

### User Attributes <a href="#user-attributes" id="user-attributes"></a>

#### Personalizing and targetting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
// Syntax
RNApxorSDK.setUserCustomInfo(properties);

// Example
RNApxorSDK.setUserCustomInfo({
  Age: 10,
  Name: "John Wick",
});
```

### Client Events[**​**](http://localhost:3000/docs/android-sdk/Tracking#client-events) <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

```javascript
// Syntax
RNApxorSDK.logClientEvent(event_name, properties);

// Example
RNApxorSDK.logClientEvent("ADD_TO_CART", {
  userId: "johnwick@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

### Handle custom redirection using Key-Value pairs <a href="#handle-custom-redirection-using-key-value-pairs" id="handle-custom-redirection-using-key-value-pairs"></a>

If your app wants to redirect users based on simple key-value pairs instead using Deeplink URLs or Activity, you can follow below approach

```java
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 Screen

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

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

```java
RNApxorSDK.trackScreen("HomeScreen");
```

### Track Navigation <a href="#track-navigation" id="track-navigation"></a>

**If you are already using a navigation library like&#x20;**<mark style="background-color:yellow;">**`@react-navigation`**</mark>**,  please follow below mentioned steps for Apxor SDK to automatically track screen navigation**

```typescript
import { useNavigationContainerRef } from "@react-navigation/native"

const navigationRef = useNavigationContainerRef()

return (
  <NavigationContainer
    ref={navigationRef}
    onReady={() => {
      const currentRoute = navigationRef?.current?.getCurrentRoute()
      if (currentRoute) {
        RNApxorSDK.trackScreen(currentRoute.name)
      }
    }}
    onStateChange={() => {
      const currentRoute = navigationRef?.current?.getCurrentRoute()
      if (currentRoute) {
        RNApxorSDK.trackScreen(currentRoute.name)
      }
    }}
  >
   // your screens and navigators
  </NavigationContainer>
)

```

{% hint style="info" %}
**Note**

1. You will need it on both `onReady` and `onStateChange` as the SDK needs to log navigation events on the initial app launch and also on futher navigations between screens.
2. The `NavigationContainer` need **not** be straight from `@react-navigation`. It can be from any 3rd party wrapper around `NavigationContainer` (like BugSnag)
   {% endhint %}

**Otherwise use the following API to track navigations on every screen/route change**

```java
// Syntax
RNApxorSDK.logNavigationEvent(screen_name);

// Example
RNApxorSDK.logNavigationEvent("LoginScreen");
```

#### Handle Deeplinks <a href="#handle-deeplinks" id="handle-deeplinks"></a>

Follow the instructions given in [here](https://reactnative.dev/docs/linking) to enable deeplinks in your application.

Whenever Apxor React Native SDK sends the deeplink URL to the app, the following callback will be executed and you have to interpret the URL and navigate the user to the necessary page or tab.

Add the following code snippet in your root component to handle deeplink URLs

```javascript
import { Linking } from "react-native";

function YourRootComponent(props) {
  // Use `componentDidMount` for Class components
  useEffect(() => {
    Linking.addEventListener("url", (event) => {
      const { url } = event;

      // Your custom function which interprets the URL
      // and redirect users to the necessary page or tab
      handleDeeplinkURL(url);
    });
  }, []);
}
```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# Cordova

### APIs

Add the following after your import statements in every component where you use Apxor APIs

```javascript
declare var ApxorSDK: any;
```

### Identifying Users <a href="#identifying-users" id="identifying-users"></a>

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 recognize your users :

```javascript
// Syntax
ApxorSDK.setUserIdentifier("STRING");

// Example
ApxorSDK.setUserIdentifier("<unique_user_id>");
```

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 :

```javascript
// Syntax
ApxorSDK.logAppEvent(event_name, properties[, isAggreagte]);

// Example
ApxorSDK.logAppEvent("ADD_TO_CART", {
    "userId": "johnwick@example.com",
    "value": 1299,
    "item": "Sony Head Phone 1201"
}[, false]);
```

### Client Events[**​**](http://localhost:3000/docs/android-sdk/Tracking#client-events) <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

```javascript
// Syntax
ApxorSDK.logClientEvent(event_name, properties);

// Example
ApxorSDK.logClientEvent("ADD_TO_CART", {
  userId: "johnwick@example.com",
  value: 1299,
  item: "Sony Head Phone 1201",
});
```

### User Attributes <a href="#user-attributes" id="user-attributes"></a>

#### Personalizing and targeting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```javascript
// Syntax
ApxorSDK.setUserCustomInfo(properties);

// Example
ApxorSDK.setUserCustomInfo({
  Age: 10,
  Name: "John Wick",
});
```

### Session Attributes <a href="#session-attributes" id="session-attributes"></a>

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,

```java
ApxorSDK.setSessionCustomInfo({network: "4G", city: "Newyork"});
```

### Track Screens <a href="#track-screens" id="track-screens"></a>

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

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

```javascript
ApxorSDK.trackScreen("CartPage");
```

> **Note**
>
> You can check the typings or APIs exposed by exploring `plugins/cordova-plugin-apxor-sdk/www/ApxorCordovaPlugin.js` or `plugins/cordova-plugin-apxor-sdk/src/ApxorSDK.d.ts`

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# Flutter

### Identifying Users <a href="#identifying-users" id="identifying-users"></a>

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 recognize your users :

```dart
ApxorFlutter.setUserIdentifier("<SOME_USER_ID>");
```

### Setting up campaign triggers, capturing data for targeting and goal tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

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 :

<figure><img src="/files/cjD16dAViQgcMYKKhg53" alt=""><figcaption></figcaption></figure>

### **App Events**[**​**](http://localhost:3000/docs/android-sdk/Tracking#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:

<figure><img src="/files/pwqGbcAFBkZQWXuNvL64" alt=""><figcaption></figcaption></figure>

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 :

```dart
ApxorFlutter.logAppEvent("Login", attributes: {
  "type": "Google",
  "language": "valyrian",
});
```

### User Attributes <a href="#user-attributes" id="user-attributes"></a>

#### Personalizing and targetting by user persona[​](http://localhost:3000/docs/android-sdk/Tracking#personalising-and-targetting-by-user-persona) <a href="#personalising-and-targetting-by-user-persona" id="personalising-and-targetting-by-user-persona"></a>

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.<br>

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.<br>

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.

<figure><img src="/files/kwd028HZ6jg2J3mAGyFH" alt=""><figcaption></figcaption></figure>

This is how you log user information to Apxor :

```dart
ApxorFlutter.setUserAttributes({
  'age': 27,
  'gender': "male",
});
```

### 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,

```dart
ApxorFlutter.setSessionAttributes({
  "network": "4G",
  "location": "Hyderabad",
});
```

### Client Events[**​**](http://localhost:3000/docs/android-sdk/Tracking#client-events) <a href="#client-events" id="client-events"></a>

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.<br>

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.

<figure><img src="/files/aJ3Mv29Z26IODheNEIVE" alt=""><figcaption></figcaption></figure>

> Example:
>
> Soft back button, user reaching end of page, etc.

```dart
ApxorFlutter.logClientEvent("SoftBackPressed", attributes: {
  "screenName": "Payment",
});
```

### Track Screens <a href="#track-screens" id="track-screens"></a>

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.

<figure><img src="/files/T7Xr6AIf4U1AWAnQruYJ" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Use the following APIs only if you have not defined routes in navigator or application. If you already have defined the routes, the same route names will be used to setup campaigns on inactivity or time spent on those screens.
{% endhint %}

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

```dart
ApxorFlutter.trackScreen("LoginScreen", context); // Pass build context

ApxorFlutter.trackScreen("AddToCartScreen", context); // Pass build context

ApxorFlutter.trackScreen("PaymentScreen", context); // Pass build context
```

### Tooltips in WebView <a href="#tooltips-in-webview" id="tooltips-in-webview"></a>

{% hint style="info" %}
**Note**

Please check the updated versions for **Android**

<mark style="background-color:purple;">`apxor-android-sdk-core`</mark> >= 2.9.4

<mark style="background-color:purple;">`apxor-android-sdk-rtm`</mark> plugin version >= 2.2.0

<mark style="background-color:purple;">`wysiwyg`</mark> >= 1.4.1
{% endhint %}

Many native applications feature `WebView`s to display descriptive content and much more. Apxor Flutter 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`.

<details>

<summary>Support for webview_flutter</summary>

* Create webview controller if you don't have one and Add a tag to the `WebView and set the controller with the same tag`

```dart
_controller = new WebViewController();
_controller.setJavaScriptMode(JavaScriptMode.unrestricted);
_controller.addJavaScriptChannel("ApxorFlutter",
      onMessageReceived: (message) {
            ApxorFlutter.apxorJsMessageHandler(message.message);
   });
_controller.setNavigationDelegate(NavigationDelegate(
      onPageStarted: (url) async =>
      await ApxorFlutter.setWebViewController("MyWebView",_controller)));
```

* Add a tag to the `WebView`  and set the controller as shown.

```dart
WebViewWidget(
    key: const ValueKey("MyWebView"),
    controller: _controller,
    ),
```

</details>

<details>

<summary>Support for flutter_inappwebview</summary>

* Add a tag to the `WebView and set the controller with the same tag`

```dart
InAppWebView(
  //...
  key: const ValueKey("MyWebView"),
  onWebViewCreated: (controller) {
    //...
    ApxorFlutter.setInAppWebViewController("MyWebView",controller);
    controller.addJavaScriptHandler(
      handlerName: "ApxorFlutter",
      callback: (args) {
        ApxorFlutter.apxorJsMessageHandler(args[0]);
      });
    //...
  },
  /...
),
```

</details>

### Log Events inside WebView <a href="#log-events-inside-webview" id="log-events-inside-webview"></a>

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

  ```js
  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.

  ```html
  ...
  <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.

  ```js
  componentDidMount() {
      if (window.Apxor && window.Apxor.logAppEvent) {
          window.Apxor.logAppEvent('LoginPageLoaded', null);
      }
  }
  ```

### Yeah! You are ready to create your first [Campaign](/product-guides/create-a-campaign/mobile) or [Survey](/product-guides/create-a-survey/legacy)


# Release Notes

## Native

### AndroidX

| Plugin Name            | Latest Version | Release Date |
| ---------------------- | -------------- | ------------ |
| apxor-android-sdk-rtm  | 2.7.5          | 2026-04-20   |
| apxor-android-sdk-qe   | 1.8.9          | 2026-02-25   |
| apxor-android-sdk-core | 3.2.5          | 2026-02-09   |
| surveys                | 2.3.1          | 2025-12-30   |
| wysiwyg                | 1.6.5          | 2025-10-10   |
| apxor-android-sdk-push | 1.3.1          | 2023-09-29   |
| apxor-jetpack-compose  | 1.0.2          | 2024-06-07   |

### iOS

<table><thead><tr><th width="259.3333333333333">Plugin Name</th><th>Latest Version</th><th>Release Date</th></tr></thead><tbody><tr><td>Core</td><td>2.10.47</td><td>2026-02-26</td></tr><tr><td>WYSIWYG</td><td>1.02.76</td><td>2026-02-26</td></tr><tr><td>CE</td><td>1.05.33</td><td>2026-03-20</td></tr><tr><td>RTA</td><td>1.09.54</td><td>2026-08-10</td></tr><tr><td>Survey</td><td>1.04.25</td><td>2026-08-10</td></tr><tr><td>Push</td><td>1.01.04</td><td>2025-05-15</td></tr><tr><td>SwiftUI (Add if SwiftUI App)</td><td>1.01.01</td><td>2024-04-22</td></tr></tbody></table>

## Web

| Plugin Name  | Latest Version | Release Date |
| ------------ | -------------- | ------------ |
| apxor        | 3.1.2          | 2026-07-23   |
| apxor-rtm    | 2.2.4          | 2026-07-23   |
| apxor-qe     | 2.0.8          | 2026-07-23   |
| apxor-rtm-ui | 0.9.12         | 2026-04-13   |

## React Native

### AndroidX

| Plugin Name                  | Latest Version | Release Date |
| ---------------------------- | -------------- | ------------ |
| apxor-android-sdk-rtm        | 2.7.5          | 2026-04-20   |
| apxor-android-sdk-qe         | 1.8.9          | 2026-02-25   |
| apxor-android-sdk-core       | 3.2.5          | 2026-02-09   |
| surveys                      | 2.3.1          | 2025-12-30   |
| wysiwyg                      | 1.6.5          | 2025-10-10   |
| apxor-android-sdk-push       | 1.3.1          | 2023-09-29   |
| apxor-android-crash-reporter | 1.0.5          | 2019-05-01   |

### iOS

<table><thead><tr><th width="259.3333333333333">Plugin Name</th><th align="center">Latest Version</th><th>Release Date</th></tr></thead><tbody><tr><td>Core</td><td align="center">2.10.44</td><td>2025-12-19</td></tr><tr><td>WYSIWYG</td><td align="center">1.02.75</td><td>2025-12-19</td></tr><tr><td>CE</td><td align="center">1.05.31</td><td>2025-07-30</td></tr><tr><td>RTA</td><td align="center">1.09.54</td><td>2026-08-10</td></tr><tr><td>Survey</td><td align="center">1.04.25</td><td>2026-08-10</td></tr><tr><td>Push</td><td align="center">1.01.04</td><td>2025-05-15</td></tr></tbody></table>

### React Native

| Plugin Name                   | Latest Version | Release Date |
| ----------------------------- | -------------- | ------------ |
| react-native-apxor-sdk        | 1.7.6          | 2024-07-03   |
| react-native-apxor-rtm-plugin | 1.7.1          | 2024-07-03   |

## Cordova

### AndroidX

| Plugin Name            | Latest Version | Release Date |
| ---------------------- | -------------- | ------------ |
| apxor-android-sdk-rtm  | 2.7.1          | 2025-12-30   |
| apxor-android-sdk-qe   | 1.8.8          | 2025-10-10   |
| apxor-android-sdk-core | 3.2.4          | 2025-10-10   |
| surveys                | 2.3.0          | 2025-10-10   |
| wysiwyg                | 1.6.5          | 2025-10-10   |

### iOS <a href="#getting-started-with-apxor-ios-sdk" id="getting-started-with-apxor-ios-sdk"></a>

<table><thead><tr><th width="259.3333333333333">Plugin Name</th><th>Latest Version</th><th>Release Date</th></tr></thead><tbody><tr><td>Core</td><td>2.10.44</td><td>2025-12-19</td></tr><tr><td>WYSIWYG</td><td>1.02.75</td><td>2025-12-19</td></tr><tr><td>CE</td><td>1.05.30</td><td>2025-05-15</td></tr><tr><td>RTA</td><td>1.09.54</td><td>2026-08-10</td></tr><tr><td>Survey</td><td>1.04.25</td><td>2026-08-10</td></tr></tbody></table>

### Cordova

<table><thead><tr><th width="293">Plugin Name</th><th>Latest Version</th><th>Release Date</th></tr></thead><tbody><tr><td>cordova-plugin-apxor-sdk</td><td>1.2.6</td><td>2025-05-21</td></tr></tbody></table>

## Change Logs

### <mark style="color:green;">Androidx</mark>

#### <mark style="color:purple;">**apxor-android-sdk-core**</mark>

<mark style="color:orange;">Released (v3.2.5- 2026-02-09)</mark>

* Blacklisting support for event , user, session properties

<mark style="color:orange;">Released (v3.2.4- 2025-07-30)</mark>

* Updated compile and target sdk versions to 34

<mark style="color:orange;">Released (v3.2.3- 2025-07-30)</mark>

* Introduced support for identifying debug vs. production build at runtime.

<mark style="color:orange;">Released (v3.2.2- 2025-06-04)</mark>

* AutoScroll Support

<mark style="color:orange;">Released (v3.1.9 - 2025-03-25)</mark>

* Handling databaseThread exceptions

<mark style="color:orange;">Released (v3.1.8 - 2024-12-26)</mark>

* Fixed issues in NavigationEvents Handling
* Logging plugin version as Session attribute

<mark style="color:orange;">Released (v3.1.7 - 2024-10-29)</mark>

* Setting of user attributes from JS apis for Web badges

<mark style="color:orange;">Released (v3.1.6 - 2024-10-09)</mark>

* Fixed Event Sanity crash

<mark style="color:orange;">Released (v3.1.5 - 2024-09-26)</mark>

* Refactored Plugins Loading

<mark style="color:orange;">Released (v3.1.2 - 2024-08-09)</mark>

* Logged updated user and session attributes as additional info

<mark style="color:orange;">Released (v3.1.0 - 2024-07-05)</mark>

* Added utility method to get app state

<mark style="color:orange;">Released (v3.0.9 - 2024-06-07)</mark>

* Added support for AVF in jetpack compose
* Modified plugin initialized event attributes

<mark style="color:orange;">Released (v3.0.7 - 2024-05-28)</mark>

* Handling initialization without internet.

<mark style="color:orange;">Released (v3.0.6 - 2024-05-24)</mark>

* Added removeKey api for removing shared preferences.
* Added Plugins.Json for default plugins initialization.

<mark style="color:orange;">Released (v3.0.5 - 2024-05-06)</mark>

* Handling SDK initialization and ANR's
* Handling evaluation events after plugin initialization

<mark style="color:orange;">Released (v3.0.4 - 2024-03-08)</mark>

* Advanced Trigger Conditions
* Advanced View Finding
* Video in app using media 3 exoplayer&#x20;
* Install referrer to get install attribution from play store
* Survey minor bug fixes

<mark style="color:orange;">Released (v2.9.9 - 2024-01-09)</mark>

* Refresh api to dismiss and show nudges when refresh occurs.

<mark style="color:orange;">Released (v2.9.8 - 2023-12-27)</mark>

* Reset method for user and session properties.
* Event Callback Listener.

<mark style="color:orange;">Released (v2.9.7 - 2023-12-18)</mark>

* Added Support for Jetpack Compose

<mark style="color:orange;">Released (v2.9.5 - 2023-09-29)</mark>

* Fixed an issue where screen names were not invalidated upon navigation between activities.

#### <mark style="color:purple;">**apxor-android-sdk-qe**</mark>

<mark style="color:orange;">Released (v1.8.9- 2026-02-25)</mark>

* FAB Support

<mark style="color:orange;">Released (v1.8.8- 2025-10-10)</mark>

* Updated compile and target sdk versions to 34

<mark style="color:orange;">Released (v1.8.7- 2025-10-01)</mark>

* NonEligibleUser events fix

<mark style="color:orange;">Released (v1.8.6- 2025-06-04)</mark>

* AutoScroll Support

<mark style="color:orange;">Released (v1.8.5- 2025-05-19)</mark>

* Event Property support for Dynamic Text

<mark style="color:orange;">Released (v1.8.4- 2025-01-01)</mark>

* Stop conditions across sessions

<mark style="color:orange;">Released (v1.8.3 - 2024-12-20)</mark>

* Survey Stop conditions V2

<mark style="color:orange;">Released (v1.8.2 - 2024-11-27)</mark>

* Survey stop conditions&#x20;

<mark style="color:orange;">Released (v1.8.1 - 2024-10-29)</mark>

* Web Badges requirement to not update the trigger to a screen event.

<mark style="color:orange;">Released (v1.8.0 - 2024-10-09)</mark>

* Differentiating Onboarding display type in event logging

<mark style="color:orange;">Released (v1.7.8 - 2024-08-09)</mark>

* Fixed issue in UserAttributes based stop condition
* Fixed issue in Video pip delete conditions

<mark style="color:orange;">Released (v1.7.5 - 2024-07-05)</mark>

* Logged apx\_nudge\_terminated event for goal event based termination
* Removed an Action is already been shown check
* Fixed issue in apx\_context\_evaluated event with apx\_variant\_code property

<mark style="color:orange;">Released (v1.7.4 - 2024-06-28)</mark>

* Fix for campaign start time issue
* Added stories termination
* Renamed campaign terminated event to nudge terminated event

<mark style="color:orange;">Released (v1.7.3 - 2024-06-07)</mark>

* Added support for avf in jetpack compose

<mark style="color:orange;">Released (v1.7.1 - 2024-05-28)</mark>

* Registering termination conditions if the campaign is already shown
* Added Embed cards termination

<mark style="color:orange;">Released (v1.7.0 - 2024-05-24)</mark>

* Handling session limits

<mark style="color:orange;">Released (v1.6.9 - 2024-05-06)</mark>

* Handling evaluation of events after Plugin initialization
* Scheduling and Repeat conditions
* Overall count fix
* Removed isActionBeingShown check for termination and Pre-Inapp conditions in Video-Inapp

<mark style="color:orange;">Released (v1.6.8 - 2024-04-11)</mark>

* Bug Fixes

<mark style="color:orange;">Released (v1.6.7 - 2024-04-08)</mark>

* Event attribute validation

<mark style="color:orange;">Released (v1.6.6 - 2024-03-08)</mark>

* Advanced Trigger Conditions
* Advanced View Finding
* Video in app using media 3 exoplayer&#x20;
* Install referrer to get install attribution from play store
* Survey minor bug fixes

<mark style="color:orange;">Released (v1.6.0 - 2023-10-04)</mark>

* Updated proguard-rules.
* Added ApxUtils for inter-plugin dependency.
* Introduced Termination conditions support.
* Added support for No-context campaigns.

#### <mark style="color:purple;">**WYSIWYG**</mark>

<mark style="color:orange;">Released (v1.6.5- 2025-10-10)</mark>

* Updated compile and target sdk versions to 34

<mark style="color:orange;">Released (v1.6.4 - 2025-07-30)</mark>

* AVF support for finding views in web

<mark style="color:orange;">Released (v1.6.3 - 2024-10-30)</mark>

* Added safeguard to prevent WebView debugging in production environments

<mark style="color:orange;">Released (v1.6.2 - 2024-10-09)</mark>

* minSDK version check handling at plugin initialisation

<mark style="color:orange;">Released (v1.6.1 - 2024-09-26)</mark>

* minSDK version check handling at plugin initialisation

<mark style="color:orange;">Released (v1.5.6 - 2024-07-05)</mark>

* Changed rtm dependency to rtm-x dependency
* Refactored toast messages

<mark style="color:orange;">Released (v1.5.5 - 2024-06-26)</mark>

* Added support for stories
* Added density to the layout information
* Added options to show/hide embedded cards replacing toggle
* Added option to remove widget

<mark style="color:orange;">Released (v1.5.3 - 2024-06-10)</mark>

* Added support for AVF in Jetpack Compose

<mark style="color:orange;">Released (v1.5.1 - 2024-05-28)</mark>

* Embedded cards support.

<mark style="color:orange;">Released (v1.5.0 - 2024-05-24)</mark>

* SSE connection using okhttp3
* Configurable SSE Widget Position
* Preview Issue Fixed

<mark style="color:orange;">Released (v1.4.9 - 2024-03-08)</mark>

* Advanced Trigger Conditions
* Advanced View Finding
* Video in app using media 3 exoplayer&#x20;
* Install referrer to get install attribution from play store
* Survey minor bug fixes

<mark style="color:orange;">Released (v1.4.6 - 2023-12-18)</mark>

* Added Support for jetpack compose

<mark style="color:orange;">Released (v1.4.5 - 2023-12-11)</mark>

* Changes in the layout extraction for webview (webview tag, optimized css path)
* Support for automatically sending screenshot after preview including Flutter
* Improved debug logs

<mark style="color:orange;">Released (v1.4.2 - 2023-09-29)</mark>

* Fixed an issue where screen names were not invalidated upon navigation between activities.
* Added support for Badge termination in the preview.

#### <mark style="color:purple;">**apxor-android-sdk-pushv2**</mark>

<mark style="color:orange;">Released (v1.3.1 - 2023-09-29)</mark>

* Introduced real-time nudge feature.

#### <mark style="color:purple;">**surveys**</mark>

<mark style="color:orange;">Released (v2.3.1- 2025-12-30)</mark>

* Fixes IME insets and screen restriction issues

<mark style="color:orange;">Released (v2.3.0- 2025-10-10)</mark>

* Updated compile and target sdk versions to 34

<mark style="color:orange;">Released (v2.2.9 - 2025-08-29)</mark>

* Removed deprecated methods and dependencies

<mark style="color:orange;">Released (v2.2.8 - 2025-06-03)</mark>

* Support for offline surveys

<mark style="color:orange;">Released (v2.2.7 - 2025-05-19)</mark>

* Surveys Dynamic Text and Script support

<mark style="color:orange;">Released (v2.2.6 - 2025-03-25)</mark>

* Added checks for posting survey response

<mark style="color:orange;">Released (v2.2.5 - 2025-01-22)</mark>

* Survey Adaptive Text support for NPS.

<mark style="color:orange;">Released (v2.2.4 - 2025-01-21)</mark>

* Survey Image Persistence support
* Survey Adaptive Text support
* Invalid URL/path handling

<mark style="color:orange;">Released (v2.2.3 - 2024-12-20)</mark>

* Survey Stop conditions V2

<mark style="color:orange;">Released (v2.2.2 - 2024-11-27)</mark>

* Survey stop conditions

<mark style="color:orange;">Released (v2.2.1 - 2024-11-11)</mark>

* Logging nudge not shown when the current activity is null
* Retry time to show survey when the current activity is null in preview mode

<mark style="color:orange;">Released (v2.2.0 - 2024-10-09)</mark>

* Support for Survey preview

<mark style="color:orange;">Released (v2.1.8 - 2024-07-05)</mark>

* Added delay met event
* Added survey not shown event

<mark style="color:orange;">Released (v2.1.7 - 2024-06-28)</mark>

* Removed empty check for selected choices
* Validate url changed to v3
* Version logging as session attributes

<mark style="color:orange;">Released (v2.1.5 - 2024-05-28)</mark>

* Handling initialization without internet

<mark style="color:orange;">Released (v2.1.4 - 2024-05-06)</mark>

* Fixed disabled color not applied for outlined buttons
* Handling SDK Initialization and evaluation of event after plugin initialization

<mark style="color:orange;">Released (v2.1.3 - 2024-04-08)</mark>

* Blacklisting and whitelisting of screens
* Min and Max number of choices selection
* Default redirection in response based surveys

<mark style="color:orange;">Released (v2.1.2 - 2024-03-08)</mark>

* Advanced Trigger Conditions
* Advanced View Finding
* Video in app using media 3 exoplayer&#x20;
* Install referrer to get install attribution from play store
* Survey minor bug fixes

<mark style="color:orange;">Released (v2.0.9 - 2024-02-08)</mark>

* Renamed animation resource files to resolve conflicts with Client Application resources

<mark style="color:orange;">Released (v2.0.8 - 2024-01-03)</mark>

* Redirection version 2.
* Redirection in response based surveys.
* Request for survey and Thank you message.

<details>

<summary>Older Releases</summary>

<mark style="color:orange;">Released (v2.0.7 - 2023-12-27)</mark>

* Surveys Results

<mark style="color:orange;">Released (v2.0.1 - 2023-09-29)</mark>

* Introducing the New Surveys
* NPS Template: Gather valuable feedback using the Net Promoter Score (NPS) template.
* Use ratings with design options of number tiles and radio buttons to capture user sentiment effectively.
* Follow-Up Questions: Engage users with follow-up questions based on the rating selected or options selected in single-choice and multi-choice questions.
* One-Click Suggested Answers: Make it easy for respondents by providing one-click suggested answers tailored to their response to the main question.

</details>

#### <mark style="color:purple;">**apxor-android-sdk-rtm**</mark>

<mark style="color:orange;">Released (v2.7.5- 2026-04-20)</mark>

* Fab Stop Conditions Support
* Fix fab image scaling and vibration issues

<mark style="color:orange;">Released (v2.7.4- 2026-02-26)</mark>

* Fab support
* Campaigns as click actions
* Stories support in fab

<mark style="color:orange;">Released (v2.7.3- 2026-02-25)</mark>

* Fab support

<mark style="color:orange;">Released (v2.7.2- 2025-10-01)</mark>

* Pip UI changes and fixes

<mark style="color:orange;">Released (v2.7.1- 2025-12-30)</mark>

* Fix whitelist blacklist issue in inapps and pip

<mark style="color:orange;">Released (v2.7.0- 2025-10-10)</mark>

* Updated compile and target sdk versions to 34
* Stories full screen mode support

<mark style="color:orange;">Released (v2.6.9 - 2025-10-01)</mark>

* Updated story redirection handling

<mark style="color:orange;">Released (v2.6.8 - 2025-08-29)</mark>

* Removed deprecated methods and dependencies

<mark style="color:orange;">Released (v2.6.7- 2025-07-30)</mark>

* Added safeguard to prevent WebView debugging in production environments

<mark style="color:orange;">Released (v2.6.6- 2025-06-04)</mark>

* AutoScroll Support
* Disable User Interaction support
* View Visibility threshold support

<mark style="color:orange;">Released (v2.6.4 - 2025-05-19)</mark>

* InAppBuilder Dynamic Script support
* Dynamic Text support for CoachMarkv2 and Badge
* Disable User Interaction support

<mark style="color:orange;">Released (v2.6.3 - 2025-03-25)</mark>

* Target view click stop condition and immediate termination for walkthroughs
* Auto Dismiss For VideoInapp
* Black Listing and white listing for VideoInapp

<mark style="color:orange;">Released (v2.6.2 - 2025-01-21)</mark>

* PIP button swap support
* Exclude percentage support

<mark style="color:orange;">Released (v2.6.1 - 2024-11-14)</mark>

* Delay for webview badges

<mark style="color:orange;">Released (v2.5.8 - 2024-10-09)</mark>

* Tap and Swipe features, v4 events in Onboarding
* Dynamic Script support in CoachmarksV2

<mark style="color:orange;">Released (v2.5.7 - 2024-09-26)</mark>

* Crash fix when SDK is not initialised
* Fixes Jetpackcompose issues

<mark style="color:orange;">Released (v2.5.1 - 2024-08-09)</mark>

* Handling buttons position in maximised mode

<mark style="color:orange;">Released (v2.4.8 - 2024-07-18)</mark>

* Logged apx\_nudge\_not\_shown events during activity navigation and in other possible cases
* Logged apx\_delay\_met event after the completion of delay duration
* Display toast messages for test campaigns
* Handling threads in stories termination

<mark style="color:orange;">Released (v2.4.6 - 2024-06-26)</mark>

* Added support for Stories
* Sync validate url upgraded to V3
* Wait interval for Embedded cards is handled by webSDK
* Fixed issue with ReactNative Embedded cards preview
* Changed tag for Webview in embedded cards
* Added priority for Embedded cards
* Flutter loop fix for Embedded cards
* Version logging as session attributes

<mark style="color:orange;">Released (v2.4.5 - 2024-06-10)</mark>

* Added support for AVF in jetpack compose

<mark style="color:orange;">Released (v2.4.2 - 2024-05-28)</mark>

* Embed Cards Support
* Handling initialization without internet
* Logger Interface for web views

<mark style="color:orange;">Released (v2.4.1 - 2024-05-24)</mark>

* Handling issue in onboarding for jetpack compose.

<mark style="color:orange;">Released (v2.4.0 - 2024-05-06)</mark>

* Handling events after plugin initialization.
* &#x20;Webview caching for improving performance in inapps.
* &#x20;Video download handling for video in apps.
* &#x20;Adaptive text for nudges.
* &#x20;Configurable content overflow check.

<mark style="color:orange;">Released (v2.3.9 - 2024-04-08)</mark>

* Blacklisting and whitelisting of screens for inApps
* Never show action for buttons in tooltips , web inlines and inApps
* Tooltip animation in dim background

<mark style="color:orange;">Released (v2.3.8 - 2024-03-08)</mark>

* Advanced Trigger Conditions
* Advanced View Finding
* Video in app using media 3 exoplayer&#x20;
* Install referrer to get install attribution from play store
* Survey minor bug fixes

<mark style="color:orange;">Released (v2.3.5 - 2024-02-21)</mark>

* Improved support for apps with obfuscation.

<mark style="color:orange;">Released (v2.3.4 - 2024-02-08)</mark>

* Renamed animation resource files to resolve conflicts with Client Application resources

<details>

<summary>Older Releases</summary>

<mark style="color:orange;">Released (v2.3.2 - 2024-02-05)</mark>

* Improved checks and bug fixes for inlines and videos.

<mark style="color:orange;">Released (v2.3.1 - 2024-01-19)</mark>

* Nudges refresh fix.

<mark style="color:orange;">Released (v2.3.0 - 2024-01-09)</mark>

* Refresh api for nudges.
* CoachmarkV2 bug fixes.
* Misplacement of tooltip in dim-background fixed

<mark style="color:orange;">Released (v2.2.9 - 2023-12-27)</mark>

* CoachMarkV2 with Images and Arrow.
* Support for callback on event.

<mark style="color:orange;">Released (v2.2.7 - 2023-12-11)</mark>

* Added jetpack compose support

<mark style="color:orange;">Released (v2.2.7 - 2023-12-11)</mark>

* Overall count screen explainer fix
* Screen Explainer for flutter
* Improved isShowing flag update for flutter
* Close Icon position fix for Tooltips

<mark style="color:orange;">Released (v2.2.1 - 2023-09-29)</mark>

* Added Enhanced Coachmarks nudges feature.
* Added Badge nudges feature.
* Fixed issues in the Explainer feature.
* Implemented tracking of screen changes.
* Fixed the view-in-app audio issue.

</details>

#### <mark style="color:purple;">**apxor-jetpack-compose**</mark>

<mark style="color:orange;">Released (v1.0.2 - 2024-06-07)</mark>

* Added support for AVF in Jetpack Compose

<mark style="color:orange;">Released (v1.0.0 - 2023-12-18)</mark>

* New Release

### <mark style="color:green;">iOS</mark>

#### <mark style="color:purple;">**ApxoriOSSDK-Core**</mark>

<mark style="color:orange;">Released (v2.10.47 - 2026-02-26)</mark>

* CallBacks in iOS

<mark style="color:orange;">Released (v2.10.46 - 2026-02-26)</mark>

* Fab
* Campaign Action , Story Action

<mark style="color:orange;">Released (v2.10.45 - 2026-02-25)</mark>

* User Prop Issue Fix

<mark style="color:orange;">Released (v2.10.44 - 2025-12-19)</mark>

* Coach mark v1 issue
* iOS26 Liquid Glass Screenshot issue

<mark style="color:orange;">Released (v2.10.43 - 2025-07-30)</mark>

* Video Inapp video download and delete

<mark style="color:orange;">Released (v2.10.42 - 2025-05-15)</mark>

* Survey Dynamic Text / Script
* Inapp Builder Dynamic Text / Script
* Event Prop support for Dynamic Text
* Tooltip Redirection Deprecated API
* Disable User Interaction
* Refactored apx\_reason for Dynamic Text/Script Failed Cases
* Capable to show nudge even if NavBar is hidden.
* DYSM Issue For Xcode 16
* Dynamic Script/text support for all data types

<mark style="color:orange;">Released (v2.10.41 - 2025-03-01)</mark>

* Walkthrough Stop conditions
* Inapp cancel action
* Inapp redirection issue fix
* Video-inapp black listing and whitelisting fixes
* A/B variant code fix
* CoachMark v2 ripple opacity
* Removed `apx_plugin_initalized` event and logging the versions as session props

<mark style="color:orange;">Released (v2.10.40 - 2025-01-21)</mark>

* Survey Adaptive Text
* Coachmark fix

<mark style="color:orange;">Released (v2.10.39 - 2025-01-10)</mark>

* Enhancements in Stop condition across Sessions

<mark style="color:orange;">Released (v2.10.38 - 2025-01-02)</mark>

* Goal Event Stop condition across Sessions

<mark style="color:orange;">Released (v2.10.37 - 2024-12-17)</mark>

* Screen Explainer&#x20;

<mark style="color:orange;">Released (v2.10.36 - 2024-11-27)</mark>

* Survey stop conditions&#x20;

<mark style="color:orange;">Released (v2.10.35 - 2024-11-14)</mark>

New dashboard features added

* Fixed Events that are logged before SDK initialization
* Event Prop support for Dynamic script and text

<mark style="color:orange;">Released (v2.10.31 - 2024-08-22)</mark>

New dashboard features added

* Event sanity
* Event logging for v4 campaigns
* multistep walkthrough revamp
* Inapp Builder
* Bug fixes related to new dashboard

<mark style="color:orange;">Released (v2.10.27 - 2024-07-20)</mark>

* Bug fixes

<mark style="color:orange;">Released (v2.10.26 - 2024-06-28)</mark>

* New Audience Support
* Data Type Handling in user, session and event attributes

<mark style="color:orange;">Released (v2.10.24 - 2024-06-27)</mark>

* Stories feature added

<mark style="color:orange;">Released (v2.10.23 - 2024-06-20)</mark>

* Added New scheduling and repeat conditions
* bug fixes

<mark style="color:orange;">Released (v2.10.22 - 2024-05-28)</mark>

* Added Embed cards support

<mark style="color:orange;">Released (v2.10.21 - 2024-05-03)</mark>

* React Native Bug fixes

<mark style="color:orange;">Released (v2.10.20 - 2024-04-22)</mark>

* Added swiftUI support

<mark style="color:orange;">Released (v2.10.18 - 2024-04-08)</mark>

* Campaign Diagnostic

<mark style="color:orange;">Released (v2.10.17 - 2024-03-20)</mark>

* Added Advanced View Finding for React Native

<mark style="color:orange;">Released (v2.10.16 - 2024-03-15)</mark>

* Added Advanced View Finding for native and Flutter

<mark style="color:orange;">Released (v2.10.15 - 2024-02-16)</mark>

* Added Video In-app

<mark style="color:orange;">Released (v2.10.14 - 2024-02-15)</mark>

* Bug fixes

<mark style="color:orange;">Released (v2.10.13 - 2024-01-25)</mark>

* Added support for test ids in react native and new test device addition flow

<mark style="color:orange;">Released (v2.10.12 - 2024-01-09)</mark>

* New api for screen refresh fix

<details>

<summary>Older Releases</summary>

<mark style="color:orange;">Released (v2.10.10 - 2023-12-06)</mark>

* Minor bug fixes

<mark style="color:orange;">Released (v2.10.06 - 2023-11-18)</mark>

* Animations : shine and ripple
* Scrolls: horizontal and vertical scrolls
* Stop conditions: when to stop badge display on an element
* Bug fixes

<mark style="color:orange;">Released (v2.10.03 - 2023-09-29)</mark>

* Added support for badges and enhanced the Coachmarks.
* Improved the display of nudges on the navigation bar.
* Improved the support for Flutter.

</details>

#### <mark style="color:purple;">**ApxoriOSSDK-CE**</mark>

<mark style="color:orange;">Released (v1.05.33 - 2026-03-20)</mark>

* Fix in Multiple Goal Event Stop condition

<mark style="color:orange;">Released (v1.05.32 - 2026-02-26)</mark>

* Fab
* Campaign Action , Story Action

<mark style="color:orange;">Released (v1.05.31 - 2025-07-30)</mark>

* Video Inapp video download and delete

<mark style="color:orange;">Released (v1.05.30 - 2025-05-15)</mark>

* Survey Dynamic Text / Script
* Inapp Builder Dynamic Text / Script
* Event Prop support for Dynamic Text
* Tooltip Redirection Deprecated API
* Disable User Interaction
* Refactored  `apx_reason`  for Dynamic Text/Script Failed Cases
* Capable to show nudge even if NavBar is hidden.
* DYSM Issue For Xcode 16
* Dynamic Script/text support for all data types

<mark style="color:orange;">Released (v1.05.29 - 2025-03-01)</mark>

* Goal Event Stop condition across Sessions
* Walkthrough Stop conditions
* Inapp cancel action
* Inapp redirection issue fix
* Video-inapp black listing and whitelisting fixes
* A/B variant code fix
* CoachMark v2 ripple opacity
* Removed `apx_plugin_initalized` event and logging the versions as session props

<mark style="color:orange;">Released (v1.05.28 - 2025-01-02)</mark>

* Goal Event Stop condition across Sessions

<mark style="color:orange;">Released (v1.05.27 - 2024-11-27)</mark>

* Screen Explainer

<mark style="color:orange;">Released (v1.05.26 - 2024-12-17)</mark>

* Survey Stop Conditions V2

<mark style="color:orange;">Released (v1.05.25 - 2024-11-27)</mark>

* Survey stop conditions

<mark style="color:orange;">Released (v1.05.24 - 2024-11-14)</mark>

* Fixed Events that are logged before SDK initialization
* Event Prop support for Dynamic script and text
* Regex Support for Trigger Events

<mark style="color:orange;">Released (v1.05.19 - 2024-08-22)</mark>

New dashboard features added

* Event sanity
* Event logging for v4 campaigns
* multistep walkthrough revamp
* Inapp Builder
* Bug fixes related to new dashboard

<mark style="color:orange;">Released (v1.05.17 - 2024-07-25)</mark>

* Minor bug fixes

<mark style="color:orange;">Released (v1.05.16 - 2024-06-28)</mark>

* New Audience Support
* Data Type Handling in user, session and event attributes

<mark style="color:orange;">Released (v1.05.14 - 2024-06-27)</mark>

* Stories feature added

<mark style="color:orange;">Released (v1.05.13 - 2024-06-20)</mark>

* Added New scheduling and repeat conditions
* bug fixes

<mark style="color:orange;">Released (v1.05.12 - 2024-06-11)</mark>

* Added never show button action
* Black listing and white listing screens to show in-apps and surveys
* UI changes to tooltips

<mark style="color:orange;">Released (v1.05.11 - 2024-05-28)</mark>

* Added Embed cards support

<mark style="color:orange;">Released (v1.05.09 - 2024-05-03)</mark>

* React Native Bug fixes

<mark style="color:orange;">Released (v1.05.08 - 2024-04-08)</mark>

* Campaign Diagnostic

<mark style="color:orange;">Released (v1.05.06 - 2023-11-18)</mark>

* Animations : shine and ripple
* Scrolls: horizontal and vertical scrolls
* Stop conditions: when to stop badge display on an element
* Bug fixes

<mark style="color:orange;">Released (v1.05.04 - 2023-09-29)</mark>

* Added support for termination conditions for badges.

#### <mark style="color:purple;">**ApxoriOSSDK-WYSIWYG**</mark>

<mark style="color:orange;">Released (v1.02.76 - 2026-02-26)</mark>

* Fab
* Campaign Action , Story Action

<mark style="color:orange;">Released (v1.02.75- 2025-12-19)</mark>

* Coach mark v1 issue
* iOS26 Liquid Glass Screenshot issue

<mark style="color:orange;">Released (v1.02.74 - 2025-05-15)</mark>

* Survey Dynamic Text / Script
* Inapp Builder Dynamic Text / Script
* Event Prop support for Dynamic Text
* Tooltip Redirection Deprecated API
* Disable User Interaction
* Refactored  `apx_reason`  for Dynamic Text/Script Failed Cases
* Capable to show nudge even if NavBar is hidden.
* DYSM Issue For Xcode 16
* Dynamic Script/text support for all data types

<mark style="color:orange;">Released (v1.02.73 - 2025-03-01)</mark>

* Goal Event Stop condition across Sessions
* Walkthrough Stop conditions
* Inapp cancel action
* Inapp redirection issue fix
* Video-inapp black listing and whitelisting fixes
* A/B variant code fix
* CoachMark v2 ripple opacity
* Removed `apx_plugin_initalized` event and logging the versions as session props

<mark style="color:orange;">Released (v1.02.72 - 2024-12-19)</mark>

* Screen Explainer

<mark style="color:orange;">Released (v1.02.71 - 2024-11-14)</mark>

* AVF In webviews

<mark style="color:orange;">Released (v1.02.68 - 2024-08-22)</mark>

New dashboard features added

* Event sanity
* Event logging for v4 campaigns
* multistep walkthrough revamp
* Inapp Builder
* Bug fixes related to new dashboard

<mark style="color:orange;">Released (v1.02.67 - 2024-06-27)</mark>

* Stories feature added

<mark style="color:orange;">Released (v1.02.66 - 2024-05-28)</mark>

* Added Embed cards support

<mark style="color:orange;">Released (v1.02.65 - 2024-04-22)</mark>

* Added SwiftUI support

<mark style="color:orange;">Released (v1.02.63 - 2024-04-08)</mark>

* Campaign Diagnostic

<mark style="color:orange;">Released (v1.02.62 - 2024-03-20)</mark>

* Added Advanced View Finding for React Native

<mark style="color:orange;">Released (v1.02.61 - 2024-03-15)</mark>

* Added Advanced View Finding for native and Flutter

<mark style="color:orange;">Released (v1.02.60 - 2024-02-16)</mark>

* Added Video In-app

<mark style="color:orange;">Released (v1.02.59 - 2024-01-25)</mark>

* Added support for test ids in react native and new test device addition flow

<details>

<summary>Older Releases</summary>

<mark style="color:orange;">Released (v1.02.58 - 2023-12-27)</mark>

* new webview templates
* survey request and success message

<mark style="color:orange;">Released (v1.02.54 - 2023-10-11)</mark>

* Resolved action conflicts in case of web views.
* Added support for badges and enhanced the Coachmarks.
* Improved the support for Flutter.

</details>

#### <mark style="color:purple;">**ApxoriOSSDK-RTA**</mark>&#x20;

<mark style="color:orange;">Released (v1.09.54 - 2026-08-10)</mark>

* Removed window Deprecated API
* Tooltip Close icon tint color

<mark style="color:orange;">Released (v1.09.51 - 2026-02-26)</mark>

* Fab
* Campaign Action , Story Action

<mark style="color:orange;">Released (v1.09.50 - 2026-02-02)</mark>

* VideoPIP Enhancements

<mark style="color:orange;">Released (v1.09.49 - 2025-12-19)</mark>

* Coach mark v1 issue
* iOS26 Liquid Glass Screenshot issue

<mark style="color:orange;">Released (v1.09.48 - 2025-10-06)</mark>

* Stories&#x20;
  * Full screen mode
  * Redirection

<mark style="color:orange;">Released (v1.09.47 - 2025-08-29)</mark>

* Cordova Redirection Fix

<mark style="color:orange;">Released (v1.09.46 - 2025-07-30)</mark>

* Video Inapp video download and delete

<mark style="color:orange;">Released (v1.09.45 - 2025-05-28)</mark>

* Nudges on views that are not in view port(Scroll handled by the app).

<mark style="color:orange;">Released (v1.09.44 - 2025-05-15)</mark>

* Survey Dynamic Text / Script
* Inapp Builder Dynamic Text / Script
* Event Prop support for Dynamic Text
* Tooltip Redirection Deprecated API
* Disable User Interaction
* Refactored  `apx_reason`  for Dynamic Text/Script Failed Cases
* Capable to show nudge even if NavBar is hidden.
* DYSM Issue For Xcode 16
* Dynamic Script/text support for all data types

<mark style="color:orange;">Released (v1.09.43 - 2025-03-01)</mark>

* Goal Event Stop condition across Sessions
* Walkthrough Stop conditions
* Inapp cancel action
* Inapp redirection issue fix
* Video-inapp black listing and whitelisting fixes
* A/B variant code fix
* CoachMark v2 ripple opacity
* Removed `apx_plugin_initalized` event and logging the versions as session props

<mark style="color:orange;">Released (v1.09.42 - 2024-01-21)</mark>

* Survey Adaptive Text
* Coachmark fix

<mark style="color:orange;">Released (v1.09.41 - 2024-01-10)</mark>

* Exclude Percentage
* video Inapp Button
* Survey Image Persistance

<mark style="color:orange;">Released (v1.09.40 - 2024-12-19)</mark>

* Screen Explainer

<mark style="color:orange;">Released (v1.09.39 - 2024-11-15)</mark>

* Flutter critical bug fixes

<mark style="color:orange;">Released (v1.09.38 - 2024-11-14)</mark>

* Fixed Events that are logged before SDK initialization
* AVF In webviews
* Multi-Badges in webviews
* User prop and session prop api for webview
* Event changes in Badges

<mark style="color:orange;">Released (v1.09.31 - 2024-08-22)</mark>

New dashboard features added

* Event sanity
* Event logging for v4 campaigns
* multistep walkthrough revamp
* Inapp Builder
* Bug fixes related to new dashboard

<mark style="color:orange;">Released (v1.09.27 - 2024-07-25)</mark>

* Minor bug fixes

<mark style="color:orange;">Released (v1.09.25 - 2024-06-28)</mark>

* New Audience Support
* Data Type Handling in user, session and event attributes

<mark style="color:orange;">Released (v1.09.24 - 2024-06-27)</mark>

* Stories feature added

<mark style="color:orange;">Released (v1.09.23 - 2024-06-20)</mark>

* Added New scheduling and repeat conditions
* bug fixes

<mark style="color:orange;">Released (v1.09.22 - 2024-06-11)</mark>

* Added never show button action
* Black listing and white listing screens to show in-apps and surveys
* UI changes to tooltips

<mark style="color:orange;">Released (v1.09.21 - 2024-06-08)</mark>

* Adhoc fixes
  * Keyboard handling for in-app as a form
  * percent encoding for spaces for button click events
  * Badge behavior for UI Table view Header and Footer

<mark style="color:orange;">Released (v1.09.20 - 2024-05-28)</mark>

* Added Embed cards support

<mark style="color:orange;">Released (v1.09.19 - 2024-05-03)</mark>

* React Native Bug fixes

<mark style="color:orange;">Released (v1.09.18 - 2024-04-22)</mark>

* Added SwiftUI support

<mark style="color:orange;">Released (v1.09.16 - 2024-04-08)</mark>

* Campaign Diagnostic

<mark style="color:orange;">Released (v1.09.15 - 2024-03-20)</mark>

* Added Advanced View Finding for React Native

<mark style="color:orange;">Released (v1.09.14 - 2024-03-15)</mark>

* Added Advanced View Finding for native and Flutter

<mark style="color:orange;">Released (v1.09.13 - 2024-02-16)</mark>

* Added Video In-app

<mark style="color:orange;">Released (v1.09.12 - 2024-02-15)</mark>

* Bug fixes

<mark style="color:orange;">Released (v1.09.11 - 2024-01-09)</mark>

* New api for screen refresh fix

<details>

<summary>Older Releases</summary>

<mark style="color:orange;">Released (v1.09.09 - 2023-12-27)</mark>

* new webview templates
* survey request and success message

<mark style="color:orange;">Released (v1.09.04 - 2023-11-18)</mark>

* Animations : shine and ripple
* Scrolls: horizontal and vertical scrolls
* Stop conditions: when to stop badge display on an element
* Bug fixes

<mark style="color:orange;">Released (v1.09.02 - 2023-10-11)</mark>

* Resolved action conflicts in case of web views.
* Added support for badges and enhanced the Coachmarks.
* Introduced the ability to use custom fonts in in-apps.
* Improved the support for Flutter.

</details>

#### <mark style="color:purple;">**ApxoriOSSDK-Survey**</mark>**&#x20;***<mark style="color:red;">**(new)**</mark>*&#x20;

<mark style="color:orange;">Released (v1.04.25 - 2026-08-10)</mark>

* Removed window Deprecated API
* Tooltip Close icon tint color

<mark style="color:orange;">Released (v1.04.24 - 2025-10-22)</mark>

* Survey Text limits and placeholder enhancements

<mark style="color:orange;">Released (v1.04.23 - 2025-05-15)</mark>

* Survey Dynamic Text / Script
* Event Prop support for Dynamic Text
* Refactored  `apx_reason`  for Dynamic Text/Script Failed Cases
* DYSM Issue For Xcode 16
* Dynamic Script/text support for all data types

<mark style="color:orange;">Released (v1.04.22 - 2025-03-01)</mark>

* Goal Event Stop condition across Sessions
* Walkthrough Stop conditions
* Inapp cancel action
* Inapp redirection issue fix
* Video-inapp black listing and whitelisting fixes
* A/B variant code fix
* CoachMark v2 ripple opacity
* Removed `apx_plugin_initalized` event and logging the versions as session props

<mark style="color:orange;">Released (v1.04.21 - 2024-01-21)</mark>

* Survey Adaptive Text
* Coachmark fix

<mark style="color:orange;">Released (v1.04.20 - 2024-01-10)</mark>

* Exclude Percentage
* video Inapp Button
* Survey Image Persistance

<mark style="color:orange;">Released (v1.04.19 - 2024-12-17)</mark>

* Survey Stop Conditions V2

<mark style="color:orange;">Released (v1.04.18 - 2024-11-27)</mark>

* Survey stop conditions

<mark style="color:orange;">Released (v1.04.17 - 2024-14-11)</mark>

* Fixed Events that are logged before SDK initialization

<mark style="color:orange;">Released (v1.04.14 - 2024-08-22)</mark>

New dashboard features added

* Event sanity
* Event logging for v4 campaigns
* multistep walkthrough revamp
* Inapp Builder
* Bug fixes related to new dashboard

<mark style="color:orange;">Released (v1.04.13 - 2024-07-25)</mark>

* Minor bug fixes

<mark style="color:orange;">Released (v1.04.12 - 2024-06-20)</mark>

* Added New scheduling and repeat conditions
* bug fixes

<mark style="color:orange;">Released (v1.04.11 - 2024-06-11)</mark>

* Added never show button action
* Black listing and white listing screens to show in-apps and surveys
* UI changes to tooltips

<mark style="color:orange;">Released (v1.04.10 - 2024-05-03)</mark>

* React Native Bug fixes

<mark style="color:orange;">Released (v1.04.09 - 2024-04-08)</mark>

* Campaign Diagnostic

<mark style="color:orange;">Released (v1.04.06 - 2023-12-27)</mark>

* new webview templates
* survey request and success message

<mark style="color:orange;">Released (v1.04.02 - 2023-11-04)</mark>

* Experience enhancements
* Minor bug fixes

<mark style="color:orange;">Released (v1.04.01 - 2023-09-29)</mark>

* Introducing the New Surveys
* NPS Template: Gather valuable feedback using the Net Promoter Score (NPS) template.
* Use ratings with design options of number tiles and radio buttons to capture user sentiment effectively.
* Follow-Up Questions: Engage users with follow-up questions based on the rating selected or options selected in single-choice and multi-choice questions.
* One-Click Suggested Answers: Make it easy for respondents by providing one-click suggested answers tailored to their response to the main question.

### <mark style="color:green;">Web</mark>

#### <mark style="color:purple;">**apxor**</mark>

<mark style="color:orange;">Released (v3.1.0 - 2026-06-16)</mark>

* Added "url" property to APX\_PAGE\_OPENED event
* Added apx\_nudge\_id and apx\_nudge\_name to every event
* updated event name InApp\_button\_Clicked to inapp\_button\_clicked along with InLines and Surveys
* updated apx\_failure\_type to apx\_notshown\_type in apx\_non\_eligible\_user and apx\_nudge\_not\_shown event
* Added apx\_nudge\_delay\_met event
* updated onboarding events as per excel sheet given by poorna anna
* updated custom inapp template events firing ( inapp\_shown and walkthrough\_cancelled firing twice)
* integrated custom HTML tooltip support
* integrated blacklisting events support
* Updated Timeout inApp UI

<mark style="color:orange;">Released (v3.0.3 - 2025-11-26)</mark>

* Added Types for Init function in sdk-core module

<mark style="color:orange;">Released (v3.0.1 - 2024-09-27)</mark>

* Funnel Dropoff&#x20;
* Frequency and New Repeat Conditions
* Survey Preview
* Font color issues in track events and track pages

<mark style="color:orange;">Released (v2.7.0 - 2024-07-16)</mark>

* Added event attributes in auto track events and auto track pages.

<mark style="color:orange;">Released (v2.6.0 - 2024-04-08)</mark>

* Advanced View Finding
* Track Pages & Track Events&#x20;
* No Context Campaigns and Screen Binding
* Legacy coachmark and new coachmark walkthrough issues
* Never show action for buttons in web and webviews&#x20;
* Min and Max choices selection in surveys
* Default redirection in response based surveys
* Campaign diagnostics revamp

<mark style="color:orange;">Released (v2.5.0 - 2024-02-21)</mark>

* Boolean support for event properties
* Function for preserving local storage
* Survey Close Icon Position Change
* Callbacks

<mark style="color:orange;">Released (v2.4.0 - 2024-01-02)</mark>

* Request for Survey and Thankyou message
* Survey Redirections
* Survey Results
* Campaign Diagnostics
* Event Sanity
* Reset Method
* Minor Fixes

#### <mark style="color:purple;">**apxor-qe**</mark>

<mark style="color:orange;">Released (v2.0.6- 2026-06-16)</mark>

* Added "url" property to APX\_PAGE\_OPENED event
* Added apx\_nudge\_id and apx\_nudge\_name to every event
* updated event name InApp\_button\_Clicked to inapp\_button\_clicked along with InLines and Surveys
* updated apx\_failure\_type to apx\_notshown\_type in apx\_non\_eligible\_user and apx\_nudge\_not\_shown event
* Added apx\_nudge\_delay\_met event
* updated onboarding events as per excel sheet given by poorna anna
* updated custom inapp template events firing ( inapp\_shown and walkthrough\_cancelled firing twice)
* integrated custom HTML tooltip support
* integrated blacklisting events support

<mark style="color:orange;">Released (v2.0.4 - 2025-10-09)</mark>

* Survey Enhacements

<mark style="color:orange;">Released (v2.0.1 - 2024-09-27)</mark>

* Funnel Dropoff&#x20;
* Frequency and New Repeat Conditions
* Survey Preview
* Font color issues in track events and track pages

<mark style="color:orange;">Released (v1.8.0 - 2024-07-16)</mark>

* Added event attributes in auto track events and auto track pages.

<mark style="color:orange;">Released (v1.7.0 - 2024-04-08)</mark>

* Advanced View Finding
* Track Pages & Track Events&#x20;
* No Context Campaigns and Screen Binding
* Legacy coachmark and new coachmark walkthrough issues
* Never show action for buttons in web and webviews&#x20;
* Min and Max choices selection in surveys
* Default redirection in response based surveys
* Campaign diagnostics revamp

<mark style="color:orange;">Released (v1.6.0 - 2024-02-21)</mark>

* Boolean support for event properties
* Function for preserving local storage
* Survey Close Icon Position Change
* Callbacks

<mark style="color:orange;">Released (v1.5.0 - 2024-01-02)</mark>

* Request for Survey and Thankyou message
* Survey Redirections
* Survey Results
* Campaign Diagnostics
* Event Sanity
* Reset Method
* Minor Fixes

#### <mark style="color:purple;">**apxor-rtm**</mark>

<mark style="color:orange;">Released (v2.2.2 - 2026-06-16)</mark>

* Added "url" property to APX\_PAGE\_OPENED event
* Added apx\_nudge\_id and apx\_nudge\_name to every event
* updated event name InApp\_button\_Clicked to inapp\_button\_clicked along with InLines and Surveys
* updated apx\_failure\_type to apx\_notshown\_type in apx\_non\_eligible\_user and apx\_nudge\_not\_shown event
* Added apx\_nudge\_delay\_met event
* updated onboarding events as per excel sheet given by poorna anna
* updated custom inapp template events firing ( inapp\_shown and walkthrough\_cancelled firing twice)
* integrated custom HTML tooltip support
* integrated blacklisting events support

<mark style="color:orange;">Released (v2.0.9 - 2026-03-26)</mark>

* Carousal Embedded Cards

<mark style="color:orange;">Released (v2.0.4 - 2025-10-09)</mark>

* Survey Enhancements

<mark style="color:orange;">Released (v2.0.2 - 2024-09-27)</mark>

* Funnel Dropoff&#x20;
* Frequency and New Repeat Conditions
* Survey Preview
* Font color issues in track events and track pages

<mark style="color:orange;">Released (v1.13.0 - 2024-07-16)</mark>

* Added event attributes in auto track events and auto track pages.

<mark style="color:orange;">Released (v1.12.0 - 2024-04-08)</mark>

* Advanced View Finding
* Track Pages & Track Events&#x20;
* No Context Campaigns and Screen Binding
* Legacy coachmark and new coachmark walkthrough issues
* Never show action for buttons in web and webviews&#x20;
* Min and Max choices selection in surveys
* Default redirection in response based surveys
* Campaign diagnostics revamp

<mark style="color:orange;">Released (v1.11.0 - 2024-02-21)</mark>

* Boolean support for event properties
* Function for preserving local storage
* Survey Close Icon Position Change
* Callbacks

<mark style="color:orange;">Released (v1.10.0 - 2024-01-02)</mark>

* Request for Survey and Thankyou message
* Survey Redirections
* Survey Results
* Campaign Diagnostics
* Event Sanity
* Reset Method
* Minor Fixes

### <mark style="color:green;">Cordova</mark>

#### <mark style="color:purple;">**cordova-plugin-apxor-sdk**</mark>

<mark style="color:orange;">Released (v1.2.5 - 2023-12-05)</mark>

* Support for new iOS plugins
* Track screen support
* Deeplink handling refactor using internal event
* Mulish font support


# Performance

#### Mechanism

* **Tools Used**: PACT (Apxor’s in-house performance monitoring tool)
* **Benchmarking candidate**: Firebase SDK
* **Duration of each run**: 10 minutes
* **Total no. of runs**: 10

#### Impact on App Size

| S.No. | Description       | App Size              |
| ----- | ----------------- | --------------------- |
| 1     | Standalone App    | 3.8 MB                |
| 2     | App + NudgesSDK   | 4.55 MB **(+750 KB)** |
| 3     | App + FirebaseSDK | 4.6 MB **(+800 KB)**  |

#### CPU Bechmarking

The following matrix consists of **Device vs %CPU consumed**

<table><thead><tr><th width="159">Device</th><th width="155" align="center">Standalone App</th><th width="224" align="center">App + ApxorNudgesSDK</th><th align="center">App + FirebaseSDK</th></tr></thead><tbody><tr><td><strong>OnePlus 3</strong><br>(Android 9)</td><td align="center">23.12</td><td align="center">31.6</td><td align="center">49.08</td></tr><tr><td><strong>OnePlus 7</strong><br>(Android 10)</td><td align="center">8.62</td><td align="center">10.70</td><td align="center">12.43</td></tr><tr><td><strong>Xiaomi Mi A1</strong><br>(Android 9)</td><td align="center">24.23</td><td align="center">30.40</td><td align="center">35.94</td></tr><tr><td><strong>Xiaomi Mi A3</strong><br>(Android 10)</td><td align="center">6.69</td><td align="center">8.25</td><td align="center">7.52</td></tr></tbody></table>

<mark style="background-color:yellow;">**Note**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">On an average, for the high end devices (OnePlus 5 and above) with ApxorNudgesSDK integrated, CPU usage would increase by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**2%**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">while with FirebaseSDK it would increase by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**4-5%**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">.</mark>

<mark style="background-color:yellow;">In low end devices with ApxorNudgesSDK integrated, CPU usage would increase by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**8%**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">while for firebase the CPU usage would increase by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**20%**</mark><mark style="background-color:yellow;">.</mark>

#### Memory Bechmarking

The following matrix consists of **Device vs Memory Usage in KB**

<table><thead><tr><th width="226.33333333333331">Device</th><th align="center">App + ApxorNudgesSDK</th><th align="center">App + FirebaseSDK</th></tr></thead><tbody><tr><td><strong>OnePlus 3</strong><br>(Android 9)</td><td align="center">24.84</td><td align="center">28.92</td></tr><tr><td><strong>OnePlus 7</strong><br>(Android 10)</td><td align="center">24.62</td><td align="center">29.38</td></tr><tr><td><strong>Xiaomi Mi A1</strong><br>(Android 9)</td><td align="center">18.10</td><td align="center">24.18</td></tr><tr><td><strong>Xiaomi Mi A3</strong><br>(Android 10)</td><td align="center">20.11</td><td align="center">26.90</td></tr></tbody></table>

<mark style="background-color:yellow;">**Note**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">For ApxorNudgesSDK with all the plugins installed, the memory increases by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**30 KB**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">which is on par with the Firebase SDK that has seen an increase by</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**29 KB**</mark><mark style="background-color:yellow;">.</mark>

#### Battery Usage Bechmarking

The following matrix consists of **Device vs %Battery Drain**

<table><thead><tr><th width="173">Device</th><th width="171" align="center">Standalone App</th><th width="219" align="center">App + ApxorNudgesSDK</th><th align="center">App + FirebaseSDK</th></tr></thead><tbody><tr><td><strong>OnePlus 3</strong><br>(Android 9)</td><td align="center">0.15</td><td align="center">0.19</td><td align="center">0.29</td></tr><tr><td><strong>OnePlus 7</strong><br>(Android 10)</td><td align="center">0.03</td><td align="center">0.05</td><td align="center">0.05</td></tr><tr><td><strong>Xiaomi Mi A1</strong><br>(Android 9)</td><td align="center">0.18</td><td align="center">0.23</td><td align="center">0.32</td></tr><tr><td><strong>Xiaomi Mi A3</strong><br>(Android 10)</td><td align="center">0.12</td><td align="center">0.13</td><td align="center">0.13</td></tr></tbody></table>

<mark style="background-color:yellow;">**Note**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">For ApxorNudgesSDK with all the plugins installed on an average the battery drain % would be</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**0.03%**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">while with the FirebaseSDK installed it is recorded to be around</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**0.06%**</mark><mark style="background-color:yellow;">.</mark>


# Troubleshooting

<details>

<summary>Error: "Could not find apxor"</summary>

Make sure that you've added Apxor's Maven repository to your root-level build.gradle file

</details>

<details>

<summary>Error: "Class not found"</summary>

Please check if plugins.json is added to the assets folder to initialise the libraries.

</details>


# Product Guides

These guides will help you understand the campaign, survey, templates available in each, and a step-by-step guide on creating, designing, and launching the campaigns and surveys.

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Create a Campaign</strong></td><td align="center"></td><td><em>You can create and publish campaigns with minimal effort with Apxor</em></td><td><a href="/files/DQaunccSSKIhQfswMKNN">/files/DQaunccSSKIhQfswMKNN</a></td><td><a href="/pages/jgKxPRWiqxhyNeBPHjCV">/pages/jgKxPRWiqxhyNeBPHjCV</a></td></tr><tr><td align="center"><strong>Create a Survey</strong></td><td align="center"></td><td><em>You can create and publish surveys with minimal effort with Apxor</em></td><td><a href="/files/8PSTdbokou9Wt8hvfPdG">/files/8PSTdbokou9Wt8hvfPdG</a></td><td><a href="/pages/XSvmtE21z0XlfXvIjRCs">/pages/XSvmtE21z0XlfXvIjRCs</a></td></tr><tr><td align="center"><strong>Custom Reports</strong></td><td align="center"></td><td><em>How to Download Custom Reports?</em></td><td><a href="/files/vGDci1qH3VwAy9yI15zq">/files/vGDci1qH3VwAy9yI15zq</a></td><td><a href="/pages/rHdSm7LaniCQWmayAZZO">/pages/rHdSm7LaniCQWmayAZZO</a></td></tr><tr><td align="center"><strong>Adding a Test Device</strong></td><td align="center"></td><td><em>Add a test device to preview your campaigns and surveys before they go live</em></td><td><a href="/files/a9tTD7WgYuXo8FjRlpBN">/files/a9tTD7WgYuXo8FjRlpBN</a></td><td></td></tr></tbody></table>


# Integration Checklist

To fully utilize Apxor's offerings, make sure you have completed the following Integration Checklist. You may skip the unnecessary steps as per your requirement.

## Integration and Initialization

The Integration and Initialization step is a must to use any Apxor feature. The Apxor dependencies are needed to track events, setup behavioral triggers, draw nudges and surveys and facilitate creation of campaigns by mirroring your mobile screen to identify the right UI element to show the campaign

Refer here for process. [Android(X)](/getting-started-with-apxor/sdk/android-x#integration-and-initialization).

## Identifying Users <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

In order to use **Segments** and **Cohorts**, it is mandatory to set User Identifier for Apxor to recognize your users.

Refer here for more info and process. [Android(X)](/getting-started-with-apxor/sdk/android-x#identifying-users).

## Log events and user data for Targeting, Triggering and goal Tracking[​](http://localhost:3000/docs/android-sdk/Tracking#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking) <a href="#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking" id="setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking"></a>

It is recommended to track all the events, event attributes, session attributes and user attributes. This data will be used to effectively Target the users, accurately identify the trigger condition and track the goal event completion.&#x20;

Refer here for more info and logging process. [Android(X)](/getting-started-with-apxor/sdk/android-x#setting-up-campaign-triggerscapturing-data-for-targetting-and-goal-tracking).

## Define Screens Names

It is important to define the screens to set them up as triggers and also to capture the time spent on the screens. This information  necessary to set campaigns on inactivity or time spent on specific screen. Tracking screens is mandatory if your app uses [fragments](https://developer.android.com/guide/fragments#:~:text=A%20Fragment%20represents%20a%20reusable,an%20activity%20or%20another%20fragment.), and you want to show nudges on UI elements in these fragments.

Refer here for more info and process. [Android(X)](/getting-started-with-apxor/sdk/android-x#track-screens).

## Set Tags for WebView and log events

If you application uses WebView and you want to show nudges on the UI elements in these WebView, you need to set tags to them for unique identification and log the events in the WebView.

Refer here for process. [Android(X)](/getting-started-with-apxor/sdk/android-x#tooltips-in-webview).

## Add Apxor's Embed and Story Slots

If you want to use Apxor's Embedded cards and Stories feature, you need to add the respective slots on your screens. Apxor will display the Embedded cards and Stories campaigns in these slots.

Refer here for process. [Android(X)](/getting-started-with-apxor/sdk/android-x#embed-and-story-slots).

## Handle Custom Redirection using Key-Value pairs

It is recommended to handle key-value pair redirection if you intend to use the same for redirecting the users from the nudge CTAs.

Refer here for more info and process. [Android(X)](/getting-started-with-apxor/sdk/android-x#handle-custom-redirection-using-key-value-pairs).


# Create a Campaign

You can create and publish campaigns and surveys with minimal effort with Apxor.

<figure><img src="/files/4ijThN5o2YE0Ap81VqTo" alt=""><figcaption></figcaption></figure>

On the Dashboard home page, select your organization name, then select the application for which you want to launch the campaign, then click on Nudges in the left panel and select Campaigns.

On the Campaigns dashboard, you have the CTA to create a new campaign, on the right side. Once you click the CTA, you will be asked to enter the Campaign details. Enter the Name of the campaign and choose a tag if you want to categorize this campaign, and click on **Create**.

## Add templates

{% content-ref url="/pages/JTvTWOEgP9XwPdGgncPX" %}
[Mobile](/product-guides/create-a-campaign/mobile)
{% endcontent-ref %}

{% content-ref url="/pages/LsHDEqZxXdRdv9q1IU1o" %}
[Web Templates](/product-guides/create-a-campaign/web/web-templates)
{% endcontent-ref %}


# Mobile

### Add Templates

You can start designing the campaign by adding templates by clicking on the ➕ icon on the left side. You can select from [tooltips](/product-guides/create-a-campaign/mobile/campaign-designs/tooltips), [inapp-messages](/product-guides/create-a-campaign/mobile/campaign-designs/in-app-messages), [coachmarks](/product-guides/create-a-campaign/mobile/campaign-designs/coachmarks) and [badges](/product-guides/create-a-campaign/mobile/campaign-designs/badges). Once you have found the right template, click “Select”.

<figure><img src="/files/PkbSHPhc2uFBYWhiKcnE" alt=""><figcaption></figcaption></figure>

### Select Test Device

You will need to select a test device for the templates that will anchor to a UI element. Search and select your device name. If your device is not registered already, [follow the steps here to get it registered](/product-guides/adding-a-test-device). Open the application on your test device. Click on “Enable Widget”. Then you will see the Apxor logo on the top center of your test device screen. Click on that logo, then click on "**Select this screen**".

{% hint style="info" %}
**Note**

You need to add the test device again if you reinstall the application or clear the application data.
{% endhint %}

<figure><img src="/files/EmVhWfhabQ0QIzu8R6QZ" alt=""><figcaption></figcaption></figure>

You will see the snippet of your test device screen on the right side. Select the UI element you want the template to anchor to, then click “**Continue**”. You can also click on the previous step to edit if needed.

Select the path or view id/tag of the UI element and click “**Proceed**”.

### Capture Screen with the Widget for Immersive Templates

1. After selecting the immersive card template, click on select screen on dashboard
2. Scan QR Code using your mobile test device
3. Click on "Launch App" in the browser page that opens
4. Click on the Apxor Widget at the top, then click on "Toggle Embed Cards" or "Toggle Stories" to see all the embed cards present on the current screen.
5. To capture the screen for the dashboard, click on the Apxor Widget and select "Select this screen."

<figure><img src="/files/8aCoJ694J2V73aA8Zbf9" alt=""><figcaption></figcaption></figure>

### Customize your Template

#### Text and Font

To edit the text of the title, description, or buttons, click on the text, and a popup will appear where you can edit the text, font type, font size, and font color. You can also add a custom font by adding ttf/otf file.

<figure><img src="/files/hCaVRLDXLDVEUJKpyT2V" alt=""><figcaption></figcaption></figure>

You can enable **Adaptive Text**; if enabled, the text size will adapt to the end user's device text settings; small, medium, and large. If this is not enabled, the text size selected on the Apxor dashboard will be applied.

You can also select the **Dynamic Text** option as per your need. Using Dynamic Text, we can read and present any of the values of

* User properties
* Session Properties
* UI element in the front end
* Response from an API call
* Dynamic Text

  * Provide your preferred variable name
  * Select the property type
  * Select the property you want
  * Provide the default value and click on “**Add**”.
  * Write your text with the variable name in curly **{var\_name}** braces and click **Save**
  * You can also write the script to trigger conditional dynamic text

  <figure><img src="/files/BnL1U3S5q4KniJYVSD0E" alt=""><figcaption></figcaption></figure>
* Script: We can perform the mathematical and logical operations between the values read for the variables using a few lines of code.

**Unary Operators**

> ! (Negation)

**Logical Operators**

> && (Logical AND)
>
> **`||`** (Logical OR)

**Mathematical Operators**

> `+` (Arithmetic Addition)
>
> `-`(Arithmetic Subtraction)
>
> &#x20;`*`(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 an HTTP GET API call
>
> **`format`** will be used to format a string
>
> **`if`**, **`else`** will be used to write a conditional evaluation
>
> **`true`**, **`false`** boolean keywords
>
> **`toInt`** will be helpful to convert double/float values to integer
>
> `replace` will be useful for replacing a substring in a string

#### Screen Restriction

Enable Screen Restriction for your InApp to avoid disturbing the user flow on important screens.

1. **None:** Display the nudge without restrictions upon satisfying the trigger condition.
2. **Blacklists:** Select the screens where you want to avoid displaying the nudge.
3. **Whitelists:** Select the screens where you want to display the nudge; rest all the screens will be blacklisted for showing this nudge.

#### Edit Design

You can choose a close button at the top-right corner of a tooltip. Click the close button radio icon in the Edit Design section to enable it in the tooltip. Once enabled, click on the cross icon in the tooltip for further [customizations](/product-guides/create-a-campaign/mobile/campaign-designs/tooltips#close-icon).&#x20;

You can change the background color of the text and buttons by simply clicking on them.

<figure><img src="/files/NfYOMgYZ1bJmORBKwFwP" alt=""><figcaption></figcaption></figure>

You can alter the number of buttons from the available options. You can also change the button action.

* Actions
  * Dismiss

    This action will let the user dismiss this step in the survey, and the user will be shown the next step in the flow.
  * Redirect

    This action will redirect the user to an external link or an internal page in the app.
  * Cancel

    This action will let the user end the entire flow. The flow will end when the user clicks on a button with the “cancel” action, and all the further steps will disappear.
  * Never Show

    This action will stop showing the campaign if the user clicks on a button with the Never Show action, even if the limits are not exhausted for the repetition.

You can also dim the background or enable animation for the nudge/tooltip.

<figure><img src="/files/MRDF4ZRXWoCm3khh9D6a" alt=""><figcaption></figcaption></figure>

* In the Dismiss Config section
  * you can choose if the tooltip/coachmark should be dismissed by clicking outside anywhere on the screen.
  * you can choose if the tooltip/in-app-message/coachmark should disappear automatically after *X* seconds of inactivity by the user.
* You can choose the delay time to show the campaign.

### Preview on Device

You can select the test device from the bottom and click “**Preview on device**” to view the nudge on your test device. Ensure the Apxor overlay widget is enabled on the screen to preview the nudge. You need to kill the app and reopen it after each change for the preview.

You can see the preview screen after clicking “**Refresh**” on the left panel.

Know the difference between [Preview vs. Test vs. Publish](/product-guides/preview-vs.-test-vs.-publish)

### Next Steps in Campaign Creation

{% content-ref url="/pages/9CbR5EcXObVnyanc9mUP" %}
[Target](/product-guides/create-a-campaign/mobile/target)
{% endcontent-ref %}

{% content-ref url="/pages/nGSHxV4mKU4vdUk9Gbbd" %}
[Trigger](/product-guides/create-a-campaign/mobile/trigger)
{% endcontent-ref %}

{% content-ref url="/pages/G589kk1C1Sp2s4GoMNhH" %}
[Schedule and Limit](/product-guides/create-a-campaign/mobile/schedule-and-limit)
{% endcontent-ref %}

{% content-ref url="/pages/ThKHoWua7F8GsYDrSOwi" %}
[Review and Test](/product-guides/create-a-campaign/mobile/review-and-test)
{% endcontent-ref %}

{% content-ref url="/pages/KNBRERCbtmxVU4p08slf" %}
[Set Priority and Publish](/product-guides/create-a-campaign/mobile/set-priority-and-publish)
{% endcontent-ref %}


# Target

Start by selecting your target users – whether you want to aim the campaign to “All Users”, “Segment” of Users, or “Cohort” of users.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPtrkJ3vMAFJUXSFiqzDo%2Fuploads%2Fb3fQt9733qx3m42H5psr%2FTarget.gif?alt=media&#x26;token=9ff3e086-fde6-4767-8205-095e174407f3" alt=""><figcaption></figcaption></figure>

### All Users

If you choose all users, you can also select an app event that users did not do in their lifetime to narrow down the target audience from the drop-down.

<figure><img src="/files/FA88SsfTLEXcfGBVskrp" alt=""><figcaption></figcaption></figure>

> **Segment vs Cohort**
>
> * A "**Segment**" is a group of consumers who share similar characteristics such as age, income, geographic location, or purchasing behavior. Marketers often use consumer segments to identify and target specific groups of consumers with tailored products, messaging, and marketing strategies.
> * A "**Cohort**" is a group of individuals sharing a common characteristic or experience within a defined period. In the context of consumer behavior, a cohort might refer to a group of individuals who were born in a certain year, graduated from college in a certain year, or who first purchased a product during a specific time period. Cohorts can be useful for understanding a group of consumers' purchasing patterns and behaviors over time.

### Segment

If you choose a segment of users, you can select the user segment from the drop-down below “Select Segment”. By selecting the segment, you will be able to see the segment details below. You can also specify the time period during which you want to select the users in that segment, it can be Between 2 date ranges or in the “Last” in the previous day(s). To further drill down the segment, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/Nep1LClSzTfY5a48RfLp" alt=""><figcaption></figcaption></figure>

> You can also create a segment under Target Audience > Segments > Create section in the left panel. Select the User Properties, Session Properties, and events performed by the users. Then enter the name of your segment and click save.

### Cohort

If you chose Cohort of users, you could select the user cohort from the dropdown below “select or upload new cohort”. To further drill down the Cohort, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/qhAi0qKew5rcCugSjZyC" alt=""><figcaption></figcaption></figure>

#### Create Cohort

There are three ways to create a cohort

1. Upload a new cohort from the dropdown while selecting a cohort. Upload a csv file up to 50 MB, name your cohort, then click upload.
2. From **Target Audience > Cohorts > Upload** section in the left panel. Upload a csv file up to 50 MB and name your cohort.
3. From the **Target Audience > Segments** section, you can create a cohort from any segment. Click on the segment you want to create a cohort for, in the dropdown, select the date range and click on **Go.**

### Advanced Filters

You can further target users by their User journey, Attributes, and App Version in the app by selecting Advanced Filters.

<figure><img src="/files/JcWpzesdHXz0TgFRvWXp" alt=""><figcaption></figcaption></figure>

#### User Timeline

You can target users based on the user journey in the app by selecting the retention day. For example, you can show the campaign only to users in the first week of using the app by selecting Day 0 to Day 7. Additionally, you can select the range of sessions the user should have in the app so that the campaign can be displayed to him. For example, you can create a campaign that should be shown to the user only during their first 5 sessions in the app.

<figure><img src="/files/HCHSjHgkIxstTuSRQGoj" alt=""><figcaption></figcaption></figure>

#### User Properties

You can target users based on their User properties. User properties include unique user identifying information, such as their name, phone number, signup date, etc. You can select the user property Name, Data Type (whether it is a String, Numeric or Decimal), the logical operator, and the Value.

<figure><img src="/files/qLAvELJ097Qqm0RzVrdW" alt=""><figcaption></figcaption></figure>

#### Session Properties

You can Target Users based on Session properties. A Session can be simply defined as a user journey as he opens the app until he closes the app. Various pieces of information can be very impactful when accumulated in a session, for e.g., location of the user, language, etc.

<figure><img src="/files/4K7IZlGszeg35JEGM4sO" alt=""><figcaption></figcaption></figure>

> **User Properties vs. Session Properties**
>
> * User properties refer to the user’s information, which remains constant throughout the user’s journey in the app. eg. Name, Phone no, etc.
> * Session properties are the values that keep changing for every new session a user does in the app. eg. location, network, etc.

#### Build Number

You can target users based on their App Version. Please note while entering the App Version, the build number needs to be given instead of the Version number.

<figure><img src="/files/RJsi3TauGhqgf5Rt2JWx" alt=""><figcaption></figcaption></figure>

### Campaign Control Group

You can select the percentage of users for whom the campaign should not be shown. This feature will randomly exclude *x*% of users from the campaign. By default, the campaign control group is set to 3%. Using this feature, you can compare the number of users reaching the goal event with and without nudges.

<figure><img src="/files/thaV1JMGUYZ2cSwrM0Hx" alt=""><figcaption></figcaption></figure>


# Trigger

In this section, you can set the contextual conditions as to when to trigger the campaign for live users. Start by clicking on “Add Event”.

<figure><img src="/files/faH9Yv7CHvrSzXRAv7Cf" alt=""><figcaption></figcaption></figure>

## Event Conditions

* Firstly, pick the right trigger for your campaign to be shown to the users.
* You can choose whether the user “did” or “didn’t” perform the action.
* You can choose between app activity/screen, app event, or Client Event as your trigger from the drop-down button.
* You can also set the number of times the trigger must be performed along with the relevant operator (>, <,>=,<=,=,!=).
* You can also add multiple event properties to this event along with its values.
* Multiple events can be added in the trigger section by clicking “Add Another Event”.

## Combination of Multiple Conditions

You can change the conditions between any two steps. For example, users who did step 1 **AND** step 2 or did step 1 **OR** step 2 or did step 1 **AND THEN** step 2. Any combination of the AND or OR conditions can also be used. For example, users did step 1 AND step 2 OR Step 3.

### OR Condition

For a media streaming app, the user can be nudged to buy the subscription based on the condition that either the user listens to 3 songs or watches 3 videos. In this case, the trigger conditions will be,

> When user **did** **SongListened** for **== 3** times
>
> **OR**
>
> When user **did** **VideoWatched** for **== 3** times
>
> These two events can be in any order, and in between these two events, any number of events may take place.

### AND Condition

For an e-commerce app, the user can be nudged to view the cart page based on the conditions that the user lands on the home page and adds an item to the cart. In this case, the trigger conditions will be,

> When the user **did HomePageOpen** for **≥** **1** times
>
> **AND**
>
> When user **did AddedToCart** for **== 1** times
>
> These two events can be in any order, and in between these two events, any number of events may take place.

### AND-THEN Condition

For an e-commerce app, the user can be presented with a feedback survey for an item, if the user first adds the item to the cart and then removes the item from the cart. In this case, the trigger conditions will be,

> When the user **did AddedToCart** for **≥ 1** times
>
> **AND THEN**
>
> When user **did RemovedFromCart** for **== 1** times
>
> The order of these events should be exactly as mentioned, however, any number of events can be triggered in between.

## Goal Event

The goal event of the campaign, as the name suggests, is the event that indicates the campaign’s success. This lets us measure the campaign’s success effectively.

**Eg.** For a media streaming app, **SubscriptionSuccess** can be termed as the goal event.


# Schedule and Limit

Under the Schedule tab, you will be able to customize the schedule and limits of the Campaign.

### Schedule

Under Schedule, you can set the campaign duration that specifies how long the campaign should be active. Enabling the “Show at Specific Time of the day” allows you to decide the timings at which the campaign must be shown to the user. If you chose a specific time period of the day based on your users' active time, the conversion rate will increase.

<figure><img src="/files/pRXAV1Kpqd83WYPHzObQ" alt=""><figcaption></figcaption></figure>

### Refresh users in Segments

This option must be enabled only when using “Segments” in your target audience. You can specify if the campaign’s target users should be re-evaluated every n number of hours, days, or weeks while the campaign is active. For example, you can refresh the users in the segment and display the campaign to be shown every day.

### Limit to Displaying

Finally, set the campaign display limit conditions by selecting the maximum number of times a campaign can be displayed to a user, either per session or overall. To further drill them down and get to the specifications, you can enable the Day and Session Limits to specify how many times it can be shown per session and per day.

<figure><img src="/files/KrdhKTgxYO4SWJ9d2gbO" alt=""><figcaption></figcaption></figure>


# Review and Test

Under the Review Tab, you will be able to see an overall summary of the campaign created. You can click on the “Edit” options next to each section box if any changes are needed.

To test the campaign on your test devices, click on “**Test**” in the top right corner. Select the device(s) from the drop-down menu under “Select your test devices” on which the testing needs to be performed, and click on “Launch Testing”. Click on “Register New Device” at the bottom of dropdown if your device is not listed. [Click here](/product-guides/adding-a-test-device) for other methods to register your device.

**NOTE:** For a final confirmation the trigger events are mentioned in the Test Campaign Screen. In case you want to change the trigger events, you can close the test campaign popup and go back to Configuration, or else it can be ignored

<figure><img src="/files/H68nDotP7YEiGYQ1PWfm" alt=""><figcaption></figcaption></figure>

Once you click “**Launch Testing**”, the campaign is auto-saved and will be taken back to the [Campaign Listing Page](/product-guides/create-a-campaign/mobile/campaign-listings-page), wherein you can see the campaign name and details in the Drafts.

To test the campaign on your device, open your app and ensure you meet the set context to trigger and launch the campaign.


# Set Priority and Publish

If you're happy with the look of your campaign and want to post it to your users, you should publish your campaign. Click on the "Publish" CTA on the top right corner to publish the campaign.

To Publish a campaign from the listings page, click Edit CTA under the Actions section on the [campaigns listing page](/product-guides/create-a-campaign/mobile/campaign-listings-page). You will be redirected to the campaign "Review" Screen, where you have an option to "Publish" the campaign in the top-right-hand corner.

Once you click on Publish, a pop-up box will appear asking to set the priority for this campaign. The pop-up will show all the previously created campaigns that satisfy both the following conditions:

1. The scheduled time for the campaign has an overlapping time interval with the newly created campaign.
2. The set of events used for triggering the campaigns has some common events.

   Consider the following example,

   * Campaign 1 is scheduled between 22 Apr 2023, 19:00 - 25 Apr 2023, 18:00, and Campaign 2 is scheduled between 25 Apr 2023, 15:00 - 01 May 2023, 15:00.
   * The triggering events for Campaign 1 are Add\_To\_Cart\_Clicked **OR** Item\_Description\_Clicked
   * The triggering event for Campaign 2 is Add\_To\_Cart\_Clicked

   <figure><img src="/files/1CZasyZl2cbJvsUFwqEp" alt=""><figcaption></figcaption></figure>

Then you need to set the priority order between these two campaigns. The campaign with the highest priority will be triggered in case of a conflict. Click and hold the six dots at the left of your campaign name and drag below in your preferred priority order. The topmost is the highest priority, and the bottom is the lowest. You can shuffle the order till you click on Next. After setting the priority order, click on the Next button; you will be asked for confirmation. Click on the Back button if you want to change the priority order. Click the Next button to confirm, and your campaign will be live at the scheduled time.

<figure><img src="/files/GRwsdjj05CDN3cyH6rWw" alt=""><figcaption></figcaption></figure>


# A/B Testing

### What is A/B Testing, and what do we offer

A/B testing can be helpful in determining the most effective nudges or campaign designs. A/B testing is a process in which we compare two or more than two variants of a digital nudge or campaign design to see which one performs better in goal event conversion. We distribute the users randomly among the variants and measure how many complete the goal event for each of the variant.

Let's say we want to encourage users to sign up for a newsletter. We might create two versions of a nudge: one with a simple message and a bright orange button and another with a longer message and a blue button. We would randomly show each version to users from different groups and measure how many sign up for the newsletter.

The results of A/B testing allow us to make data-driven decisions, about, which nudges are most effective. We can then use this information to optimize our nudges and create better user experiences.

Using A/B testing on our platform, we can help you create digital nudges that drive behavior change and improve user outcomes. We provide the following features of A/B testing:

* Ability to experiment between design variations
* Ability to experiment between flow variations
* Target Experiment Group selection: Randomized selection of the target group for the experimentation. Ideally, experimentation need not be done on all users.
* Variants Split along with Control Group: Can choose the variants’ split among the target users.
* Completely Randomized Variant Allocation: The variants will be allocated to users in a randomized manner so that the results will not be biased. Once a user allocated a variant for a campaign, he will not be shown any other variant throughout the campaign period. It avoids the cascading effect.

{% hint style="info" %}
**Control Group is Mandatory for A/B Testing**

A/B testing is a method that compares two variations of a feature, message, advertisement, or other user experience. However, many people overlook the importance of a control group. In reality, A/B testing should be called A/B/C testing, where "C" represents the control group. If a business is looking for the best solution for a new implementation, it should definitely use A/B testing. However, for the experiment to be effective and achieve real success, measuring outcomes against a benchmark is absolutely essential and the control group is the most effective benchmark to utilize.
{% endhint %}

* Goal Event Selection: To decide the winner of the variants, choose a goal action that indicates the success of the campaign. It helps in measuring the effectiveness of the variants.
* Auto / Manual Publish Winner: Once the experiment is done, one can opt for rolling out the winner variant to all the users in case of the statistically significant winner is concluded. Otherwise, the winner variant will not be published.
* A/B Results: We use the Bayesian A/B to the Frequentist approach as it has its own advantages, especially when smaller samples are available. For each variant, the following are available
  * Campaign Viewed Users
  * Converted Users (did perform the goal event)
  * Conversion Percentage
  * Overall Improvement over the Control Group
  * Chance to be a winner
  * Chance to beat the control
  * Expected Loss
  * Expected Improvement
  * All the other metrics that are for a campaign

### Getting Started with A/B Testing

<figure><img src="/files/3nTYIUAiGfl6JMWixpLb" alt=""><figcaption></figcaption></figure>

* Creating an A/B Test campaign in Apxor is short and simple. Click on the A/B icon in the top right corner.
* In the pop-up that appears, enter the name for this variant of design and click on Add
* Click on the Black "plus" ➕ icon to add another variant.
* Select the variants from the top bar and start adding templates to it.


# Campaign Listings Page

Once you click on Campaign in the left panel you will land on the campaign listings page.

<figure><img src="/files/Q4GLtRkNPFbM16Ttlrji" alt=""><figcaption></figcaption></figure>

**Campaign Name:** The campaign's name and description/Tag in the grey background box.

**Created Date:** The creation date of the campaign.

**Start Date:** The start date of the campaign. (there is a sort option given to you for the start date, wherein you can sort them in descending or ascending order. Hover over the **Start** text and click on the arrows that appear).

**End date:** The end date of the campaign (along with a sort option)

**Actions:** Under Actions, we have following activities

<figure><img src="/files/h2ifiWpuJvt3UTA5jEKf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/v9we9e60Y0T2iF8O5FGF" alt=""><figcaption></figcaption></figure>


# Campaign Analytics

Once you click on the analytics symbol on the campaign listing page, you will be redirected to the campaign analytics page. This dashboard consists of numbers and graphs depicting various information about the campaign.

<figure><img src="/files/ZCzBfe48xWomDgozKKqq" alt=""><figcaption></figcaption></figure>

* ***X*****&#x20;Users:** Users that are shown the campaign
* ***X*****&#x20;Conversions:** Users who have done the goal event after the campaign is shown
* ***X*****% Conversion Rate:** Percentage of Conversion
* Comparison of all the above with the Control Group ( Only those who have done the trigger but the campaign is not shown intentionally. This gives you perfect comparison)

<figure><img src="/files/7kE4GQ3UwiXa47Jo598C" alt=""><figcaption></figcaption></figure>

* Funnel of the steps in a multistep walkthrough
* Day wise Steps conversions
* Conversions of the primary and secondary goal events
* Day Wise Goal event conversions
* Comparison of the following KPIs among the users who have shown that specific campaign and ALL users. The first bar in the graph is for all users, and the second bar for the users in this campaign.
  * **D1 Retention**

    Day 1 Retention is a metric that measures the percentage of users who continue to use your website or application one day after their installation. A user is considered retained if on **Day0** the user performs the event **install** and on **Day1** the user did **apx\_app\_opened** event i.e. the user opens the app.
  * **D0 Uninstalls**

    Day 0 Uninstalls represent the percentage of users who uninstall or delete your application immediately on the same day of their installation. When the user performed the event **install** and **uninstall** within same day (00:00 to 23:59)
  * **Average Number of Sessions**

    Average Sessions Per User is a metric that calculates the average number of unique sessions or interactions individual users have within your website or application over a day.
  * **Average time spent in a session**

    Average time spent in a session Per User is a metric that calculates the average number of unique sessions or interactions individual users have within your website or application over a day.


# Campaign Designs

Campaigns in the Apxor dashboard let you create and launch nudges like **Tooltips**, **Coachmarks**, **Badges**, and **In-App Messages** on the fly. A campaign can be a single nudge or a multi-step walkthrough, or a combination of any or all the nudges. You can use the Apxor Product Intelligence platform to uncover actionable insights to create campaigns or launch actions based on any use case, hunch, or requirement.

<figure><img src="/files/Dii7ppHgvGYlFiEgU06t" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Tooltips</strong></td><td></td><td><em>Tooltips are short helpful inline messages that anchor text to a UI element and give contextual information to a user without taking up the entire app screen.</em></td><td><a href="/files/kVw8QW0Bo30LWqH3CSI5">/files/kVw8QW0Bo30LWqH3CSI5</a></td><td><a href="/pages/gwlLgcMUlbyveeNwTpvo">/pages/gwlLgcMUlbyveeNwTpvo</a></td></tr><tr><td align="center"><strong>In-App Messages</strong></td><td></td><td><em>In-App messages grab a lot of user attention and allow you to easily communicate with your users via announcements, offers, etc., and prompt actions.</em></td><td><a href="/files/vws6DlhAiBAHDbYYcEbo">/files/vws6DlhAiBAHDbYYcEbo</a></td><td><a href="/pages/Gi4ry28zVHgF7Um8lHan">/pages/Gi4ry28zVHgF7Um8lHan</a></td></tr><tr><td align="center"><strong>Coachmarks</strong></td><td></td><td><em>A coachmark is a powerful tool that works well as part of tutorials, improving feature adoption and directing user attention to a particular screen section.</em></td><td><a href="/files/y7m3kucamTrpcMi7YmeC">/files/y7m3kucamTrpcMi7YmeC</a></td><td><a href="/pages/wgRO42eK8CXgODeMPd3t">/pages/wgRO42eK8CXgODeMPd3t</a></td></tr><tr><td align="center"><strong>Badges</strong></td><td></td><td><em>A nudge/badge is a subtle way of grabbing and directing the user’s attention to any part of the app screen.</em></td><td><a href="/files/kWnHfMv4cQiaDjntxJQN">/files/kWnHfMv4cQiaDjntxJQN</a></td><td><a href="/pages/3kg9vhyEhWkYArOgerhS">/pages/3kg9vhyEhWkYArOgerhS</a></td></tr></tbody></table>

Get started by creating your first [campaign](/product-guides/create-a-campaign/mobile).


# Tooltips

{% embed url="<https://youtu.be/EkV_SIzxFS8>" %}

Tooltips are short helpful inline messages that anchor text to a UI element and give contextual information to a user without taking up the entire app screen. You can choose any of the following templates for tooltips:

### Basic Text

This template is a combination of a title and description with up to 2 buttons.

<figure><img src="/files/qGshQ2aNZJKgz0SqLyHf" alt="" width="375"><figcaption></figcaption></figure>

### Basic Text + Image

This template contains an image, a title, and a description with up to 2 buttons.

<figure><img src="/files/TAi1VqSgn0BdfaQj494w" alt="" width="375"><figcaption></figcaption></figure>

### Short Menu

This template consists of up to 3 buttons with icons and descriptions.

### Customizations

Each of these 3 tooltips can be customized as per the need. The available customizations for the same are as below:

<details>

<summary>Element Selection</summary>

* By Element ID
* By Customized Tag
* By Path
* By text filter in the element's content (android only) : For example, some cards in the viewport share the same id but will change from user to user. Then you can choose the element on which an element highlighter should be shown by selecting the common id and a filter for what to search.

</details>

<details>

<summary>Design</summary>

1. Container
   * Fill Color
   * Gradient
   * Radius
2. CTAs
   1. Number of Buttons: 0, 1 or 2
   2. Button Fill: None, Solid
   3. Button Fill Color, Gradient
   4. Button radius (Rounded Rectangles)
   5. Action Options:
      * Dismiss the current step
      * Cancel the entire walkthrough
      * Redirect through
        * Activity
        * Deeplink
        * Key Value Pairs

</details>

<details>

<summary>Text</summary>

1. Font Size and Color
2. Custom Font (any font that is an asset of the app)
3. Font Style (Italic, Bold, Strike Through)
4. Localized Formatting: Customize different parts of your text in various formats. Split into your desired number of lines etc.
5. Dynamic Text: We can read and present any of the values of
   * User properties
   * Session Properties
   * UI element in the front end
   * Response from an API call
6. Dynamic Script: We can perform the mathematical and logical operations between the values read from the above 4 sources using a few lines of code.

</details>

<details>

<summary>Effects</summary>

* Auto Dismiss after *X* seconds
* Dismiss on Outside touch on the screen
* Dim Background with Color and Opacity
* Waiting time for rendering: Useful in screen stabilization
* Animation Effect with configurable speed

</details>

<details>

<summary>Close Icon</summary>

You can choose if you want a close icon at the top-right corner of a tooltip

1. Type
   1. Normal
      * Icon color
   2. Filled
      * Icon color
      * Fill color
      * Shape: Rectangle, Circle
   3. Custom
      * Provide a url path to a custom icon image
2. Actions :&#x20;
   * Cancel the entire walkthrough
   * Dismiss the current step and continue the walkthrough
3. Offset : Move position from **Top** and **Right**
4. Change **Height** and **Width** of icon

</details>

## Create a mobile campaign

Go back to creating a [mobile campaign](/product-guides/create-a-campaign/mobile).


# In-App Messages

In-App messages grab a lot of user attention and allow you to easily communicate with your users via announcements, offers, etc., and prompt actions.

{% embed url="<https://youtu.be/KQWqoBRWA0w>" %}

### Top Banner

This template sticks to the top of your app screen and allows a title, description, icon, and upto two buttons.

* You can choose whether to include a image icon in the template or not.
* You can select either 1 or 2 number of CTA buttons.
* You can also dim the background.

<figure><img src="/files/FXYDvLL7fIfMvcLctjCg" alt="" width="375"><figcaption></figcaption></figure>

### Footer

This template sticks to the bottom of your app screen and allows a title, description, icon, and upto two buttons.

* You can choose whether to include a image icon in the template or not.
* You can select either 1 or 2 number of CTA buttons.
* You can also dim the background.

<figure><img src="/files/nr4OQbbH65ODjQf9ebyE" alt="" width="375"><figcaption></figcaption></figure>

### Center Modal

The Center Modal template is a great option for drawing attention to a specific message or offer. It includes an image, title, and up to two buttons, and can be customized to show just the image if desired. This template looks like a pop-up and is perfect for prompting users to take action.

* If you are using just the image option then the CTA actions of dismiss, redirect and cancel will be applicable on tapping the image.
* You can also dim the background.

<figure><img src="/files/tWCAkbD7FplupEDuWIXa" alt="" width="375"><figcaption></figcaption></figure>

### Full Screen Cover

The Full-Screen Cover template is ideal for displaying larger images and messages. It takes over the entire screen of your app and includes a title and up to two buttons.

* If you are using just the image option then the CTA actions of dismiss, redirect and cancel will be applicable on tapping the image.
* You can also dim the background.

<figure><img src="/files/DLvs3B5b3oprt8dgL6fK" alt="" width="375"><figcaption></figcaption></figure>

### Carousel

This template allows you to create an in-app slideshow with a maximum of 5 images

* You can also dim the background

<figure><img src="/files/GuncMm0h6sumTESOZQrD" alt="" width="375"><figcaption></figcaption></figure>

### Custom HTML

{% embed url="<https://youtu.be/_zh5FdeuiMU>" %}

The custom HTML option allows for even more flexibility in designing in-app messages. With this option, you can create your own template using HTML and CSS. This is a great option for those who want complete control over the design of their in-app messages. You can also customize various aspects of the in-app message, including the container design, CTAs, text, and effects, to ensure that your message is eye-catching and effective.

### Customizations

<details>

<summary>Design</summary>

</details>

<details>

<summary>Text</summary>

* Font Size and Color
* Custom Font (any font that is an asset of the app)
* Font Style (Italic, Bold, Strike Through)
* Localized Formatting: Customize different parts of your text in various formats. Split into your desired number of lines etc.
* Dynamic Text: We can read and present any of the values of
* * User properties
  * Session Properties
  * UI element in the front end
  * Response from an API call
* Dynamic Script: We can perform the mathematical and logical operations between the values read from the above 4 sources using a few lines of code.

</details>

<details>

<summary>Effects</summary>

* Auto Dismiss after X seconds
* Dim Background
* Waiting time for rendering: Useful in screen stabilization

</details>

## Create a mobile campaign

Go back to creating a [mobile campaign](/product-guides/create-a-campaign/mobile).


# Coachmarks

{% embed url="<https://youtu.be/kQrHD_ArA0o>" %}

A coachmark is a powerful tool that works well as part of tutorials, improving feature adoption and directing user attention to a particular screen section. Select the informative spotlight template to showcase a coachmark.

<figure><img src="/files/VNIQ5UjrZ3qbILerKQwx" alt="" width="375"><figcaption></figcaption></figure>

### Customizations

* Make the coachmark circular or rectangular.
* Have arrow directed towards the UI element.
* Select 0, 1 or 2 number of buttons.
* Select a ripple animation
* Select the position of the coachmark with respect to the UI element from top, right, bottom and left options.
* Change the opacity of the coachmark in the range of 10 to 100%.
* Dismiss on touch outside.
* Delay the campaign rendering

## Create a mobile campaign

Go back to creating a [mobile campaign](/product-guides/create-a-campaign/mobile).


# Badges

{% embed url="<https://youtu.be/ziwGvnU55B0>" %}

## Simple Badge(Legacy)

The Simple Badge Legacy template is a small circular dot that can be positioned at the Left, Right, Top Center and Center of the UI element. You can also change the color of the dot. You can enable animation for the dot, which is a slight up-and-down motion for the dot. You can select the number of seconds to delay the campaign being shown after the trigger condition is met.

<figure><img src="/files/47CsX3qnTZ39meeGgcVA" alt=""><figcaption></figcaption></figure>

## New Badges

The new badge templates come with more config options. You can achieve all the templates starting from any of them.

### Templates

#### 1. Simple Badge

By default, the Simple Badge template is a circular red dot at the top-right position of the UI element.

The general use of this template is to draw the user’s attention to click a CTA associated with the UI element.

#### 2. Static Badge

By default, the Static Badge is a capsule-shaped nudge with the text **NEW** written on it at the top-right position of the UI element.

The general use of this template is to make the user try out a newly launched feature.

#### 3. Badge with Label & Icon

By default, the badge with label template, as the name suggests, is a capsule-shaped nudge with the text label written on it and an icon at the top-right position of the UI element.

#### 4. Offer Badge with Background Image

By default, the Offer Badge with Background Image template has a blue colored background image with the text Offer 8% written on it.

The general use of this template is to attract the user with an ongoing offer.

## Configuring a Badge

Select any of the badge templates, and you’ll land on the design page. You can see the Edit Design section on the right side of the dashboard. You can also click on the badge in design to open the configuration options palate.

<figure><img src="/files/p9mWesAWJvmodtH2VtzJ" alt=""><figcaption></figcaption></figure>

#### Background Type and Size

You can choose between shape and image as the background type. You can also configure the size of the nudge. Once you click on the in-place design of nudge, a pop-up with config options will open, where you can select the shape as a circle or rectangle or provide an image URL for a background image.

You can also configure the color, corner radius, stroke, and stroke color and provide an offset for the nudge.

<figure><img src="/files/JlrR7S2ydOcQWhZaXpO0" alt=""><figcaption></figcaption></figure>

#### Position

You can place the nudge in the Top Right, Top Left, Top Center, Bottom Right, Bottom Left, Bottom Center, Left, Right and Center positions with respect to the UI element.

#### Label and Icon

You can write text on the nudge and also add an icon.

<figure><img src="/files/o43Eu2ycvz3xTMT6DERx" alt=""><figcaption></figcaption></figure>

Once enabled, click on the text in design to be able to use the font config options. You can select the position of the text with respect to the icon. You can also configure the font type, font color, font size, alignment and margin.

<figure><img src="/files/vMg3LNeaFQDRw9UfKAzI" alt=""><figcaption></figcaption></figure>

After clicking on the icon in design, you can provide the icon URL, configure the icon size, and provide a margin.

## Stop Conditions for Badges

You can decide to stop showing the badge to the end user based on the four scenarios below. Once you have finalized the design and moved to the Target section on the dashboard, you will find the Stop Conditions section at the bottom.

<figure><img src="/files/M0A5K6w6jT3phDscyFeq" alt=""><figcaption></figcaption></figure>

#### User Property

You can stop showing the badge once a specified user property gets updated.

1. Click on the checkbox for User Property
2. Select the user property from the dropdown
3. Select the user property value; the badge should no longer be displayed upon achieving this.

eg.

&#x20;   **subscription\_type** updates to **paid**

&#x20;   **app\_version** updates to **2.0.03**

#### Goal Event

You can choose to stop showing the badge once the specified goal event of the campaign is triggered.

eg.

**purchase\_complete** is triggered

**level\_up** is triggered

#### After *x* days since the badge is shown for the first time

You can set a condition to stop showing the badge after a certain number of days have passed since the badge was first shown. This can be helpful if you want to display the badge for a limited amount of time before removing it from the UI element.

#### Click on the target element

You can stop showing the badge once the user clicks on the targeted UI element.

## Create a mobile campaign

Go back to creating a [mobile campaign](/product-guides/create-a-campaign/mobile).


# Web

You can start designing the campaign by adding templates by clicking on the ➕ icon on the left side. Select a suitable [template](/product-guides/create-a-campaign/web/web-templates) for you and get going.

## CTAs on the Dashboard

On the top right corner of the Dashboard you have four CTAs for tooltips and three CTAs for modals

1. Launch URL
2. Configure
3. Edit
4. Save

<figure><img src="/files/ZQHvremdrZh8or7gqBIs" alt=""><figcaption></figcaption></figure>

## Launch URL:

After clicking the Launch URL icon, you will be asked to enter the URL of your pre-integrated website. You can then select the UI elements after enabling the web view detector from the top right corner.

<figure><img src="/files/dTUby3oMIYjuAz05VA1C" alt=""><figcaption></figcaption></figure>

## Configure:

After clicking the configure icon, you can use the Edit Design section to configure your template.

### Edit Design Section (Modals)

<figure><img src="/files/tyI0clfAoCsd4pMU4ISN" alt=""><figcaption></figcaption></figure>

1. **Direction**

   Choose the alignment of text and buttons as either vertical or horizontal.
2. **Close Icon**

   You can select whether to include the close icon in the template or not.
3. **Title Icon**

   You can also add an icon to the left of the title.
4. **Media Type**

   You can select the media type you want in your modal from 4 options.

   **None**: No media item, just Title, Description and two Buttons

   **Icon**: A small icon along with Title, Description and two Buttons

   **Image**: An image along with Title, Description and two Buttons

   **Video**: A video along with Title, Description and two Buttons

   You can place the media on top of the text or on the left of the text.
5. **Width**

   You can use the slider to adjust the width of the template. The height will be automatically adjusted according to the width to maintain the aspect ratio.
6. **Position**

   You can select the position at which you want to place the template on the screen. You have options from Center, Top Left, Top Right, Bottom Left and Bottom Right.
7. **Dim Background**

   You can choose if you want to dim the background behind the template. You can also select the background color and opacity percentage.
8. **Dismiss Config**

   You can set the template to dismiss on touch outside the template and auto dismiss after *x* seconds.
9. **Delay**

   You can set the template to be shown after *x* seconds from the context being met.

### Edit Design Section (Tooltips)

<figure><img src="/files/aW7UlvdVQSVwfvRcWyGU" alt=""><figcaption></figcaption></figure>

1. **Direction**

   Choose the alignment of text and buttons as either vertical or horizontal.
2. **Close Icon**

   You can select whether to include the close icon in the template or not.
3. **Title Icon**

   You can also add an icon to the left of the title.
4. **Arrow Type**

   You can choose the arrow type of the tooltip which points to the UI element from the six available options. Normal, Round, Narrow, Large, Small and Wide.
5. **Media Type**

   You can select the media type you want in your modal from 4 options.

   **None**: No media item, just Title, Description and two Buttons

   **Icon**: A small icon along with Title, Description and two Buttons

   **Image**: An image along with Title, Description and two Buttons

   **Video**: A video along with Title, Description and two Buttons

   You can place the media on top of the text or on the left of the text.
6. **Width**

   You can use the slider to adjust the width of the template. The height will be automatically adjusted according to the width to maintain the aspect ratio.
7. **Position**

   You can select the position at which you want to place the template on the screen. You have options from Center, Top Left, Top Right, Bottom Left and Bottom Right.
8. **Animation**

   You can enable animation for the tooltip and set the animation duration. The animation is a slight up and down movement of the tooltip.
9. **Dim Background**

   You can choose if you want to dim the background behind the template. You can also select the background color and opacity percentage.
10. **Dismiss Config**

    You can set the template to dismiss on touch outside the template and auto dismiss after *x* seconds.
11. **Delay**

    You can set the template to be shown after *x* seconds from the context being met.

## Edit UI element

After clicking on this edit icon you will be shown the **Select UI Element** modal, edit the URL and click on **Launch URL.** Reselect the UI element you want in the new tab that opens. Come back to this tab and click on Proceed.

<figure><img src="/files/YBzrNkA4XhsRO3pFRztj" alt=""><figcaption></figcaption></figure>

## Save Template:

After clicking the Save this Template icon, you will be asked to enter the name for this template which will then be stored under your saved templates. Use this option to save your configured template for further use in other campaigns.

You can access your saved templates while selecting a template by clicking on the Saved Templates CTA as shown in image below.

<figure><img src="/files/GjBnVXh7sED5UXANuAf6" alt=""><figcaption></figcaption></figure>

## In-Place Editing

You can click on the items in the template to use the edit options available. You can also remove an item by hovering on it and clicking on the delete icon that appears at the top left corner of that item.

<figure><img src="/files/1T9MzjR2Iq05Emlgdz34" alt=""><figcaption></figcaption></figure>

To add the removed item again hover over the template and click on the pencil icon visible in the above image.

### Title Config

<figure><img src="/files/hV6Wtbd0CSjTsPyFqOAH" alt=""><figcaption></figcaption></figure>

Once you click on the Title text, you will get the Title config pop-up.

You can find the options to edit the text, font size, font color, text alignment, font weight(normal or bold), font style(normal or italic), font type among others.

You can also use Dynamic Text in the Title to personalize it based on user properties.

You can use the Text Paddings options to position your text at the desired position in the template.

### Description Config

<figure><img src="/files/duJiEm83SGDiItteRwui" alt=""><figcaption></figcaption></figure>

Once you click on the Description text, you will get the Description config pop-up.

You can find the options to edit the text, font size, font color, text alignment, font weight(normal or bold), font style(normal or italic), font type among others.

You can also use Dynamic Text in the Description to personalize it based on user properties.

You can use the Text Paddings options to position your text at the desired position in the template.

You can check the text scrollable checkbox if you have a large description text and want to make the text scrollable without disturbing the size of the template container.

Slider can be used to vary the height of the scrollable text box. You can enable the border for the scrollable box and change the border color, border width and select the border style (solid, dashed or dotted).

### Background Config

<figure><img src="/files/MFMhQq5qjyH0hCP2OLrO" alt=""><figcaption></figcaption></figure>

You can change the background color, paddings from top, right, bottom and left.

You can enable the shadow for the template container, change the shadow color, set the offset, vary the blur effect and set the spread amount.

You can choose to enable the border for the template container, vary the border width, border radius, change the border color and choose the border style(solid, dashed or dotted).

### Button Text Config

<figure><img src="/files/HMm3YuSebkIQlOcRvJxf" alt=""><figcaption></figcaption></figure>

Once you click on the Button text, you will get the Button Text Config pop-up.

You can find the options to edit the text, font size, font color, font weight(normal or bold), font style(normal or italic), font type among others.

You can also use Dynamic Text in the Title to personalize it based on user properties.

You can use the Button Text Paddings options to position your text at the desired position in the button.

### Button Config

<figure><img src="/files/GHGmlKyRa1yuhXD6qsA3" alt=""><figcaption></figcaption></figure>

Once you click on the Button background, you will get the Button Config pop-up.

You can choose button type(filled or none), background color of the button, button margins(top, right, bottom and left), button paddings(top, right, bottom and left).

You can enable button border, set the border width, border radius, border color and border style(solid, dashed or dotted).

You can choose the button action(dismiss, cancel or redirect). Cancel action cancels the entire walkthrough. Dismiss action dismisses the current step and continue with the remaining walkthrough. You can select whether to open the redirection URL in same tab or new tab.

### Icon Config

<figure><img src="/files/TKISi9JoW3fdbMciDG28" alt=""><figcaption></figcaption></figure>

Once you click on the Icon, you will get the Icon Config pop-up.

You can enter the icon URL, set the icon width, icon height, icon alignment(start, center or end).

You can enable border, set the border width, border radius, border color and border style(solid, dashed or dotted).

### Image Config

<figure><img src="/files/paQs5rDloOXw0fSBqqHY" alt=""><figcaption></figcaption></figure>

Once you click on the Image, you will get the Image Config pop-up.

You can enter the image URL, set the image aspect ratio in terms of width x height.

You can enable border, set the border width, border radius, border color and border style(solid, dashed or dotted).

### Video Config

<figure><img src="/files/HDg62iJ803GFwsX05qlt" alt=""><figcaption></figcaption></figure>

Once you click on the Video, you will get the Video Config pop-up.

You can enter the mp4 video URL path, set the video aspect ratio in terms of width x height.

You can enable border, set the border width, border radius, border color and border style(solid, dashed or dotted). You can choose whether to enable the audio or not.

### Close Icon Config

<figure><img src="/files/1IgAd5a0STAlDSyv9fun" alt=""><figcaption></figcaption></figure>

Once you click on the Close Icon, you will get the Close Icon Config pop-up.

You can select the icon type(normal, filled or custom). You can enter your custom icon URL if you select icon type as custom. You can select the action as either Cancel or Dismiss. Cancel action cancels the entire walkthrough. Dismiss action dismisses the current step and continue with the remaining walkthrough.

You can set the icon color, fill color and shape of the icon(rectangle or circle).

You can resize the icon and use the offset options to position the cross icon as per your need.

## Preview on Device

You can select the test device from the bottom and click “**Preview on device**” to view the nudge on your test device.

### Next Steps in Campaign Creation

{% content-ref url="/pages/LxW02nE43JohfJyZb2Wu" %}
[Target](/product-guides/create-a-campaign/web/target)
{% endcontent-ref %}

{% content-ref url="/pages/GRnUlNSe4P4jVWPTmNN0" %}
[Trigger](/product-guides/create-a-campaign/web/trigger)
{% endcontent-ref %}

{% content-ref url="/pages/FlSw2juZwp17WF4YnA31" %}
[Schedule and Limit](/product-guides/create-a-campaign/web/schedule-and-limit)
{% endcontent-ref %}

{% content-ref url="/pages/Sb8dS1XSNsbVtOEdSFcf" %}
[Review and Test](/product-guides/create-a-campaign/web/review-and-test)
{% endcontent-ref %}

{% content-ref url="/pages/2HXFKVLhNNP40frXS0Ax" %}
[Set Priority and Publish](/product-guides/create-a-campaign/web/set-priority-and-publish)
{% endcontent-ref %}


# Target

Start by selecting your target users – whether you want to aim the campaign to “All Users”, “Segment” of Users, or “Cohort” of users.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPtrkJ3vMAFJUXSFiqzDo%2Fuploads%2Fb3fQt9733qx3m42H5psr%2FTarget.gif?alt=media&#x26;token=9ff3e086-fde6-4767-8205-095e174407f3" alt=""><figcaption></figcaption></figure>

### All Users

If you choose all users, you can also select an app event that users did not do in their lifetime to narrow down the target audience from the drop-down.

<figure><img src="/files/FA88SsfTLEXcfGBVskrp" alt=""><figcaption></figcaption></figure>

> **Segment vs Cohort**
>
> * A "**Segment**" is a group of consumers who share similar characteristics such as age, income, geographic location, or purchasing behavior. Marketers often use consumer segments to identify and target specific groups of consumers with tailored products, messaging, and marketing strategies.
> * A "**Cohort**" is a group of individuals sharing a common characteristic or experience within a defined period. In the context of consumer behavior, a cohort might refer to a group of individuals who were born in a certain year, graduated from college in a certain year, or who first purchased a product during a specific time period. Cohorts can be useful for understanding a group of consumers' purchasing patterns and behaviors over time.

### Segment

If you choose a segment of users, you can select the user segment from the drop-down below “Select Segment”. By selecting the segment, you will be able to see the segment details below. You can also specify the time period during which you want to select the users in that segment, it can be Between 2 date ranges or in the “Last” in the previous day(s). To further drill down the segment, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/Nep1LClSzTfY5a48RfLp" alt=""><figcaption></figcaption></figure>

> You can also create a segment under Target Audience > Segments > Create section in the left panel. Select the User Properties, Session Properties, and events performed by the users. Then enter the name of your segment and click save.

### Cohort

If you chose Cohort of users, you could select the user cohort from the dropdown below “select or upload new cohort”. To further drill down the Cohort, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/qhAi0qKew5rcCugSjZyC" alt=""><figcaption></figcaption></figure>

#### Create Cohort

There are three ways to create a cohort

1. Upload a new cohort from the dropdown while selecting a cohort. Upload a csv file up to 50 MB, name your cohort, then click upload.
2. From **Target Audience > Cohorts > Upload** section in the left panel. Upload a csv file up to 50 MB and name your cohort.
3. From the **Target Audience > Segments** section, you can create a cohort from any segment. Click on the segment you want to create a cohort for, in the dropdown, select the date range and click on **Go.**

### Advanced Filters

You can further target users by their User journey, Attributes, and App Version in the app by selecting Advanced Filters.

<figure><img src="/files/JcWpzesdHXz0TgFRvWXp" alt=""><figcaption></figcaption></figure>

#### User Timeline

You can target users based on the user journey in the app by selecting the retention day. For example, you can show the campaign only to users in the first week of using the app by selecting Day 0 to Day 7. Additionally, you can select the range of sessions the user should have in the app so that the campaign can be displayed to him. For example, you can create a campaign that should be shown to the user only during their first 5 sessions in the app.

<figure><img src="/files/HCHSjHgkIxstTuSRQGoj" alt=""><figcaption></figcaption></figure>

#### User Properties

You can target users based on their User properties. User properties include unique user identifying information, such as their name, phone number, signup date, etc. You can select the user property Name, Data Type (whether it is a String, Numeric or Decimal), the logical operator, and the Value.

<figure><img src="/files/qLAvELJ097Qqm0RzVrdW" alt=""><figcaption></figcaption></figure>

#### Session Properties

You can Target Users based on Session properties. A Session can be simply defined as a user journey as he opens the app until he closes the app. Various pieces of information can be very impactful when accumulated in a session, for e.g., location of the user, language, etc.

<figure><img src="/files/4K7IZlGszeg35JEGM4sO" alt=""><figcaption></figcaption></figure>

> **User Properties vs. Session Properties**
>
> * User properties refer to the user’s information, which remains constant throughout the user’s journey in the app. eg. Name, Phone no, etc.
> * Session properties are the values that keep changing for every new session a user does in the app. eg. location, network, etc.

#### Build Number

You can target users based on their App Version. Please note while entering the App Version, the build number needs to be given instead of the Version number.

<figure><img src="/files/RJsi3TauGhqgf5Rt2JWx" alt=""><figcaption></figcaption></figure>

### Campaign Control Group

You can select the percentage of users for whom the campaign should not be shown. This feature will randomly exclude *x*% of users from the campaign. By default, the campaign control group is set to 3%. Using this feature, you can compare the number of users reaching the goal event with and without nudges.

<figure><img src="/files/thaV1JMGUYZ2cSwrM0Hx" alt=""><figcaption></figcaption></figure>


# Trigger

In this section, you can set the contextual conditions as to when to trigger the campaign for live users. Start by clicking on “Add Event”.

<figure><img src="/files/faH9Yv7CHvrSzXRAv7Cf" alt=""><figcaption></figcaption></figure>

## Event Conditions

* Firstly, pick the right trigger for your campaign to be shown to the users.
* You can choose whether the user “did” or “didn’t” perform the action.
* You can choose between app activity/screen, app event, or Client Event as your trigger from the drop-down button.
* You can also set the number of times the trigger must be performed along with the relevant operator (>, <,>=,<=,=,!=).
* You can also add multiple event properties to this event along with its values.
* Multiple events can be added in the trigger section by clicking “Add Another Event”.

## Combination of Multiple Conditions

You can change the conditions between any two steps. For example, users who did step 1 **AND** step 2 or did step 1 **OR** step 2 or did step 1 **AND THEN** step 2. Any combination of the AND or OR conditions can also be used. For example, users did step 1 AND step 2 OR Step 3.

### OR Condition

For a media streaming app, the user can be nudged to buy the subscription based on the condition that either the user listens to 3 songs or watches 3 videos. In this case, the trigger conditions will be,

> When user **did** **SongListened** for **== 3** times
>
> **OR**
>
> When user **did** **VideoWatched** for **== 3** times
>
> These two events can be in any order, and in between these two events, any number of events may take place.

### AND Condition

For an e-commerce app, the user can be nudged to view the cart page based on the conditions that the user lands on the home page and adds an item to the cart. In this case, the trigger conditions will be,

> When the user **did HomePageOpen** for **≥** **1** times
>
> **AND**
>
> When user **did AddedToCart** for **== 1** times
>
> These two events can be in any order, and in between these two events, any number of events may take place.

### AND-THEN Condition

For an e-commerce app, the user can be presented with a feedback survey for an item, if the user first adds the item to the cart and then removes the item from the cart. In this case, the trigger conditions will be,

> When the user **did AddedToCart** for **≥ 1** times
>
> **AND THEN**
>
> When user **did RemovedFromCart** for **== 1** times
>
> The order of these events should be exactly as mentioned, however, any number of events can be triggered in between.

## Goal Event

The goal event of the campaign, as the name suggests, is the event that indicates the campaign’s success. This lets us measure the campaign’s success effectively.

**Eg.** For a media streaming app, **SubscriptionSuccess** can be termed as the goal event.


# Schedule and Limit

Under the Schedule tab, you will be able to customize the schedule and limits of the Campaign.

### Schedule

Under Schedule, you can set the campaign duration that specifies how long the campaign should be active. Enabling the “Show at Specific Time of the day” allows you to decide the timings at which the campaign must be shown to the user. If you chose a specific time period of the day based on your users' active time, the conversion rate will increase.

<figure><img src="/files/pRXAV1Kpqd83WYPHzObQ" alt=""><figcaption></figcaption></figure>

### Refresh users in Segments

This option must be enabled only when using “Segments” in your target audience. You can specify if the campaign’s target users should be re-evaluated every n number of hours, days, or weeks while the campaign is active. For example, you can refresh the users in the segment and display the campaign to be shown every day.

### Limit to Displaying

Finally, set the campaign display limit conditions by selecting the maximum number of times a campaign can be displayed to a user, either per session or overall. To further drill them down and get to the specifications, you can enable the Day and Session Limits to specify how many times it can be shown per session and per day.

<figure><img src="/files/KrdhKTgxYO4SWJ9d2gbO" alt=""><figcaption></figcaption></figure>


# Review and Test

Under the Review Tab, you will be able to see an overall summary of the campaign created. You can click on the “Edit” options next to each section box if any changes are needed.

To test the campaign on your test devices, click on “**Test**” in the top right corner. Select the device(s) from the drop-down menu under “Select your test devices” on which the testing needs to be performed, and click on “Launch Testing”. Click on “Register New Device” at the bottom of dropdown if your device is not listed. [Click here](/product-guides/adding-a-test-device) for other methods to register your device.

**NOTE:** For a final confirmation the trigger events are mentioned in the Test Campaign Screen. In case you want to change the trigger events, you can close the test campaign popup and go back to Configuration, or else it can be ignored

<figure><img src="/files/H68nDotP7YEiGYQ1PWfm" alt=""><figcaption></figcaption></figure>

Once you click “**Launch Testing**”, the campaign is auto-saved and will be taken back to the [Campaign Listing Page](/product-guides/create-a-campaign/mobile/campaign-listings-page), wherein you can see the campaign name and details in the Drafts.

To test the campaign on your device, open your app and ensure you meet the set context to trigger and launch the campaign.


# Set Priority and Publish

If you're happy with the look of your campaign and want to post it to your users, you should publish your campaign. Click on the "Publish" CTA on the top right corner to publish the campaign.

To Publish a campaign from the listings page, click Edit CTA under the Actions section on the [campaigns listing page](/product-guides/create-a-campaign/mobile/campaign-listings-page). You will be redirected to the campaign "Review" Screen, where you have an option to "Publish" the campaign in the top-right-hand corner.

Once you click on Publish, a pop-up box will appear asking to set the priority for this campaign. The pop-up will show all the previously created campaigns that satisfy both the following conditions:

1. The scheduled time for the campaign has an overlapping time interval with the newly created campaign.
2. The set of events used for triggering the campaigns has some common events.

   Consider the following example,

   * Campaign 1 is scheduled between 22 Apr 2023, 19:00 - 25 Apr 2023, 18:00, and Campaign 2 is scheduled between 25 Apr 2023, 15:00 - 01 May 2023, 15:00.
   * The triggering events for Campaign 1 are Add\_To\_Cart\_Clicked **OR** Item\_Description\_Clicked
   * The triggering event for Campaign 2 is Add\_To\_Cart\_Clicked

   <figure><img src="/files/1CZasyZl2cbJvsUFwqEp" alt=""><figcaption></figcaption></figure>

Then you need to set the priority order between these two campaigns. The campaign with the highest priority will be triggered in case of a conflict. Click and hold the six dots at the left of your campaign name and drag below in your preferred priority order. The topmost is the highest priority, and the bottom is the lowest. You can shuffle the order till you click on Next. After setting the priority order, click on the Next button; you will be asked for confirmation. Click on the Back button if you want to change the priority order. Click the Next button to confirm, and your campaign will be live at the scheduled time.

<figure><img src="/files/GRwsdjj05CDN3cyH6rWw" alt=""><figcaption></figcaption></figure>


# A/B Testing

### What is A/B Testing, and what do we offer

A/B testing can be helpful in determining the most effective nudges or campaign designs. A/B testing is a process in which we compare two or more than two variants of a digital nudge or campaign design to see which one performs better in goal event conversion. We distribute the users randomly among the variants and measure how many complete the goal event for each of the variant.

Let's say we want to encourage users to sign up for a newsletter. We might create two versions of a nudge: one with a simple message and a bright orange button and another with a longer message and a blue button. We would randomly show each version to users from different groups and measure how many sign up for the newsletter.

The results of A/B testing allow us to make data-driven decisions, about, which nudges are most effective. We can then use this information to optimize our nudges and create better user experiences.

Using A/B testing on our platform, we can help you create digital nudges that drive behavior change and improve user outcomes. We provide the following features of A/B testing:

* Ability to experiment between design variations
* Ability to experiment between flow variations
* Target Experiment Group selection: Randomized selection of the target group for the experimentation. Ideally, experimentation need not be done on all users.
* Variants Split along with Control Group: Can choose the variants’ split among the target users.
* Completely Randomized Variant Allocation: The variants will be allocated to users in a randomized manner so that the results will not be biased. Once a user allocated a variant for a campaign, he will not be shown any other variant throughout the campaign period. It avoids the cascading effect.

{% hint style="info" %}
**Control Group is Mandatory for A/B Testing**

A/B testing is a method that compares two variations of a feature, message, advertisement, or other user experience. However, many people overlook the importance of a control group. In reality, A/B testing should be called A/B/C testing, where "C" represents the control group. If a business is looking for the best solution for a new implementation, it should definitely use A/B testing. However, for the experiment to be effective and achieve real success, measuring outcomes against a benchmark is absolutely essential and the control group is the most effective benchmark to utilize.
{% endhint %}

* Goal Event Selection: To decide the winner of the variants, choose a goal action that indicates the success of the campaign. It helps in measuring the effectiveness of the variants.
* Auto / Manual Publish Winner: Once the experiment is done, one can opt for rolling out the winner variant to all the users in case of the statistically significant winner is concluded. Otherwise, the winner variant will not be published.
* A/B Results: We use the Bayesian A/B to the Frequentist approach as it has its own advantages, especially when smaller samples are available. For each variant, the following are available
  * Campaign Viewed Users
  * Converted Users (did perform the goal event)
  * Conversion Percentage
  * Overall Improvement over the Control Group
  * Chance to be a winner
  * Chance to beat the control
  * Expected Loss
  * Expected Improvement
  * All the other metrics that are for a campaign

### Getting Started with A/B Testing

<figure><img src="/files/3nTYIUAiGfl6JMWixpLb" alt=""><figcaption></figcaption></figure>

* Creating an A/B Test campaign in Apxor is short and simple. Click on the A/B icon in the top right corner.
* In the pop-up that appears, enter the name for this variant of design and click on Add
* Click on the Black "plus" ➕ icon to add another variant.
* Select the variants from the top bar and start adding templates to it.


# Campaign Listings Page

Once you click on Campaign in the left panel you will land on the campaign listings page.

<figure><img src="/files/Q4GLtRkNPFbM16Ttlrji" alt=""><figcaption></figcaption></figure>

**Campaign Name:** The campaign's name and description/Tag in the grey background box.

**Created Date:** The creation date of the campaign.

**Start Date:** The start date of the campaign. (there is a sort option given to you for the start date, wherein you can sort them in descending or ascending order. Hover over the **Start** text and click on the arrows that appear).

**End date:** The end date of the campaign (along with a sort option)

**Actions:** Under Actions, we have following activities

<figure><img src="/files/h2ifiWpuJvt3UTA5jEKf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/v9we9e60Y0T2iF8O5FGF" alt=""><figcaption></figcaption></figure>


# Campaign Analytics

Once you click on the analytics symbol on the campaign listing page, you will be redirected to the campaign analytics page. This dashboard consists of numbers and graphs depicting various information about the campaign.

<figure><img src="/files/ZCzBfe48xWomDgozKKqq" alt=""><figcaption></figcaption></figure>

* ***X*****&#x20;Users:** Users that are shown the campaign
* ***X*****&#x20;Conversions:** Users who have done the goal event after the campaign is shown
* ***X*****% Conversion Rate:** Percentage of Conversion
* Comparison of all the above with the Control Group ( Only those who have done the trigger but the campaign is not shown intentionally. This gives you perfect comparison)

<figure><img src="/files/7kE4GQ3UwiXa47Jo598C" alt=""><figcaption></figcaption></figure>

* Funnel of the steps in a multistep walkthrough
* Day wise Steps conversions
* Conversions of the primary and secondary goal events
* Day Wise Goal event conversions
* Comparison of the following KPIs among the users who have shown that specific campaign and ALL users. The first bar in the graph is for all users, and the second bar for the users in this campaign.
  * **D1 Retention**

    Day 1 Retention is a metric that measures the percentage of users who continue to use your website or application one day after their installation. A user is considered retained if on **Day0** the user performs the event **install** and on **Day1** the user did **apx\_app\_opened** event i.e. the user opens the app.
  * **D0 Uninstalls**

    Day 0 Uninstalls represent the percentage of users who uninstall or delete your application immediately on the same day of their installation. When the user performed the event **install** and **uninstall** within same day (00:00 to 23:59)
  * **Average Number of Sessions**

    Average Sessions Per User is a metric that calculates the average number of unique sessions or interactions individual users have within your website or application over a day.
  * **Average time spent in a session**

    Average time spent in a session Per User is a metric that calculates the average number of unique sessions or interactions individual users have within your website or application over a day.


# Web Templates

## Modals

These various modal templates provide versatile options for delivering digital nudges on your website, catering to different content needs and visual preferences while maintaining user-friendly functionality.

<figure><img src="/files/x6T70lUEjxPikPfc06Lu" alt=""><figcaption></figcaption></figure>

### Modal - Small:

The Modal-Small web template is a compact design element that includes a title, description, two action buttons, and a cross icon for closing. It offers a concise and focused way to present information or guide user actions without overwhelming the user interface.

### Modal - Medium:

The Modal-Medium web template strikes a balance between size and impact. It consists of a title, description, two action buttons, and a cross icon for closing. This template provides a moderate-sized modal that's suitable for delivering important messages or prompting user interactions.

### Modal - Large:

The Modal-Large web template offers a spacious and attention-grabbing design with a title, description, two action buttons, and a cross icon for closing. It provides ample room for conveying detailed information or guiding users through important decisions within a larger modal.

### Modal - Icon:

The Modal-Icon web template features an eye-catching icon alongside a title, description, two action buttons, and a cross icon for closing. This template combines visual appeal with essential information, making it ideal for drawing attention to specific actions or messages.

### Modal - Image:

The Modal-Image web template takes advantage of visual storytelling by including a large image alongside a title, description, two action buttons, and a cross icon for closing. This template is perfect for conveying messages that rely heavily on imagery or visual impact.

### Modal - Scrollable:

The Modal-Scrollable web template offers a unique solution for presenting extensive content. It includes a title, a generously sized scrollable description area, two action buttons, and a cross icon for closing. This template is designed to accommodate lengthy text or content that requires scrolling, ensuring that users can access all the information they need.

## Tooltips

These tooltip web templates provide versatile options for enhancing user experience on your website by offering various tooltip sizes and formats to suit different UI elements and content requirements.

<figure><img src="/files/Z6RZ0c3CUtDTuvGLbt4G" alt=""><figcaption></figcaption></figure>

### Tooltip-Small:

The Tooltip-Small web template is a compact design element tailored for tooltips on UI elements. It consists of a title, brief description, two action buttons, and a cross icon for closing. This template provides concise and focused information without obstructing the user's view.

### Tooltip - Medium:

The Tooltip-Medium web template strikes a balance between size and informativeness, making it suitable for tooltips on UI elements. It includes a title, detailed description, two action buttons, and a cross icon for closing. This template offers a moderate-sized tooltip for conveying important context or options to the user.

### Tooltip - Large:

The Tooltip-Large web template offers an extensive tooltip design, ideal for providing comprehensive information or choices for UI elements. It includes a title, a detailed description, two action buttons, and a cross icon for closing. This template ensures that users have ample space to access valuable insights or actions.

### Tooltip - Icon:

The Tooltip-Icon web template combines visual appeal with information. It includes an icon, title, detailed description, two action buttons, and a cross icon for closing. This template is designed to enhance tooltips with eye-catching visuals while delivering essential context or options.

### Tooltip - Image:

The Tooltip-Image web template leverages visual storytelling by incorporating a large image alongside a title, description, two action buttons, and a cross icon for closing. It's perfect for tooltips that rely heavily on images or visual aids to communicate information or actions effectively.

### Tooltip - Scrollable:

The Tooltip-Scrollable web template offers a practical solution for tooltips with extensive content. It includes a title, a generously sized scrollable description area, two action buttons, and a cross icon for closing. This template ensures that tooltips can accommodate lengthy text or content that necessitates scrolling, ensuring all details are accessible to users.

## Videos

<figure><img src="/files/vWLJWgMkukOIao1UdVOC" alt=""><figcaption></figcaption></figure>

### Tooltip-Video:

The Tooltip-Video web template is a dynamic and engaging design element that incorporates a large video alongside essential information. It includes a title, descriptive text, two action buttons, and a cross icon for closing. This template is perfect for tooltips that use video content to provide users with informative and interactive experiences. Users can watch the video while also having access to relevant information and actions.

### Videos:

The "Videos" digital nudge web template offers an immersive and engaging way to capture users' attention. It features a prominent, large video element and a convenient cross icon for closing. This template is designed to showcase video content in a visually appealing and user-friendly manner. Users can easily watch the video, allowing you to deliver compelling messages, visual stories, or important information with the power of video. It's an effective choice for adding interactive and attention-grabbing multimedia experiences to your website while ensuring users can easily exit the video when desired.

### Modal-Video:

The Modal-Video web template offers a visually striking way to present video content within a modal. It includes a large video, a title, descriptive text, two action buttons, and a cross icon for closing. This template provides users with a focused video experience, allowing them to watch the video while also providing additional context, options, or information through the accompanying elements. It's an effective choice for delivering video-driven messages or actions in a controlled and user-friendly manner.

## Create a Web Campaign

Go back to config options for [web campaign](/product-guides/create-a-campaign/web)


# Create a Survey

On the Dashboard home page, select your organization name, then select the application for which you want to launch the survey, then click on Nudges in the left panel and select Surveys.

On the Surveys dashboard, you have the CTA to create a new survey, on the right side. Once you click the CTA, you will be asked to enter the Survey details. Enter the Name of the survey, choose a tag if you want to categorize this survey, select legacy or latest surveys based on your need and click on **Create**.

{% content-ref url="/pages/XSvmtE21z0XlfXvIjRCs" %}
[Legacy](/product-guides/create-a-survey/legacy)
{% endcontent-ref %}

{% content-ref url="/pages/xGYIUWYDh2PJVgHvW8yZ" %}
[Latest](/product-guides/create-a-survey/latest)
{% endcontent-ref %}


# Legacy

## Add Templates

You can start designing the survey by adding templates by clicking on the ➕ icon on the left side. Click on the “>” arrow button to view different templates under each head. You can select from [Request-For-Survey](/product-guides/create-a-survey/legacy/survey-designs/request-for-survey), [Single-Choice](/product-guides/create-a-survey/legacy/survey-designs/single-response), [Multi-Choice](/product-guides/create-a-survey/legacy/survey-designs/multi-response), [Rating](/product-guides/create-a-survey/legacy/survey-designs/rating), [Short-Answer](/product-guides/create-a-survey/legacy/survey-designs/short-answer) and [Success-Message](/product-guides/create-a-survey/legacy/survey-designs/success-message). Once you have found the right template, click “Select”.

<figure><img src="/files/GZSIwLEj350l0tvUfwlk" alt=""><figcaption></figcaption></figure>

## Customize your Template

Click on the "**Theming**" icon in the top right corner to customize a theme for your survey. Click on the option like question configuration or options configuration and click on the color to change it. For the Single Choice, Multi Select, Rating, and Short Answer templates, the following customizations are available:

### Theming

* The **Theming** section is a global config for the survey. The customizations made here will be applicable to all the question templates selected in this survey.
* Questions Configuration:

  Text Color and Background Color
* Options Configuration: Active Text Color, Inactive Text Color, Active Background Color, and Inactive Background color. Here Active means the option which is currently selected.
* Progressbar Configuration:

  Enable or Disable the progress bar, and change the progress bar color.
* Submit and Close Button Configuration:

  Enable or Disable the close button, and change the close button color.

  Change the Text, Active, and Inactive Colors of the Submit button.
* Previous and Skip Button Configuration:

  Enable or Disable the Skip and Previous buttons, and change their respective button colors.
* Once you are done with the configuration click **Done.**

### Edit Design

* In the Edit design section for the question templates, the following customizations are available:
* Orientation: Full Screen, Center, and Bottom. Once you change the orientation, it will apply to the entire survey questions(Except the **Ask for Survey** and **Success Message** templates).
* Dim Background. Once you change the dim background toggle, it will apply to the entire survey questions(Except the **Ask for Survey** and **Success Message** templates).
* The text on the submit button can be changed. Eg. Next, Submit, etc.
* Whether the question needs to be mandatory.

{% content-ref url="/pages/kKMBivXbirtTL82ZfxLk" %}
[Target](/product-guides/create-a-survey/legacy/target)
{% endcontent-ref %}

{% content-ref url="/pages/v34ps682oCbxHhal4eWH" %}
[Trigger](/product-guides/create-a-survey/legacy/trigger)
{% endcontent-ref %}

{% content-ref url="/pages/psStLnuDaUJvWVf2ARKG" %}
[Schedule and Limit](/product-guides/create-a-survey/legacy/schedule-and-limit)
{% endcontent-ref %}

{% content-ref url="/pages/awedb8thf4TNMxVSj0zm" %}
[Review and Test](/product-guides/create-a-survey/legacy/review-and-test)
{% endcontent-ref %}

{% content-ref url="/pages/accd0mC7hSHYU9s22CkL" %}
[Publish](/product-guides/create-a-survey/legacy/publish)
{% endcontent-ref %}

{% content-ref url="/pages/nFsO5Vg51zYgr4YZxUfY" %}
[Survey Listings Page](/product-guides/create-a-survey/legacy/survey-listings-page)
{% endcontent-ref %}

{% content-ref url="/pages/2iqltcX7FFDDwfnBU3Tz" %}
[Survey Analytics](/product-guides/create-a-survey/legacy/survey-analytics)
{% endcontent-ref %}

{% content-ref url="/pages/62LmUjyVh7IzyaRpO81M" %}
[Survey Designs](/product-guides/create-a-survey/legacy/survey-designs)
{% endcontent-ref %}


# Target

Start by selecting your target users – whether you want to aim the survey to “All Users”, “Segment” of Users, or “Cohort” of users.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPtrkJ3vMAFJUXSFiqzDo%2Fuploads%2Fb3fQt9733qx3m42H5psr%2FTarget.gif?alt=media&#x26;token=9ff3e086-fde6-4767-8205-095e174407f3" alt=""><figcaption></figcaption></figure>

### All Users

If you choose all users, you can also select an app event that users did not do in their lifetime to narrow down the target audience from the drop-down.

<figure><img src="/files/FA88SsfTLEXcfGBVskrp" alt=""><figcaption></figcaption></figure>

> **Segment vs Cohort**
>
> * A "**Segment**" is a group of consumers who share similar characteristics such as age, income, geographic location, or purchasing behavior. Marketers often use consumer segments to identify and target specific groups of consumers with tailored products, messaging, and marketing strategies.
> * A "**Cohort**" is a group of individuals sharing a common characteristic or experience within a defined period. In the context of consumer behavior, a cohort might refer to a group of individuals who were born in a certain year, graduated from college in a certain year, or who first purchased a product during a specific time period. Cohorts can be useful for understanding a group of consumers' purchasing patterns and behaviors over time.

### Segment

If you choose a segment of users, you can select the user segment from the drop-down below “Select Segment”. By selecting the segment, you will be able to see the segment details below. You can also specify the time period during which you want to select the users in that segment, it can be Between 2 date ranges or in the “Last” in the previous day(s). To further drill down the segment, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/Nep1LClSzTfY5a48RfLp" alt=""><figcaption></figcaption></figure>

> You can also create a segment under Target Audience > Segments > Create section in the left panel. Select the User Properties, Session Properties, and events performed by the users. Then enter the name of your segment and click save.

### Cohort

If you chose Cohort of users, you could select the user cohort from the dropdown below “select or upload new cohort”. To further drill down the Cohort, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/qhAi0qKew5rcCugSjZyC" alt=""><figcaption></figcaption></figure>

#### Create Cohort

There are three ways to create a cohort

1. Upload a new cohort from the dropdown while selecting a cohort. Upload a csv file up to 50 MB, name your cohort, then click upload.
2. From **Target Audience > Cohorts > Upload** section in the left panel. Upload a csv file up to 50 MB and name your cohort.
3. From the **Target Audience > Segments** section, you can create a cohort from any segment. Click on the segment you want to create a cohort for, in the dropdown, select the date range and click on **Go.**

### Advanced Filters

You can further target users by their User journey, Attributes, and App Version in the app by selecting Advanced Filters.

<figure><img src="/files/JcWpzesdHXz0TgFRvWXp" alt=""><figcaption></figcaption></figure>

#### User Timeline

You can target users based on the user journey in the app by selecting the retention day. For example, you can show the campaign only to users in the first week of using the app by selecting Day 0 to Day 7. Additionally, you can select the range of sessions the user should have in the app so that the campaign can be displayed to him. For example, you can create a campaign that should be shown to the user only during their first 5 sessions in the app.

<figure><img src="/files/HCHSjHgkIxstTuSRQGoj" alt=""><figcaption></figcaption></figure>

#### User Properties

You can target users based on their User properties. User properties include unique user identifying information, such as their name, phone number, signup date, etc. You can select the user property Name, Data Type (whether it is a String, Numeric or Decimal), the logical operator, and the Value.

<figure><img src="/files/qLAvELJ097Qqm0RzVrdW" alt=""><figcaption></figcaption></figure>

#### Session Properties

You can Target Users based on Session properties. A Session can be simply defined as a user journey as he opens the app until he closes the app. Various pieces of information can be very impactful when accumulated in a session, for e.g., location of the user, language, etc.

<figure><img src="/files/4K7IZlGszeg35JEGM4sO" alt=""><figcaption></figcaption></figure>

> **User Properties vs. Session Properties**
>
> * User properties refer to the user’s information, which remains constant throughout the user’s journey in the app. eg. Name, Phone no, etc.
> * Session properties are the values that keep changing for every new session a user does in the app. eg. location, network, etc.

#### Build Number

You can target users based on their App Version. Please note while entering the App Version, the build number needs to be given instead of the Version number.

<figure><img src="/files/RJsi3TauGhqgf5Rt2JWx" alt=""><figcaption></figcaption></figure>


# Trigger

In this section, you can set the contextual conditions as to when to trigger the survey for live users. Start by clicking on “Add Event”.

<figure><img src="/files/faH9Yv7CHvrSzXRAv7Cf" alt=""><figcaption></figcaption></figure>

* Firstly, pick the right trigger for your survey to be shown to the users.
* You can choose whether the user “did” or “didn’t” perform the action.
* You can choose between app activity/screen, app event, or Client Event as your trigger from the drop-down button.
* You can also set the number of times the trigger must be performed along with the relevant operator (>, <,>=,<=,=,!=).
* You can also add multiple event properties to this event along with its values.
* Multiple events can be added in the trigger section by clicking “Add Another Event”.
* You can change the conditions between any two steps. For example, users who did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**AND**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark> or did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**OR**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark> or did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**AND THEN**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark>. Any combination of the AND or OR conditions can also be used. For example, users did step 1 AND step 2 OR Step 3.
  * **Eg.**
    * For a media streaming app, the user can be nudged to buy the subscription based on the condition that either the user listens to 3 songs or watches 3 videos. In this case, the trigger conditions will be,

      > When user **did** **SongListened** for **== 3** times
      >
      > **OR**
      >
      > When user **did** **VideoWatched** for **== 3** times
      >
      > These two events can be in any order, and in between these two events, any number of events may take place.
    * For an e-commerce app, the user can be nudged to view the cart page based on the conditions that the user lands on the home page and adds an item to the cart. In this case, the trigger conditions will be,

      > When the user **did HomePageOpen** for **≥** **1** times
      >
      > **AND**
      >
      > When user **did AddedToCart** for **== 1** times
      >
      > These two events can be in any order, and in between these two events, any number of events may take place.
    * For an e-commerce app, the user can be presented with a feedback survey for an item, if the user first adds the item to the cart and then removes the item from the cart. In this case, the trigger conditions will be,

      > When the user **did AddedToCart** for **≥ 1** times
      >
      > **AND THEN**
      >
      > When user **did RemovedFromCart** for **== 1** times
      >
      > The order of these events should be exactly as mentioned, however, any number of events can be triggered in between.


# Schedule and Limit

Under the Schedule tab, you will be able to customize the schedule and limits of the Survey.

### Schedule

Under Schedule, you can set the survey duration that specifies how long the survey should be active. Enabling the “Show at Specific Time of the day” allows you to decide the timings at which the survey must be shown to the user. If you chose a specific time period of the day based on your users' active time, the conversion rate will increase.

<figure><img src="/files/pRXAV1Kpqd83WYPHzObQ" alt=""><figcaption></figcaption></figure>

### Refresh users in Segments

This option must be enabled only when using “Segments” in your target audience. You can specify if the survey’s target users should be re-evaluated every n number of hours, days, or weeks while the survey is active. For example, you can refresh the users in the segment and display the survey to be shown every day.

### Limit to Displaying

Finally, set the survey display limit conditions by selecting the maximum number of times a survey can be displayed to a user, either per session or overall. To further drill them down and get to the specifications, you can enable the Day and Session Limits to specify how many times it can be shown per session and per day.

<figure><img src="/files/KrdhKTgxYO4SWJ9d2gbO" alt=""><figcaption></figcaption></figure>


# Review and Test

Under the Review Tab, you will be able to see an overall summary of the survey created. You can click on the “Edit” options next to each section box if any changes are needed.

To test the survey on your test devices, click on “**Test**” in the top right corner. Select the device(s) from the drop-down menu under “Select your test devices” on which the testing needs to be performed, and click on “Launch Testing”. Click on “Register New Device” at the bottom of dropdown if your device is not listed. [Click here](/product-guides/adding-a-test-device) for other methods to register your device.

**NOTE:** For a final confirmation the trigger events are mentioned in the Test Campaign Screen. In case you want to change the trigger events, you can close the test campaign popup and go back to Configuration, or else it can be ignored

<figure><img src="/files/H68nDotP7YEiGYQ1PWfm" alt=""><figcaption></figcaption></figure>

Once you click “**Launch Testing**”, the survey is auto-saved and will be taken back to the [Survey Listing Page](/product-guides/create-a-survey/legacy/survey-listings-page), wherein you can see the survey name and details in the Drafts.

To test the survey on your device, open your app and ensure you meet the set context to trigger and launch the survey.


# Publish

If you're happy with the look of your survey and want to post it to your users, you should publish your survey. Click on the "Publish" CTA on the top right corner to publish the survey.

To Publish a survey from listings page, click Edit CTA under the Actions section on the [campaigns listing page](/product-guides/create-a-survey/legacy/survey-listings-page). You will be redirected to the survey "Review" Screen, where you have an option to "Publish" the survey in the top-right-hand corner. Click on Publish on the confirmation message, and your Survey will be live at the scheduled time.

<figure><img src="/files/GRwsdjj05CDN3cyH6rWw" alt=""><figcaption></figcaption></figure>


# Survey Listings Page

Once you click on Survey in the left panel you will land on survey listings page.

<figure><img src="/files/Q4GLtRkNPFbM16Ttlrji" alt=""><figcaption></figcaption></figure>

**Survey Name:** The survey's name and description/Tag in the grey background box.

**Created Date:** The creation date of the survey.

**Start Date:** The start date of the survey. (there is a sort option given to you for the start date, wherein you can sort them in descending or ascending order. Hover over the **Start** text and click on the arrows that appear).

**End date:** The end date of the campaign (along with a sort option)

**Actions:** Under Actions, we have following activities

<figure><img src="/files/h2ifiWpuJvt3UTA5jEKf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/eEu38aePK49kSxXqNeQT" alt=""><figcaption></figcaption></figure>


# Survey Analytics

Once you click on the analytics symbol on the [survey listing page](/product-guides/create-a-survey/legacy/survey-listings-page), you will be redirected to the survey analytics page. This dashboard consists of graphs depicting various information about the survey.

<figure><img src="/files/FcWfFRxbpZcPkIUc53iq" alt=""><figcaption></figcaption></figure>

* You can see the number of responses received for each question option.
* You can see the question text on the top left and the option text in the legend section on the right side of each question container.
* Hover over the bar graphs to get the exact number of responses for a particular option.
* Click on the export icon in the top right corner to download the JSON file.


# Survey Designs

The Surveys tab in the Apxor dashboard allows you to create and launch NPS (Net Promoter Code), Single-choice, Multi-choice, and Text-based questions sequentially or independently on the fly. This allows you to create response-based surveys where users can give feedback or responses based on choices made in previous questions.

<figure><img src="/files/5bHn9jHwQ9HRMpQBVQXr" alt=""><figcaption></figcaption></figure>

### Customizations

For the Single Choice, Multi Select, Rating, and Short Answer templates, the following customizations are available:

<details>

<summary>Theming</summary>

The Theming section is a global config for the survey. The customizations made here will be applicable to all the question templates selected in this survey.

Once you are done with the configuration click Done.

</details>

<details>

<summary>Edit Design</summary>

* By Element ID- In the Edit design section for the question templates, the following customizations are available:By Customized Tag
* Orientation: Full Screen, Center, and Bottom. Once you change the orientation, it will apply to the entire survey questions(Except the Ask for Survey and Success Message templates)
* Dim Background. Once you change the dim background toggle, it will apply to the entire survey questions(Except the Ask for Survey and Success Message templates)
* The text on the submit button can be changed. Eg. Next, Submit, etc.
* Whether the question needs to be mandatory.

</details>

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td align="center">Request for Survey</td><td></td><td>This template lets you ask the users whether they want to proceed with the survey; if they select No, the survey will end there.</td><td><a href="/pages/j3uYCmpqqiVzgeUBVrvO">/pages/j3uYCmpqqiVzgeUBVrvO</a></td><td><a href="/files/7PSbpqvv9IudOqIupDlv">/files/7PSbpqvv9IudOqIupDlv</a></td></tr><tr><td align="center">Single Response</td><td></td><td>This template lets you create a single-response question where a user is asked to pick only one answer from a predetermined set of responses.</td><td><a href="/pages/Y6HqniHQYgMempZmBMeJ">/pages/Y6HqniHQYgMempZmBMeJ</a></td><td><a href="/files/BB6QT3EzkwvBpe9OfFdS">/files/BB6QT3EzkwvBpe9OfFdS</a></td></tr><tr><td align="center">Multi Response</td><td></td><td>This template lets you create a multiple-response question where a user can pick more than one answer from a predetermined set of responses.</td><td><a href="/pages/YMIZcsc0TX9wXzTauhlA">/pages/YMIZcsc0TX9wXzTauhlA</a></td><td><a href="/files/XeoeGvbL9bLaK7arYO2p">/files/XeoeGvbL9bLaK7arYO2p</a></td></tr><tr><td align="center">Rating</td><td></td><td>This template allows you to evaluate users' feelings about a particular statement.</td><td><a href="/pages/YRPBD3VZDkB9e4LbY4ZU">/pages/YRPBD3VZDkB9e4LbY4ZU</a></td><td><a href="/files/HiLPelhuQcGRxe3ZKxOR">/files/HiLPelhuQcGRxe3ZKxOR</a></td></tr><tr><td align="center">Short Answer</td><td></td><td>This template allows users to enter comments/answers as a piece of text</td><td><a href="/pages/pjn6Xp7FHKPDAaR5QWFc">/pages/pjn6Xp7FHKPDAaR5QWFc</a></td><td><a href="/files/1pGS1QoYzvVQz3aRlVXw">/files/1pGS1QoYzvVQz3aRlVXw</a></td></tr><tr><td align="center">Success Message</td><td></td><td>This template displays a message or confirmation to the user upon successfully completing the survey.</td><td><a href="/pages/kxWGBjYTPmZBPqdXmmdD">/pages/kxWGBjYTPmZBPqdXmmdD</a></td><td><a href="/files/xI8jCzPi93mrPPXrb0iY">/files/xI8jCzPi93mrPPXrb0iY</a></td></tr></tbody></table>

Get started by creating your first [survey](/product-guides/create-a-survey/legacy).


# Request for Survey

This template lets you ask the users whether they want to proceed with the survey; if they select No, the survey will end there.

<figure><img src="/files/EyAScA7HzU3VU8qAsNEQ" alt="" width="375"><figcaption></figcaption></figure>

### Customizations

* Dialogue box background color
* Dialogue text color
* Icon image with the dialogue; Custom, default, or no icon image
* **Yes-box** text, color, and the background color of the Yes button.
* **No-box** text, color, and the background color of the No button.


# Single Response

This template lets you create a single-choice question where a user is asked to pick only one answer from a predetermined set of responses.

You can also add an Others option, which will allow the user to input the response in text format.

You can also randomize the order of the choices.

<figure><img src="/files/5CByI5wMPDQ8noJQ2v16" alt="" width="375"><figcaption></figcaption></figure>


# Multi Response

This template lets you create a multiple-choice question where a user can pick more than one answer from a predetermined set of responses.

You can also add an Others option, which will allow the user to input the response in text format.

You can also randomize the order of the choices.

<figure><img src="/files/C1MLQgTUVM6Op4pSYUAs" alt="" width="375"><figcaption></figcaption></figure>


# Rating

This template allows you to evaluate users' feelings about a particular statement. Users are asked to choose from a range of options scaled between two extremes: Terrible and Excellent. You can choose a rating scale between 1 to 5 and 0 to 10

<figure><img src="/files/m2dYsqw4Gdd3KeYH0M8o" alt="" width="375"><figcaption></figcaption></figure>

### Customizations

* Rating style can be: **Classis, Stylized**, or **Numbered**
* Under the advance section, you can select the action after rating, between **Redirect to Play Store and Provide Further Question.**
* Enter the play store link or the question you want to redirect to.
* Customize the follow-up question's placeholder, text color, placeholder color, background color, and max character limit.
* Based on the response submitted by the user, redirect them to different questions or playstore links.
* Set the rules for response-based redirection in **ASK IF USER SELECTS** section. Select the minimum and maximum ratings submitted by the user to trigger the particular redirection.
* Click on **Add more** and follow the same procedure to add more redirections.


# Short Answer

This template allows users to enter comments/answers as a piece of text up to 150 characters. (the upper limit of characters can be customized above 150 too)

Customize the text color, placeholder color, background color, and the maximum limit of characters allowed to enter.

<figure><img src="/files/icAmwdIthWc3z6RbGzW4" alt="" width="375"><figcaption></figcaption></figure>


# Success Message

This template displays a message or confirmation to the user upon successfully completing the survey. It can include a thank you message or confirmation of survey submission. The Success Message feature is designed to give users peace of mind that their input has been received and recorded and to create a positive user experience.

Customize the text color, icon color, and background color.

<figure><img src="/files/ROg3spUHq76Rki9LHpXm" alt="" width="375"><figcaption></figcaption></figure>


# Latest

## 1. Design Mode vs. Preview Mode

### Design Mode (default)

When you land on the design page after selecting the template, you are in design mode by default. Click on the UI elements in the simulator for further configuration options like **editing the text**, **changing the font type**, **size**, **background colour**, etc. You can also remove the UI element from the design by hovering over it and clicking the delete icon.

<figure><img src="/files/UcDjsLitRHAkPnzYA3ar" alt=""><figcaption></figcaption></figure>

### Preview Mode

Once you toggle into preview mode, you can interact with the questions in the simulator as they are intended for the end user on their device. You can **select the choices**, **answer the short answer question**, **select the rating**, and **click the Next button** to move to the next question. To be able to edit the UI elements’ configuration, you need to toggle back to Design Mode.

## 2. Edit Design Section

<figure><img src="/files/4DNG4tN0p7WdfaQCdfk8" alt=""><figcaption></figcaption></figure>

### Orientation

You can change the orientation of the template to one of **Full Screen, Center** or **Footer.** The orientation will be applied to all the questions in the survey.

### Dim Background

Enable the dim background radio button to dim the background screen when the survey container is shown to the end user.

<figure><img src="/files/USk56WLuA3DCdkhpa2C8" alt=""><figcaption></figcaption></figure>

You can change the dim background colour by clicking on the colour icon. You can also change the opacity percentage of the dim background by sliding the slider.

### Mandatory Question

Enable the Mandatory Question radio button to make this question mandatory for the end user to answer. Once enabled, the **Next** button on the survey container will be disabled until the end user makes a selection, e.g. selects an option, selects a rating, and starts typing.

### Randomize Choices

Enable the randomize choices radio button in Single-Choice and Multi-Choice templates to present the choices in randomized order to end users.

### Progress Bar

Enable the progress bar so the end user can see a small colored strip on top of survey container.

### Icon Buttons

By default the cross mark is in top right corner and the back arrow is in top left corner. You can switch their positions by clicking on the switch position icon.

## 3. In-Place Editing

When you are in **Design Mode,** you can click on the items to use the edit options available. You can also remove an item by hovering on it and clicking on the delete icon that appears at the top left corner of that item.

<figure><img src="/files/DKr4MwJnqyaV5Fy1PzqM" alt=""><figcaption></figcaption></figure>

To add the removed item again, hover over the survey container and click on the pencil/edit icon.

<figure><img src="/files/cd5jG6rHswvYoCSXTzWB" alt=""><figcaption></figcaption></figure>

### Progress Bar

Click on the progress bar at the top. A palate with options to edit the colors of completed and yet to be completed colors and size/height of the progress bar will open. Just click on the color to select your preferred color.

<figure><img src="/files/h3QEhtdm0ug28LNclfdR" alt=""><figcaption></figcaption></figure>

### Stepper

You can change the text and format of the question stepper by clicking on it.

<figure><img src="/files/4uYNS4TbgV1LhTxXuN71" alt=""><figcaption></figcaption></figure>

### Cross and Back Icons

You can change the color, size and margin of the cross icon and back arrow.

<figure><img src="/files/cwOW95ZmkgaGLZ8IOCfc" alt=""><figcaption></figcaption></figure>

### Text

You can edit any of the text items by clicking on them.

<figure><img src="/files/YEGLV7HUuMFoc5QNOEUK" alt=""><figcaption></figcaption></figure>

You can change the font type, font size and font color. You can also configure the alignment, margin and padding.

### Button

You can configure the button by clicking on the non-textual part of the button.

<figure><img src="/files/DSwqQqW1XyXZVlr33Q9a" alt=""><figcaption></figcaption></figure>

You select the button action as **Next, Submit or Dismiss.** You can change the button color for Active and Inactive state. You can use these options to select the button position, wide or small button and provide margin and paddings.

### Background

You can change the background color of any section by clicking on the non-textual portion of that section.

### Choices and Ratings

For single-choice and multi-choice templates, you can configure the choices. Click on the non-textual portion to configure the options tile. Click on the textual portion to edit the option text and textual attributes like font-type, size and active and inactive font-color.

<figure><img src="/files/qUFVzWBgBFLmDVZ1rSjO" alt=""><figcaption></figcaption></figure>

You can select the options tiles as filled or outlined, configure the corner radius, active and inactive background color and padding.

### Ratings

Click on the non-textual part in the rating tile for configuration options.

<figure><img src="/files/ErrX5DWF40EYCpo8HgRf" alt=""><figcaption></figcaption></figure>

You can configure active and inactive color, resize the tile, add stroke and stroke color to it and configure the corner radius.

Click on the rating number for number related configurations.

<figure><img src="/files/inXldOTY2bMzgVtbk10e" alt=""><figcaption></figcaption></figure>

## 4. NPS Template Specific

### Number of Buttons

Select the start and end rating number of the rating scale you want.

### Labels

Enable or disable the text label for start and end number of the rating scale.

eg. most likely, least likely, etc.

### Questions and Suggestions

You can ask question on the same screen based on the rating selected by the user.

<figure><img src="/files/Y8JEzg8pyPrDfLPqaKz3" alt=""><figcaption></figcaption></figure>

1. Click on the icon, a pop-up will appear
2. Click on Add a Question based on rating
3. Select the condition and ratings as per your requirement
4. Enable Question
   1. Edit and enter the question text
5. Enable Suggestion
   1. Suggestions are response tiles to the question. End User can just click on the tiles to select his response for the question.
   2. Click on Add Suggestion to add a suggestion tile.
   3. Click on the Suggestion 1, Suggestion 2, etc. text to edit and write your own response
6. Enable Feedback box
   1. Adds a text box for user to enter a textual response.

### Reactions

You can display a emoji and text based on the rating selected by the user.

<figure><img src="/files/wysiOkTPojwnRT28KQlz" alt=""><figcaption></figcaption></figure>

1. Click on the icon, a pop-up will appear
2. Select the condition and ratings as per your requirement
3. Enable Message
   1. Edit the text and write a message to display
   2. eg. Excellent, Very Poor, etc.
4. Enable Image
   1. provide the url


# Survey Stop Conditions

You can configure conditions to stop showing a survey to the end user based on the scenarios below. Once you have finalized the design and navigated to the **Target** section on the dashboard, you will find the **Stop Conditions** section at the bottom.

<div align="left"><figure><img src="/files/gXMuO8w086rvC72MksMy" alt="Survey Stop Conditions"><figcaption></figcaption></figure></div>

#### 1. **User Property**

Stop showing the survey once a specified user property is updated.

**To configure:**

* Check the box for **User Property**
* Select the desired user property from the dropdown
* Choose the value at which the survey should stop being shown

**Examples:**

* `subscription_type` updates to `paid`
* `app_version` updates to `2.0.03`

#### 2. **Goal Event**

Stop showing the survey once a specific goal event from the campaign is triggered.

**To configure:**

* Check the box for **Goal Event**
* Select one or more goal events associated with the campaign

**Examples:**

* `purchase_complete` is triggered
* `level_up` is triggered

You can also define combinations of events using **AND** or **OR** logic.

**Examples:**

* `Event A AND Event B`
* `Event A OR Event B`

#### 3. **Survey Completed**

Stop showing the survey once the user has completed it.

**To configure:**

* Check the box for **Survey Completed**

Once the user completes the survey (e.g., submits the final response), they will no longer be shown the same survey again.


# Target

Start by selecting your target users – whether you want to aim the survey to “All Users”, “Segment” of Users, or “Cohort” of users.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPtrkJ3vMAFJUXSFiqzDo%2Fuploads%2Fb3fQt9733qx3m42H5psr%2FTarget.gif?alt=media&#x26;token=9ff3e086-fde6-4767-8205-095e174407f3" alt=""><figcaption></figcaption></figure>

### All Users

If you choose all users, you can also select an app event that users did not do in their lifetime to narrow down the target audience from the drop-down.

<figure><img src="/files/FA88SsfTLEXcfGBVskrp" alt=""><figcaption></figcaption></figure>

> **Segment vs Cohort**
>
> * A "**Segment**" is a group of consumers who share similar characteristics such as age, income, geographic location, or purchasing behavior. Marketers often use consumer segments to identify and target specific groups of consumers with tailored products, messaging, and marketing strategies.
> * A "**Cohort**" is a group of individuals sharing a common characteristic or experience within a defined period. In the context of consumer behavior, a cohort might refer to a group of individuals who were born in a certain year, graduated from college in a certain year, or who first purchased a product during a specific time period. Cohorts can be useful for understanding a group of consumers' purchasing patterns and behaviors over time.

### Segment

If you choose a segment of users, you can select the user segment from the drop-down below “Select Segment”. By selecting the segment, you will be able to see the segment details below. You can also specify the time period during which you want to select the users in that segment, it can be Between 2 date ranges or in the “Last” in the previous day(s). To further drill down the segment, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/Nep1LClSzTfY5a48RfLp" alt=""><figcaption></figcaption></figure>

> You can also create a segment under Target Audience > Segments > Create section in the left panel. Select the User Properties, Session Properties, and events performed by the users. Then enter the name of your segment and click save.

### Cohort

If you chose Cohort of users, you could select the user cohort from the dropdown below “select or upload new cohort”. To further drill down the Cohort, you can also select an app event that users didn’t do in their lifetime.

<figure><img src="/files/qhAi0qKew5rcCugSjZyC" alt=""><figcaption></figcaption></figure>

#### Create Cohort

There are three ways to create a cohort

1. Upload a new cohort from the dropdown while selecting a cohort. Upload a csv file up to 50 MB, name your cohort, then click upload.
2. From **Target Audience > Cohorts > Upload** section in the left panel. Upload a csv file up to 50 MB and name your cohort.
3. From the **Target Audience > Segments** section, you can create a cohort from any segment. Click on the segment you want to create a cohort for, in the dropdown, select the date range and click on **Go.**

### Advanced Filters

You can further target users by their User journey, Attributes, and App Version in the app by selecting Advanced Filters.

<figure><img src="/files/JcWpzesdHXz0TgFRvWXp" alt=""><figcaption></figcaption></figure>

#### User Timeline

You can target users based on the user journey in the app by selecting the retention day. For example, you can show the campaign only to users in the first week of using the app by selecting Day 0 to Day 7. Additionally, you can select the range of sessions the user should have in the app so that the campaign can be displayed to him. For example, you can create a campaign that should be shown to the user only during their first 5 sessions in the app.

<figure><img src="/files/HCHSjHgkIxstTuSRQGoj" alt=""><figcaption></figcaption></figure>

#### User Properties

You can target users based on their User properties. User properties include unique user identifying information, such as their name, phone number, signup date, etc. You can select the user property Name, Data Type (whether it is a String, Numeric or Decimal), the logical operator, and the Value.

<figure><img src="/files/qLAvELJ097Qqm0RzVrdW" alt=""><figcaption></figcaption></figure>

#### Session Properties

You can Target Users based on Session properties. A Session can be simply defined as a user journey as he opens the app until he closes the app. Various pieces of information can be very impactful when accumulated in a session, for e.g., location of the user, language, etc.

<figure><img src="/files/4K7IZlGszeg35JEGM4sO" alt=""><figcaption></figcaption></figure>

> **User Properties vs. Session Properties**
>
> * User properties refer to the user’s information, which remains constant throughout the user’s journey in the app. eg. Name, Phone no, etc.
> * Session properties are the values that keep changing for every new session a user does in the app. eg. location, network, etc.

#### Build Number

You can target users based on their App Version. Please note while entering the App Version, the build number needs to be given instead of the Version number.

<figure><img src="/files/RJsi3TauGhqgf5Rt2JWx" alt=""><figcaption></figcaption></figure>


# Trigger

In this section, you can set the contextual conditions as to when to trigger the survey for live users. Start by clicking on “Add Event”.

<figure><img src="/files/faH9Yv7CHvrSzXRAv7Cf" alt=""><figcaption></figcaption></figure>

* Firstly, pick the right trigger for your survey to be shown to the users.
* You can choose whether the user “did” or “didn’t” perform the action.
* You can choose between app activity/screen, app event, or Client Event as your trigger from the drop-down button.
* You can also set the number of times the trigger must be performed along with the relevant operator (>, <,>=,<=,=,!=).
* You can also add multiple event properties to this event along with its values.
* Multiple events can be added in the trigger section by clicking “Add Another Event”.
* You can change the conditions between any two steps. For example, users who did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**AND**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark> or did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**OR**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark> or did <mark style="background-color:purple;">step 1</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">**AND THEN**</mark> <mark style="background-color:purple;"></mark><mark style="background-color:purple;">step 2</mark>. Any combination of the AND or OR conditions can also be used. For example, users did step 1 AND step 2 OR Step 3.
  * **Eg.**
    * For a media streaming app, the user can be nudged to buy the subscription based on the condition that either the user listens to 3 songs or watches 3 videos. In this case, the trigger conditions will be,

      > When user **did** **SongListened** for **== 3** times
      >
      > **OR**
      >
      > When user **did** **VideoWatched** for **== 3** times
      >
      > These two events can be in any order, and in between these two events, any number of events may take place.
    * For an e-commerce app, the user can be nudged to view the cart page based on the conditions that the user lands on the home page and adds an item to the cart. In this case, the trigger conditions will be,

      > When the user **did HomePageOpen** for **≥** **1** times
      >
      > **AND**
      >
      > When user **did AddedToCart** for **== 1** times
      >
      > These two events can be in any order, and in between these two events, any number of events may take place.
    * For an e-commerce app, the user can be presented with a feedback survey for an item, if the user first adds the item to the cart and then removes the item from the cart. In this case, the trigger conditions will be,

      > When the user **did AddedToCart** for **≥ 1** times
      >
      > **AND THEN**
      >
      > When user **did RemovedFromCart** for **== 1** times
      >
      > The order of these events should be exactly as mentioned, however, any number of events can be triggered in between.


# Schedule and Limit

Under the Schedule tab, you will be able to customize the schedule and limits of the Survey.

### Schedule

Under Schedule, you can set the survey duration that specifies how long the survey should be active. Enabling the “Show at Specific Time of the day” allows you to decide the timings at which the survey must be shown to the user. If you chose a specific time period of the day based on your users' active time, the conversion rate will increase.

<figure><img src="/files/pRXAV1Kpqd83WYPHzObQ" alt=""><figcaption></figcaption></figure>

### Refresh users in Segments

This option must be enabled only when using “Segments” in your target audience. You can specify if the survey’s target users should be re-evaluated every n number of hours, days, or weeks while the survey is active. For example, you can refresh the users in the segment and display the survey to be shown every day.

### Limit to Displaying

Finally, set the survey display limit conditions by selecting the maximum number of times a survey can be displayed to a user, either per session or overall. To further drill them down and get to the specifications, you can enable the Day and Session Limits to specify how many times it can be shown per session and per day.

<figure><img src="/files/KrdhKTgxYO4SWJ9d2gbO" alt=""><figcaption></figcaption></figure>


# Review and Test

Under the Review Tab, you will be able to see an overall summary of the survey created. You can click on the “Edit” options next to each section box if any changes are needed.

To test the survey on your test devices, click on “**Test**” in the top right corner. Select the device(s) from the drop-down menu under “Select your test devices” on which the testing needs to be performed, and click on “Launch Testing”. Click on “Register New Device” at the bottom of dropdown if your device is not listed. [Click here](/product-guides/adding-a-test-device) for other methods to register your device.

**NOTE:** For a final confirmation the trigger events are mentioned in the Test Campaign Screen. In case you want to change the trigger events, you can close the test campaign popup and go back to Configuration, or else it can be ignored

<figure><img src="/files/H68nDotP7YEiGYQ1PWfm" alt=""><figcaption></figcaption></figure>

Once you click “**Launch Testing**”, the survey is auto-saved and will be taken back to the [Survey Listing Page](/product-guides/create-a-survey/legacy/survey-listings-page), wherein you can see the survey name and details in the Drafts.

To test the survey on your device, open your app and ensure you meet the set context to trigger and launch the survey.


# Publish

If you're happy with the look of your survey and want to post it to your users, you should publish your survey. Click on the "Publish" CTA on the top right corner to publish the survey.

To Publish a survey from listings page, click Edit CTA under the Actions section on the [campaigns listing page](/product-guides/create-a-survey/legacy/survey-listings-page). You will be redirected to the survey "Review" Screen, where you have an option to "Publish" the survey in the top-right-hand corner. Click on Publish on the confirmation message, and your Survey will be live at the scheduled time.

<figure><img src="/files/GRwsdjj05CDN3cyH6rWw" alt=""><figcaption></figcaption></figure>


# Survey Listings Page

Once you click on Survey in the left panel you will land on survey listings page.

<figure><img src="/files/Q4GLtRkNPFbM16Ttlrji" alt=""><figcaption></figcaption></figure>

**Survey Name:** The survey's name and description/Tag in the grey background box.

**Created Date:** The creation date of the survey.

**Start Date:** The start date of the survey. (there is a sort option given to you for the start date, wherein you can sort them in descending or ascending order. Hover over the **Start** text and click on the arrows that appear).

**End date:** The end date of the campaign (along with a sort option)

**Actions:** Under Actions, we have following activities

<figure><img src="/files/h2ifiWpuJvt3UTA5jEKf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/eEu38aePK49kSxXqNeQT" alt=""><figcaption></figcaption></figure>


# Custom Reports

## How to Use

You can download the custom reports from the left panel's **Reporting > Custom reports** section.

<figure><img src="/files/DfsTVyUGZgerqna0zCeB" alt=""><figcaption></figcaption></figure>

* Select the cohort, versions, and date range for which you want to download the custom report from the top right section.
* You can also select a saved report from the drop-down below the select date section in the top right corner.
* For a new report, select the metrics you want
  * Total Events: Number of times the event was triggered
  * Users: Number of unique users
  * Sessions: Number of unique sessions
* Select the dimensions you need for the analysis one by one from the drop-down. You can select dimensions from [User Attributes](/getting-started-with-apxor/api-guides/ios#user-attributes), [Session Attributes](/getting-started-with-apxor/api-guides/ios#session-attributes), [App Events](/getting-started-with-apxor/api-guides/ios#app-events), apx\_user\_id, apx\_day, apx\_date, apx\_DayOfTheWeek, apx\_custom\_user\_id, etc.
  * Eg.&#x20;
    * apx\_event\_name: Name of the event
    * apx\_location\_city: Location city of the user
* Apply filters
  * Include or Exclude
  * select the dimension
  * exact or regex
  * Enter the property value
* Click the floppy disc icon below “Add Filter” to save this as a report for future use
* Click the refresh icon below “Add Filter” to refresh the data
* Click the bin icon below Add Filter to **Delete** this report
* Click the download icon beside the search bar to download the csv file.
* The file will be available for downloading under **Settings -> Downloads** section in the left panel. The download link will expire after one day.

## Example Use Cases

### Downloading Cohort details

Consider you have launched an in-app campaign for getting the user's consent on your updated policy. The in-app template has two CTAs, one, **I Agree** and another, **Know more**.

You noticed from the results page that a significant amount of users are clicking on Know more and not coming back to click I agree.

You might want to follow up these specific users on call for getting the insights about what they didn't like in the policy.&#x20;

Now you can create a cohort from the segment of users who clicked on Know more but did not come back and clicked on I agree.

Select that cohort and the date range on the Custom reports page. Select the properties for the user details, eg. user\_id, user\_name, contact\_number, etc.&#x20;

Click the refresh icon and download the details for your further use.


# Analytics


# Custom Dashboards

Custom Dashboard is a place where you can keep an eye on your key metrics. Add the data widgets to track your metrics at a glance.

Click on Custom Dashboard under the Analytics section in the left panel. You will be redirected to Custom Dashboards listing page. You can find the list of custom dashboards created if any. Click on the dashboard name to open the dashboard.

<figure><img src="/files/4q9EDNfRc4oBLlqtM46D" alt=""><figcaption></figcaption></figure>

## Creating a Dashboard

Click on Add Custom Dashboard on the top right CTA on the custom dashboard listings page.

Enter the name for the Dashboard and click create.

You will land on a blank dashboard. Click on Add Widget CTA in the top right corner.

<figure><img src="/files/lhhcty9dCJkIIN79oGOn" alt=""><figcaption></figcaption></figure>

Select your preferred widget from the following

* Hourly Distribution
  * Distribution of the selected event count per hour.
* Overview
  * Unique users or events count for today, yesterday, the last week, and the last month
* Event Trends
  * Number of users / events trended over a specific time
* Segment Trends
  * Number of users in a segment trended over a specific time
* Segment Breakdown
  * Breakdown distribution of the users that fall in a segment by a property
* Stickiness Metric
  * Shows visitor or account engagement as a ratio of short term versus long term return frequency. For example, Daily Active Users(DAU) versus Monthly Active Users(MAU)
* Custom Formulae
  * This widget offers you greater flexibility when performing analyses. Custom formulae are useful in observing the aggregates and relative metrics.

<figure><img src="/files/1htoJ4d8nPqpzMV1Ihna" alt=""><figcaption></figcaption></figure>

### Hourly Distribution

This is a bar graph showing the Distribution of the selected event count per hour.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the event for tracking.

<figure><img src="/files/qzN3QkaZMNxJyzw1obY5" alt=""><figcaption></figcaption></figure>

* Select the Date Range for tracking the event.

<figure><img src="/files/04ecpJCV5uBtVM4rtlZP" alt=""><figcaption></figcaption></figure>

* Click on **Apply & Preview** to see the graph in the adjacent window

<figure><img src="/files/XOEAXfM6Pylo8SPbJLhQ" alt=""><figcaption></figcaption></figure>

* Then Click on **Add to Dashboard**

The graph will be added to your dashboard.

<figure><img src="/files/rVwQcfJkbafx8poo83AJ" alt=""><figcaption></figcaption></figure>

### Overview

This is a simple graph displaying four circles with values for unique users or total events count for today, yesterday, the last week, and the last month for the selected event.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the event for tracking.
* Select whether you want Unique number of users or total number of event count for the same.
* Click on **Apply and Preview** to preview the graph before adding to the dashboard.
* Click on **Add to Dashboard** to add it to the dashboard

<figure><img src="/files/9NxMqlGld0Z4c84dERsR" alt=""><figcaption></figcaption></figure>

### Event Trends

Number of users / events trended over a specific time. This is a line graph, with a line for the selected event.&#x20;

X-axis represents the dates falling in the date range. Y-axis represents the User or the Event Count.

On hovering over the graph, you can see the user or event count for the event on the date mentioned on X-Axis.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the event for tracking
* **Event Trend**
  * Select this if you want to analyze the number of times this event was logged.
* **User Trend**
  * Select this if you want to analyze the number of unique users performing this event.
* Select the date range for which you want to analyze.
* Click on **Apply and Preview** to preview the graph before adding to the dashboard.
* Click on **Add to Dashboard** to add it to the dashboard

<figure><img src="/files/diAOBh4COVCshdvUj65F" alt=""><figcaption></figcaption></figure>

### Segment Trend

Number of users in a segment trended over a specific time. This is a line graph, with a line for each of the segment selected.&#x20;

X-axis represents the dates falling in the date range. Y-axis represents the User Count.

On hovering over the graph, you can see the user count for each of the segment on the date mentioned on X-Axis.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the Segments for tracking. You can select multiple segments
* Select the date range for which you want to analyze.
* Click on **Apply and Preview** to preview the graph before adding to the dashboard.
* Click on **Add to Dashboard** to add it to the dashboard

<figure><img src="/files/Y0NP8jA3QkqDJtXcbbMV" alt=""><figcaption></figcaption></figure>

### Segment Breakdown

This is a pie chart showing the breakdown distribution of the users that fall in a segment by a property.

On hovering over the graph, you can see the property value and its share in percentage.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the Segment for tracking.
* Select the property on which you want the breakdown.
* Select the date range for which you want to analyze.
* Click on **Apply and Preview** to preview the graph before adding to the dashboard.
* Click on **Add to Dashboard** to add it to the dashboard

<figure><img src="/files/noo2SvB1VM8EJFowYzWd" alt=""><figcaption></figcaption></figure>

### Stickiness Metric

This is a line graph that shows visitor or account engagement as a ratio of short term versus long term return frequency. For example, Daily Active Users(DAU) versus Monthly Active Users(MAU).

X-axis represents the dates falling in the date range. Y-axis represents the selected ratio.

On hovering over the graph, you can see the ratio and numbers for the selected metric on the date mentioned on X-Axis.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Select the metric from the dropdown that you want to analyze
  * DAU/MAU: ratio of daily active users to monthly active users
  * DAU/WAU: ratio of daily active users to weekly active users
  * WAU/MAU: ratio of weekly active users to monthly active users
* Select the date range for which you want to analyze.
* Click on **Apply and Preview** to preview the graph before adding to the dashboard.
* Click on **Add to Dashboard** to add it to the dashboard

<figure><img src="/files/IPocLcfIh7eXbCr7ClLF" alt=""><figcaption></figcaption></figure>

### Custom Formulae

This widget offers you greater flexibility when performing analyses. Custom formulas are useful in observing the aggregates and relative metrics.

* Enter the name for the widget, which will be displayed over the graph in the Dashboard.
* Add the events on which you would like to apply the formulae.
* You can also filter and group by the properties of the event.
* Select the formulae from the dropdown
* Select the event on which you want it to be applied.
* You can also perform mathematical operations after applying formulae on two events. Select the operator and formulae for the second event.

#### Formula syntax

In your formulas, refer to events selected in the Events Module by their corresponding letter. The functions and the parameters are not case sensitive. You can also perform the following arithmetic operations:

* Parenthesis ()
* Addition (+)
* Subtraction (-)
* Multiplication (\*)
* Division (/)

For example, the letter A in the formula `UNIQUES(A)` below refers to the event `View Item Details` while the letter B in the formula `UNIQUES(B)` below refers to the event `Add Item to Cart`. This setup will display the ratio of users who viewed an item's details to users who placed an item in their cart.

<figure><img src="/files/cxug0AUZBDkr37I6RCyV" alt=""><figcaption></figcaption></figure>

#### Metrics Formulas

With metrics formulas, you can query on a metric for a particular event you are interested in. Each metrics formula requires a letter corresponding to the event you're interested in as a parameter.

#### **AVG**

**Syntax:** AVG(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the left module of the chart control panel.

Returns the average number of times the event was triggered. This function is equivalent to `TOTALS(event)/UNIQUES(event)`.

#### **HIST**

**Syntax:** HIST(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card.

Returns the distribution of the event frequency per unique user over the selected time period.

#### **PROPAVG**

**Syntax:** PROPAVG(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card.
* This function will only work if you are grouping by a numerical property on the event. If grouping by multiple properties, the formula will perform the calculation with the first group-by clause.

Returns the average of the property values you are grouping by. This function is equivalent to `PROPSUM(event)/TOTALS(event)`.

**NOTE**: The PROPAVG formula ignores events where the selected property value is `(none)`.

#### **PROPCOUNT**

**Syntax:** PROPCOUNT(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card. If grouping by multiple properties, the formula will perform the calculation with the first group by clause.

Returns the number of distinct property values for the property the event is grouped by.

Note that PROPCOUNT is an estimate of distinct property values. This estimate is generated by a HyperLogLog algorithm, and its accuracy depends on amount of data it has to work with. Expect a relative error in the range of 0.1% for less than 12,000 unique values, and up to 0.5% for more than 12,000 unique property values, depending on the cardinality of the property.

#### **PROPCOUNTAVG**

**Syntax:** PROPCOUNTAVG(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card. If grouping by multiple properties, the formula will perform the calculation with the first group-by clause.

Returns the average number of distinct values each user has for a specified property.

For example, imagine you're interested in the average number of song genres your music app subscribers listen to. Every time a song is played, a `Play Song or Video` event will trigger; each played song also captures a `Genre_Type` event property. Running `PROPCOUNTAVG` on `Play Song or Video` grouped by `Genre_Type` will give you the average number of unique `Genre_Type` values users who fire `PlaySong or Video` have.

#### **PROPHIST**

**Syntax:** PROPHIST(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card.
* This function will only work if you are grouping by a numerical property on the event. If grouping by multiple properties, the formula will perform the calculation with the first group by clause.

Returns the distribution of the property values you are grouping by over the selected time period.

#### **PROPMAX**

**Syntax**: PROPMAX(event)

* **Event:** returns the maximum value of the property you are grouping the specified event by. The property must be numeric. If grouping by multiple properties, the calculation will be performed using the first group-by clause.

#### **PROPMIN**

**Syntax**: PROPMIN(event)

* **Event:** returns the minimum value of the property you are grouping the specified event by. The property must be numeric. If grouping by multiple properties, the calculation will be performed using the first group-by clause.

#### **PROPSUM**

**Syntax:** PROPSUM(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card. The event must be grouped by the property you'd like to sum.
* This function will only work if you are grouping by a numerical property on the event. If grouping by multiple properties, the formula will perform the calculation with the first group-by clause.

Returns the sum of the property values you are grouping the specified event by.

#### **TOTALS**

**Syntax:** TOTALS(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the left module of the chart control panel.

Returns the total number of times the event was triggered. The setup below will show the total number of times an item's details were viewed, plus the total number of times an item was added to a cart.

#### **UNIQUES**

**Syntax:** UNIQUES(event)

* **Event:** Refers to the event you are interested in. This must be a letter that corresponds to an event in the Events card.

Returns the number of unique users who triggered the event. For example, the following setup shows the ratio of users who viewed an item's details to the users who added an item to their cart.


# Uninstalls

The Uninstall Analysis Section helps you get a quick view of app Uninstalls and their trends at an event and user journey level.

## Overview

You can take a look at the total number of uninstalls and the number of Day 0 Uninstalls within the selected time period in the global date range. You can also analyze for a cohort of users or version wise filtering.

<figure><img src="/files/wbdZIMkxAF5VHCd5t49x" alt=""><figcaption></figcaption></figure>

## Uninstall Distribution

The uninstalled users can be filtered based on their User or Session Properties.

**Example:** You can choose the user property age\_range and select any value to understand the uninstall trends of users from that age range.

You can select the session property as location\_city and choose any city to get to know the uninstall trends of users who are from a particular city.

<figure><img src="/files/IwitKezDQsDEXS5vUefQ" alt=""><figcaption></figcaption></figure>

## Uninstall Trends

The Uninstall Trends give an overview of the uninstalls that occurred in the selected time period. The graph on the left shows the trend of the number of active users along with the number of uninstalled users, for a quick comparison. The graph on the right gives a comparison of the number of new installs along with the number of Day 0 uninstalled users (the number of users who uninstalled on the day they installed the app)

<figure><img src="/files/oN9tSUjFCSj0iJAW1SNO" alt=""><figcaption></figcaption></figure>

## Uninstalls by Journey

Uninstalls by Journey is a segmentation graph that allows you to group the users who uninstalled into 3 segments based on Day Wise usage from Day 0 to Day 90 and visualizes the number of uninstalls in those segments.

<figure><img src="/files/88hT6u1fTk416omYvFHW" alt=""><figcaption></figcaption></figure>

## Uninstall Day Usage

On clicking one of these segments, you can see the top events done by these users before uninstalling the app with the event count and the user count. You can also see the top events done by these users on the day of uninstall or in their lifetime by using the toggle on the top right of the graph.

<figure><img src="/files/3EyE5Hh39TYGPuCxUbra" alt=""><figcaption></figcaption></figure>


# Retention

The Retention tab under Apxor's Analysis section helps you check your app’s User Retention.​

At a glance, you can monitor user retention using the Retention Cohort Analysis and toggle between numeric or percentage values of retained user count in the selected period from the global date range filter.​

<figure><img src="/files/7ibGzs9e5WMWdzHLbE2v" alt=""><figcaption></figcaption></figure>

In the table that follows, you can see the retention cohort to further understand the retention of the selected users.​

<figure><img src="/files/dAnUajaZgOfnaV5p3Ruu" alt=""><figcaption></figcaption></figure>

## Time period selection​

Here, you can choose the kind of User Retention you wish to monitor. You can select between Daily, Weekly or Monthly retention or define a custom time period.​

<figure><img src="/files/KpEs3phHC6ULHWKSumCs" alt=""><figcaption></figcaption></figure>

## Usage Targeting (Filter By)​

Now that you have narrowed down the time period you want to analyze, you can move on to choose their app usage.

**Example:** You can only choose to see the retention of users who did the selected event on the Day 0 (Week 0, in case of weekly) using Facebook and finished a Carnatic music lesson and did same or another selected event on Day 1 (Week 1, in case of weekly)

Based on the conditions selected, you can check the retention cohort and graph.​

Using the add to dashboard icon, you can add the cohort to your any of your custom dashboards and monitor retention easily.​

## Habits Framework​

The habits framework in the Apxor dashboard lets you monitor the repeat usage trend and strength of various app events across the user’s journey.​

This lets you analyze how different habits are being formed for your users, check the front heavy features and promote features that are leading to long term habits.​

## Habit Trend​

Habit trend explains what percentage of your Day n users do a certain event.​

**Example:** 48.75% of D1 users finish a music practice while only 28.3% of D90 users do the same event.​

This helps you pin point the features that are mostly consumed by new users (Front heavy features) and features that are consumed more by your long term retained users.​

<figure><img src="/files/2D242fVWGBpKzwsF5rn9" alt=""><figcaption></figcaption></figure>

## Habit Strength ​

Habit Strength describes how many times users consume different events in various stages of their user journey.​

**Example:** Day 0 users do about 5.7 practices on an average while Day 90 users do around 7.9 practices. This showcases a clear habit being formed for the users.​

<figure><img src="/files/oma4xc6LfGXAmBNGnw3D" alt=""><figcaption></figcaption></figure>


# Funnels

Funnels in the Apxor dashboard help you with more than just monitoring your conversions rates.​ You can group the users in various steps of the funnel by a range of properties and check the impact of the same.​ Click on Funnels in the analysis tab to get started.​

## Creating a new funnel

You can choose a saved funnel that was created previously or you can start creating a new funnel by clicking on Add Step 1.

Select an event and add any event properties you'd like by clicking on Add Filter.​

<figure><img src="/files/m5Pg3d1ngsY445AkHpot" alt=""><figcaption></figcaption></figure>

After adding all your events in the funnel, you can rearrange them or add more events using the icons in the image shown.​

<figure><img src="/files/Df3AsEcLESmgfuBAQ6ob" alt=""><figcaption></figcaption></figure>

Next, select the conversion window from the dropdown, with options ranging from just a few minutes to a couple of months.

<figure><img src="/files/TT77ptOSTpPU1altDRNp" alt=""><figcaption></figcaption></figure>

You can save this funnel and name it so that you can analyse it anytime.​

<figure><img src="/files/n8ZRy3OeIygNUZ6oRSwp" alt=""><figcaption></figcaption></figure>

On clicking Get Funnel, you will be able to see the funnel for the selected events and properties within the conversion window in the time selected in the global time filter.​

## Analysing a funnel

You can take a look at the overall conversion percentage of the funnel on the top right of the funnel. ​From here, you can also add the funnel to a custom dashboard.​

<figure><img src="/files/wCHZnb8YM3zYAcUTHVOg" alt=""><figcaption></figcaption></figure>

## Funnel Comparison

You can also compare multiple saved funnels by selecting them from a dropdown in the Conversion Over Time section. Here, you will be able to take a look at the day wise trend of the conversion of the selected funnels.

<figure><img src="/files/tnPN39a4VianiUZ6vSK1" alt=""><figcaption></figcaption></figure>

## Grouping by Properties

Next you can utilise the Group by feature to understand the impact of a user, session or event property on the conversion in the funnel across the steps. Simply, choose the event from the tabs and then choose the property you want to drill down into.

<figure><img src="/files/tgUwDzbVOTizcU7cQiZC" alt=""><figcaption></figcaption></figure>

**Example:** Take a look at the impact of the session property DayOfTheWeek on conversion.

<figure><img src="/files/E3d1gNtElvrtkaccFjox" alt=""><figcaption></figcaption></figure>


# Paths

With Apxor’s Path Analysis visualize user flows in the app. You can check the paths that users took before uninstall, activation, conversion, feature discovery or drop offs. ​

The sunburst style view helps you know how users are exploring the app. Additionally, get to know the number of users who move from one step to another in a selected path when you hover or click on any flow.​

<figure><img src="/files/tGZrWU4vAH1Qk8mD18S7" alt=""><figcaption></figcaption></figure>

## Choosing Events

You can now choose a From Event or a To event.​ For example: Paths from Start Practice or Paths to App Uninstall etc.​

<figure><img src="/files/zoefm1tlJ9TqiDluwpCf" alt=""><figcaption></figcaption></figure>

Now, choose any event properties that you wish to apply here. ​

**Example:** Paths taken by users who activated Margin Plus on Mondays.​

<figure><img src="/files/tZJ0KCfqKGK6gc9cKABY" alt=""><figcaption></figcaption></figure>

Now just click on submit to be able to visualise the paths according to your Selected conditions.​


# Event Analysis

Event analysis lets you drill deeper into your events and event properties to understand user behaviour. ​

On the right of the Event analysis page, you can view the total number of users and sessions in the selected time period. You can toggle between viewing the event level metrics for All Users, New Installs, or Returning Users and even apply a User Journey wise **Day Filter** on the users. You can also select a cohort of users and apply version wise filters for the analysis to have deeper analysis.

Quickly understand the top events performed by your users in a particular time frame using the ‘Top Events’ filter widget.​ Use the ‘Day Filter’ widget to look at the top events for users on any particular day journey. ​ Slide the slider at the bottom of the graph to see more events.

**Example:** Look at the top events for all of your Day 7 users.

<figure><img src="/files/qL9qz5Va00c4VCdO0cqk" alt=""><figcaption></figcaption></figure>

## Distribution by Property

Use the Distribution by property filter to filter events by User properties (Properties that stay constant throughout a user’s journey. Example: The user's name) and Session properties (Properties that might change with every session a user does. Example: The type of internet used).​

The Pie chart view quickly helps you understand the distribution of your user properties and session properties. You can choose to view event details only for users having particular user and session properties.

After you have understood the distribution of your properties, select the properties you would like to drill deeper into and see how many users with the said property have done a particular event.​

**Example:** You can see the events distribution for Hindustani users who are aged 19 and have selected their Shruti as C#3. And also who are on Jio network in New Delhi and are currently using the 3.2.2 app version.

<figure><img src="/files/HHQDkmZdc7aIuZMC9MtG" alt=""><figcaption></figcaption></figure>

## Event Trends

Now, for any event you select under the events tab, you will get to know the number of times the event was performed, the number of users who performed the event and the no. of sessions in which the event was performed.​

<figure><img src="/files/7nK32l6H5kXO7ZxPpxsf" alt=""><figcaption></figcaption></figure>

To do further analysis and understand the event attributes distribution for the selected event, click on the info tab and choose the event attributes to view the distribution in a pie chart format.​

Using the Sessions, Users or Event toggle, take a look at the distributions across all the parameters.​

**Example:**

When you select the Sessions toggle, you will get the number of sessions in which headphones were connected or milestones were achieved among the users who did the finish practice event.

When you select the Users toggle, you will get the number of users who had their headphones connected or reached milestone while they were doing the finish practice event.​

<figure><img src="/files/d9SeCSKlG8IkxeUTOPWb" alt=""><figcaption></figcaption></figure>

When you select the Event toggle, you will get the number of times the headphones were connected or milestone was reached while users were doing finish practice event.​


# BI Dashboard

<figure><img src="/files/pY0FLhQEI3qBUF8WB0Qr" alt=""><figcaption></figcaption></figure>

### Add Visualization

To add a new visualization widget to the dashboard, click on the top right CTA and the required visualization.

<table data-view="cards"><thead><tr><th data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><a href="/pages/2sfn0y5IoRn8cmqFxw9U">/pages/2sfn0y5IoRn8cmqFxw9U</a></td><td><a href="/files/jka5X8OkoDoVGRHcsJAU">/files/jka5X8OkoDoVGRHcsJAU</a></td></tr><tr><td><a href="/pages/uHS2BcIam6mEviBG3MK3">/pages/uHS2BcIam6mEviBG3MK3</a></td><td><a href="/files/dCsOXqKPFf2uxMZMO9JC">/files/dCsOXqKPFf2uxMZMO9JC</a></td></tr><tr><td><a href="/pages/ALHYKsKbFyVVDtuaC59y">/pages/ALHYKsKbFyVVDtuaC59y</a></td><td><a href="/files/H3NvXPNPU6z4lKEAQJVS">/files/H3NvXPNPU6z4lKEAQJVS</a></td></tr><tr><td><a href="/pages/T0PJjbC4fTTqWRDZyQ7a">/pages/T0PJjbC4fTTqWRDZyQ7a</a></td><td><a href="/files/Cxy9HbVOkMcrghongQkN">/files/Cxy9HbVOkMcrghongQkN</a></td></tr><tr><td><a href="/pages/jABkocDVA3VvdlQqajr0">/pages/jABkocDVA3VvdlQqajr0</a></td><td><a href="/files/I0UvrEOhXJqhelizNQjU">/files/I0UvrEOhXJqhelizNQjU</a></td></tr></tbody></table>

### Edit and Refresh

To edit the name of the dashboard, click on the dashboard title.

Click on the refresh icon to fetch the latest data.

You can apply date range and custom filters at the dashboard level by clicking on the pencil icon.

<figure><img src="/files/KCCQ6DnK107aghCaUW0Q" alt=""><figcaption></figcaption></figure>

### Organizing and Rearranging

You can drag and move the already added visualization as your requirement. Click and hold on the six dots on the **top-left corner** of your visualization and then move them to the desired position.

<figure><img src="/files/kcwdTUkqdesazH0AaqLd" alt=""><figcaption></figcaption></figure>

### Resizing Visualization

You can resize the visualization as per your requirement. Click on hold on the **bottom-right corner** of the visualization and then increase or decrease the size as per the requirement.

<figure><img src="/files/RXDS336lniVYydWlAEFu" alt=""><figcaption></figcaption></figure>


# Frequency

This visualization is used to visualize how often each category occur, highlighting patterns and anomalies in the dataset.

<figure><img src="/files/g1aak8L4wOBucvV9HLjb" alt=""><figcaption></figcaption></figure>

### Name of Visualization

Enter the name of your Visualization widget, which will appear on your dashboard.

<figure><img src="/files/IRCSczc1E5IOEGxhJpy3" alt=""><figcaption></figcaption></figure>

### X-Axis Property

Select your preferred column name from the dropdown. The data from this column will populate the x-axis values to create a frequency visualization.

<figure><img src="/files/7zJS68Tp6ZfRGsfRGT9l" alt=""><figcaption></figcaption></figure>

### Alias for X-Axis

Enter the alias you want to display for the X-axis on the visualization graph.

<figure><img src="/files/7qtfkktgmTZx18YDDOd4" alt=""><figcaption></figcaption></figure>

### Y-Axis Property

Click on the + icon next to Y-Axis Properties to add properties for calculating values on the Y-axis. You can add more than one property here.

<figure><img src="/files/5wCmmelAXMZeLUIgPmeQ" alt=""><figcaption></figcaption></figure>

### Alias for Y-Axis

Enter the alias you want to display for the Y-axis on the visualization graph.

<figure><img src="/files/CX3uTNpX5BzS068M6xlx" alt=""><figcaption></figcaption></figure>

### Expression Builder

You can write an expression here to calculate the value for Y-Axis.

Start typing the function you want to use and select it from the suggestions. Then, place the cursor inside the brackets and type the property name you selected in Y-Axis Properties as the function attribute for calculations.

<figure><img src="/files/87m4sQdlz587TcDLPLUX" alt="" width="375"><figcaption></figcaption></figure>

The following options are available in the Expression Builder. `Ci` represents the attributes/properties selected by you

{% tabs %}
{% tab title="Arithmetic Functions" %}

<table><thead><tr><th width="172">Function</th><th width="287">Attribute Structure</th><th>Usage</th></tr></thead><tbody><tr><td>sum()</td><td>(attribute)</td><td>sum(C1)</td></tr><tr><td>sumIf()</td><td>(attribute, filter)</td><td>sumIf(C1, conditions)</td></tr><tr><td>avg()</td><td>(attribute)</td><td>avg(C1)</td></tr><tr><td>avgIf()</td><td>(attribute, filter)</td><td>avgIf(C1, conditions)</td></tr><tr><td>count()</td><td>(attribute)</td><td>count(C1)</td></tr><tr><td>countIf()</td><td>(attribute, filter)</td><td>countIf(C1, conditions)</td></tr><tr><td>uniq()</td><td>(attribute)</td><td>uniq(C1)</td></tr><tr><td>uniqIf()</td><td>(attribute, filter)</td><td>uniqIf(C1, conditions)</td></tr><tr><td>min()</td><td>(attribute)</td><td>min(C1)</td></tr><tr><td>max()</td><td>(attribute)</td><td>max(C1)</td></tr><tr><td>least()</td><td>(attribute1, attribute2)</td><td>least(C1, C2)</td></tr><tr><td>greatest()</td><td>(attribute1, attribute2)</td><td>greatest(C1, C2)</td></tr><tr><td>date_diff()</td><td>(return type, attribute1, attribute2)</td><td>date_diff('second', C1, C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Operators" %}

<table><thead><tr><th width="125" align="center">Operator</th><th>Action</th><th>Example Usage</th></tr></thead><tbody><tr><td align="center">+</td><td>Addition</td><td>uniq(C1) + uniq(C2)</td></tr><tr><td align="center">-</td><td>Subtraction</td><td>uniq(C1) - uniq(C2)</td></tr><tr><td align="center">/</td><td>Division</td><td>uniq(C1) / uniq(C2)</td></tr><tr><td align="center">*</td><td>Multiplication</td><td>uniq(C1) * uniq(C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Numeric Transformations" %}

<table><thead><tr><th width="122">Function</th><th width="346">Description</th><th>Usage</th></tr></thead><tbody><tr><td>abs()</td><td>Return the absolute value of a number</td><td>abs(C1)</td></tr><tr><td>toInt8()</td><td>Converts a value to an 8-bit integer</td><td>toInt8(C1)</td></tr><tr><td>toInt16()</td><td>Converts a value to an 16-bit integer</td><td>toInt16(C1)</td></tr><tr><td>toInt32()</td><td>Converts a value to an 32-bit integer</td><td>toInt32(C1)</td></tr><tr><td>toInt64()</td><td>Converts a value to an 64-bit integer</td><td>toInt64(C1)</td></tr><tr><td>toString()</td><td>Converts a value to a string</td><td>toString(C1)</td></tr></tbody></table>
{% endtab %}

{% tab title="Transformations" %}

| Function      | Description                                          | Usage           |
| ------------- | ---------------------------------------------------- | --------------- |
| toTimeStamp() | Converts a value to timestamp                        | toTimeStamp(C1) |
| toWeekDay()   | Converts a date to the corresponding day of the week | toWeekDay(C1)   |
| toUTCHour()   | Converts a time to its UTC Hour                      | toUTCHour(C1)   |
| toMonth()     | Converts a date to its corresponding month           | toMonth(C1)     |
| toDate()      | Converts a value to a date format                    | toDate(C1)      |
| {% endtab %}  |                                                      |                 |
| {% endtabs %} |                                                      |                 |

## sum()

The `sum()` function is used to calculate the total sum of a numeric column.

**Example:** Calculate the **total sales revenue** from all orders in the E-commerce application.

For example: Calculate the **total sales revenue** from all orders in the E-commerce application. Here A represents  the **sales\_revenue** as a property&#x20;

<figure><img src="/files/pi2O16uI4eODPoAD4ueU" alt=""><figcaption></figcaption></figure>

## sumIf()

The `sumIf()` function calculates the total sum of a numeric column, but **only for rows that meet a specified condition**. It works similarly to`sum()`, but adds a filtering condition.

**Example:** Calculate the **Total Sales Revenue** for **Failed transactions** in **Hyderabad** in an E-commerce Application

In this case, we want to calculate the total **sales revenue** (`A`) for transactions that **failed** (`B = 'FAIL'`) and are located in **Hyderabad** (`C = 'hyderabad'`).

<figure><img src="/files/jEV0X6EalMBqlrzCBJ1l" alt=""><figcaption></figcaption></figure>

## avg()

The `avg()` function is used to calculate the **average value** of a numeric column.

**Example:** Calculate the **Average Sales Revenue** from All Orders in an E-commerce Application

In this case, we want to calculate the average sales revenue from all transactions. Here, `A` represents the **sales\_revenue** as a property.

<figure><img src="/files/H5LOB1tipLo2NrFeiXIv" alt=""><figcaption></figcaption></figure>

## avgIf()

The `avgIf()` function is used to calculate the **average value** of a numeric column based on a specified condition.

**Example:** Calculate the **Average Sales Revenue** for Failed Transactions in Hyderabad.

In this case, we want to calculate the average sales revenue from transactions that failed and are located in Hyderabad. Here, `A` represents **sales\_revenue**, `B` represents **transaction\_status**, and `C` represents **location**.

<figure><img src="/files/8UnN861dN77sFJ6GqHku" alt=""><figcaption></figcaption></figure>

## count()

The `count()` function is used to **count the number of rows** or occurrences of a specific value in a column.

**Example:** Calculate the **Total Number of Transactions** in an E-commerce Application

In this case, we want to count the total number of transactions processed in the application. Here, `A` represents the **transaction\_id** as a property.

<figure><img src="/files/X8Xx49uFySTxJTbiHd4U" alt=""><figcaption></figcaption></figure>

## countIf()

The `countIf()` function is used to count the number of rows that meet a specified condition.

**Example:** Calculate the **Total Number of Failed Transactions** in **Hyderabad**

In this case, we want to count the total number of transactions that have failed and are located in Hyderabad. Here, `A` represents **transaction\_status** and `B` represents **location**.

<figure><img src="/files/AXV0R2Vae6ZqoHOG03eU" alt=""><figcaption></figcaption></figure>

## uniq()

The `uniq()` function is used to calculate the **number of distinct values** in a specified column.

**Example:** Calculate the **Total Number of Unique Customers** in the E-commerce Application

In this case, we want to count the total number of unique customers who have made purchases. Here, `A` represents the **customer\_id** as a property.

<figure><img src="/files/0srex2zQDiogj4mRTI88" alt=""><figcaption></figcaption></figure>

## uniqIf()

The `uniqIf()` function is used to count the **number of distinct values** in a column, but **only for rows that meet a specific condition**.

**Example:** Calculate the **Number of Unique Customers** Who Had **Failed Transactions** in **Hyderabad**

In this case, we want to calculate the total number of **unique customers** who experienced **failed transactions** and are located in **Hyderabad**. Here, `A` represents **customer\_id**, `B` represents **transaction\_status**, and `C` represents **location**.

<figure><img src="/files/3G2Y3OXbuS9Wys7L6gk5" alt=""><figcaption></figcaption></figure>

## min()

The `min()` function is used to calculate the **minimum value** in a numeric column.

**Example:** Calculate the **Minimum Sales Revenue** from All Orders in an E-commerce Application

In this case, we want to find the minimum sales revenue from all transactions. Here, `A` represents the **sales\_revenue** as a property.

<figure><img src="/files/78bahtCbDCodTyKhRhiB" alt=""><figcaption></figcaption></figure>

## max()

The `max()`function is used to calculate the **minimum value** in a numeric column.

**Example:** Calculate the **Minimum Sales Revenue** from All Orders in an E-commerce Application

In this case, we want to find the maximum sales revenue from all transactions. Here, `A` represents the **sales\_revenue** as a property.

<figure><img src="/files/nCDvKPuz1J0w0lTlieoA" alt=""><figcaption></figcaption></figure>

## least()

The `least()` function is used to return the **smallest value** from a set of values across multiple columns or expressions.

**Example:** Calculate the **Least Value Between Sales Revenue** and **Discount Amount for Each Order** in an E-commerce Application

In this case, we want to find the smallest value between the **sales revenue** (`A`) and **discount amount** (`B`) for each order. Here, `A` represents **sales\_revenue** and `B` represents **discount\_amount** as properties.

<figure><img src="/files/nyKepsoAYNKELB8OaGFR" alt=""><figcaption></figcaption></figure>

## greatest()

The `greatest()` function is used to return the **largest value** from a set of values across multiple columns or expressions.

**Example:** Calculate the **Greatest Value** Between **Sales Revenue** and **Discount Amount** for Each Order in an E-commerce Application

In this case, we want to find the largest value between the **sales revenue** (`A`) and **discount amount** (`B`) for each order. Here, `A` represents **sales\_revenue** and `B` represents **discount\_amount** as properties.

<figure><img src="/files/AMxX2eaLPAYdC9QINGBD" alt=""><figcaption></figcaption></figure>

## date\_diff()

The `date_diff()` function is used to calculate the **difference between two dates** in a specified unit (such as days, months, or years).

**Example:** Calculate the **Number of Days** Between **Order Date** and **Delivery Date** in an E-commerce Application

In this case, we want to calculate the number of days between the **order date** (`A`) and the **delivery date** (`B`). Here, `A` represents the **order\_date** and `B` represents the **delivery\_date** as properties.

<figure><img src="/files/VuxJVxNUgJaKAiUox10p" alt=""><figcaption></figcaption></figure>

### Custom Filters

You can filter the data in the final output on the dashboard according to your needs.

Choose whether to include data using the **=** operator or exclude it using the **!=** operator. You can also use the regex operator and provide the regex formula.

<figure><img src="/files/wsX0YaQm3kDm1p7TNrJm" alt=""><figcaption></figcaption></figure>

### Customize

You can customize the colors and add units to both the axes.

Following unit options are available

{% tabs %}
{% tab title="Time" %}
Second=sec

Minutes=mins

Hours=hrs

Days=days

Week=week
{% endtab %}

{% tab title="Numbers" %}
Thousand = K

Lakh = L

Million = M

Billion = B
{% endtab %}
{% endtabs %}

### View Chart

Click on View Chart to preview it before adding it to the dashboard.


# Aggregates

This visualization summarizes data by categories, showing totals, averages, and other key metrics.

<figure><img src="/files/muFRXhn49urb7Ft43oxx" alt=""><figcaption></figcaption></figure>

### Name of Visualization

Enter the name of your Visualization widget, which will appear on your dashboard.

<figure><img src="/files/aSmTBVIxuX1ey1kTtKNS" alt=""><figcaption></figcaption></figure>

### Aggregate Type

You can choose between grouped and single aggregate. In grouped aggregate, you can view multiple metrics within a single widget.

<figure><img src="/files/pyVjn6tvIzzG8QqhRH8B" alt=""><figcaption></figcaption></figure>

### Aggregates

Enter the following values for each of the metric required.

<figure><img src="/files/P56ayK0GEaLcounozXHc" alt=""><figcaption></figcaption></figure>

### Alias

Enter the name for each metric, which will appear on your dashboard.

### Properties

Select the column name from the dropdown for which you want to get the aggregate.

### Expression Builder

Start typing the function you want to use and select it from the suggestions. Then, place the cursor inside the brackets and type the property name you selected in Properties as the function parameter for calculations. The aggregate function will be applied on the output of this expression builder.

The following options are available in the Expression Builder. `Ci` represents the attributes/properties selected by you

{% tabs %}
{% tab title="Arithmetic Functions" %}

<table><thead><tr><th width="172">Function</th><th width="287">Attribute Structure</th><th>Usage</th></tr></thead><tbody><tr><td>sum()</td><td>(attribute)</td><td>sum(C1)</td></tr><tr><td>sumIf()</td><td>(attribute, filter)</td><td>sumIf(C1, conditions)</td></tr><tr><td>avg()</td><td>(attribute)</td><td>avg(C1)</td></tr><tr><td>avgIf()</td><td>(attribute, filter)</td><td>avgIf(C1, conditions)</td></tr><tr><td>count()</td><td>(attribute)</td><td>count(C1)</td></tr><tr><td>countIf()</td><td>(attribute, filter)</td><td>countIf(C1, conditions)</td></tr><tr><td>uniq()</td><td>(attribute)</td><td>uniq(C1)</td></tr><tr><td>uniqIf()</td><td>(attribute, filter)</td><td>uniqIf(C1, conditions)</td></tr><tr><td>min()</td><td>(attribute)</td><td>min(C1)</td></tr><tr><td>max()</td><td>(attribute)</td><td>max(C1)</td></tr><tr><td>least()</td><td>(attribute1, attribute2)</td><td>least(C1, C2)</td></tr><tr><td>greatest()</td><td>(attribute1, attribute2)</td><td>greatest(C1, C2)</td></tr><tr><td>date_diff()</td><td>(return type, attribute1, attribute2)</td><td>date_diff('second', C1, C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Operators" %}

<table><thead><tr><th width="125" align="center">Operator</th><th>Action</th><th>Example Usage</th></tr></thead><tbody><tr><td align="center">+</td><td>Addition</td><td>uniq(C1) + uniq(C2)</td></tr><tr><td align="center">-</td><td>Subtraction</td><td>uniq(C1) - uniq(C2)</td></tr><tr><td align="center">/</td><td>Division</td><td>uniq(C1) / uniq(C2)</td></tr><tr><td align="center">*</td><td>Multiplication</td><td>uniq(C1) * uniq(C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Numeric Transformations" %}

<table><thead><tr><th width="122">Function</th><th width="346">Description</th><th>Usage</th></tr></thead><tbody><tr><td>abs()</td><td>Return the absolute value of a number</td><td>abs(C1)</td></tr><tr><td>toInt8()</td><td>Converts a value to an 8-bit integer</td><td>toInt8(C1)</td></tr><tr><td>toInt16()</td><td>Converts a value to an 16-bit integer</td><td>toInt16(C1)</td></tr><tr><td>toInt32()</td><td>Converts a value to an 32-bit integer</td><td>toInt32(C1)</td></tr><tr><td>toInt64()</td><td>Converts a value to an 64-bit integer</td><td>toInt64(C1)</td></tr><tr><td>toString()</td><td>Converts a value to a string</td><td>toString(C1)</td></tr></tbody></table>
{% endtab %}

{% tab title="Transformations" %}

| Function      | Description                                          | Usage           |
| ------------- | ---------------------------------------------------- | --------------- |
| toTimeStamp() | Converts a value to timestamp                        | toTimeStamp(C1) |
| toWeekDay()   | Converts a date to the corresponding day of the week | toWeekDay(C1)   |
| toUTCHour()   | Converts a time to its UTC Hour                      | toUTCHour(C1)   |
| toMonth()     | Converts a date to its corresponding month           | toMonth(C1)     |
| toDate()      | Converts a value to a date format                    | toDate(C1)      |
| {% endtab %}  |                                                      |                 |
| {% endtabs %} |                                                      |                 |

<figure><img src="/files/jV0E2VV99ViCCNCBHpJf" alt=""><figcaption></figcaption></figure>

### Units

Select the unit from the dropdown for your aggregate value to be displayed on the dashboard.

Following unit options are available

{% tabs %}
{% tab title="Time" %}
Second = sec

Minutes = mins

Hours = hrs

Days = days

Week = week
{% endtab %}

{% tab title="Numbers" %}
Thousand = K

Lakh = L

Million = M

Billion = B
{% endtab %}
{% endtabs %}

### Final Transformation

Select whether you want to convert seconds or milliseconds to timestamp format on the dashboard.

### Custom Filters

You can filter the data in the final output on the dashboard according to your needs.

Choose whether to include data using the **=** operator or exclude it using the **!=** operator. You can also use the regex operator and provide the regex formula.

### Customize

You can customize the font size and text color for Alias, Value and the Unit displayed on the dashboard.

### View Chart

Click on View Chart to preview it before adding it to the dashboard.


# Trends

This visualization displays changes over time, helping to identify patterns and forecast future values.

<figure><img src="/files/CEaK7sMzyGViJ9sTWGHN" alt=""><figcaption></figcaption></figure>

### Data Visualization <a href="#name-of-visualization" id="name-of-visualization"></a>

Enter the following values as required to plot the trend.

<figure><img src="/files/i0XRHklzw5Y801z04VSE" alt=""><figcaption></figcaption></figure>

### Name of Visualization <a href="#name-of-visualization" id="name-of-visualization"></a>

Enter the name of your Visualization widget, which will appear on your dashboard.

### Alias for Metric

Enter the name for each metric, which will appear on your dashboard.

### Granularity

You can choose the granularity for plotting the trend graph as either Day or Hour.

### Metrics

Select the column name from the dropdown for which you want to get the trend.

### Expression Builder

Start typing the function you want to use and select it from the suggestions. Then, place the cursor inside the brackets and type the property name you selected in Properties as the function parameter for calculations. The aggregate function will be applied on the output of this expression builder.

The following options are available in the Expression Builder. `Ci` represents the attributes/properties selected by you

{% tabs %}
{% tab title="Arithmetic Functions" %}

<table><thead><tr><th width="172">Function</th><th width="287">Attribute Structure</th><th>Usage</th></tr></thead><tbody><tr><td>sum()</td><td>(attribute)</td><td>sum(C1)</td></tr><tr><td>sumIf()</td><td>(attribute, filter)</td><td>sumIf(C1, conditions)</td></tr><tr><td>avg()</td><td>(attribute)</td><td>avg(C1)</td></tr><tr><td>avgIf()</td><td>(attribute, filter)</td><td>avgIf(C1, conditions)</td></tr><tr><td>count()</td><td>(attribute)</td><td>count(C1)</td></tr><tr><td>countIf()</td><td>(attribute, filter)</td><td>countIf(C1, conditions)</td></tr><tr><td>uniq()</td><td>(attribute)</td><td>uniq(C1)</td></tr><tr><td>uniqIf()</td><td>(attribute, filter)</td><td>uniqIf(C1, conditions)</td></tr><tr><td>min()</td><td>(attribute)</td><td>min(C1)</td></tr><tr><td>max()</td><td>(attribute)</td><td>max(C1)</td></tr><tr><td>least()</td><td>(attribute1, attribute2)</td><td>least(C1, C2)</td></tr><tr><td>greatest()</td><td>(attribute1, attribute2)</td><td>greatest(C1, C2)</td></tr><tr><td>date_diff()</td><td>(return type, attribute1, attribute2)</td><td>date_diff('second', C1, C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Operators" %}

<table><thead><tr><th width="125" align="center">Operator</th><th>Action</th><th>Example Usage</th></tr></thead><tbody><tr><td align="center">+</td><td>Addition</td><td>uniq(C1) + uniq(C2)</td></tr><tr><td align="center">-</td><td>Subtraction</td><td>uniq(C1) - uniq(C2)</td></tr><tr><td align="center">/</td><td>Division</td><td>uniq(C1) / uniq(C2)</td></tr><tr><td align="center">*</td><td>Multiplication</td><td>uniq(C1) * uniq(C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Numeric Transformations" %}

<table><thead><tr><th width="122">Function</th><th width="346">Description</th><th>Usage</th></tr></thead><tbody><tr><td>abs()</td><td>Return the absolute value of a number</td><td>abs(C1)</td></tr><tr><td>toInt8()</td><td>Converts a value to an 8-bit integer</td><td>toInt8(C1)</td></tr><tr><td>toInt16()</td><td>Converts a value to an 16-bit integer</td><td>toInt16(C1)</td></tr><tr><td>toInt32()</td><td>Converts a value to an 32-bit integer</td><td>toInt32(C1)</td></tr><tr><td>toInt64()</td><td>Converts a value to an 64-bit integer</td><td>toInt64(C1)</td></tr><tr><td>toString()</td><td>Converts a value to a string</td><td>toString(C1)</td></tr></tbody></table>
{% endtab %}

{% tab title="Transformations" %}

<table><thead><tr><th width="193">Function</th><th width="269">Description</th><th>Usage</th></tr></thead><tbody><tr><td>toTimeStamp()</td><td>Converts a value to timestamp</td><td>toTimeStamp(C1)</td></tr><tr><td>toWeekDay()</td><td>Converts a date to the corresponding day of the week</td><td>toWeekDay(C1)</td></tr><tr><td>toUTCHour()</td><td>Converts a time to its UTC Hour</td><td>toUTCHour(C1)</td></tr><tr><td>toMonth()</td><td>Converts a date to its corresponding month</td><td>toMonth(C1)</td></tr><tr><td>toDate()</td><td>Converts a value to a date format</td><td>toDate(C1)</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### Custom Filters

You can filter the data in the final output on the dashboard according to your needs.

Choose whether to include data using the **=** operator or exclude it using the **!=** operator. You can also use the regex operator and provide the regex formula.

### Customize

<figure><img src="/files/f3OguF6gHz0630YgbsB7" alt=""><figcaption></figcaption></figure>

**Color:** You can customize the color for the graph.

**Graph Type:** You can select between area and line graph.

**Font Size:** You can customize the font size for Value and Unit.

**Font Color:** You can customize the font color for Value and Unit.

**Trend value type:** You can select one of the following trend value types.

1. Average
2. Median
3. Min
4. Max
5. Sum

**Dimension Units:**

Select the unit from the dropdown to be displayed on the dashboard.

Following unit options are available

{% tabs %}
{% tab title="Time" %}
Second = sec

Minutes = mins

Hours = hrs

Days = days

Week = week
{% endtab %}

{% tab title="Numbers" %}
Thousand = K

Lakh = L

Million = M

Billion = B
{% endtab %}
{% endtabs %}

### View Chart

Click on View Chart to preview it before adding it to the dashboard.


# Pie Chart/Advanced Pie Chart

This Visualization breaks down data into segments, illustrating each category's contribution to the whole.

<figure><img src="/files/T8qSn5R8CcLNkIGkrtqT" alt=""><figcaption></figcaption></figure>

### Data Visualization

Enter the following values as per the requirement.

<figure><img src="/files/23S8oeOlKbfU2c5Nnl1G" alt=""><figcaption></figcaption></figure>

### Name of Visualization

Enter the name of your Visualization widget, which will appear on your dashboard.

### Identifier

Select the column name from the dropdown to use as the identifier for counting distribution in the pie chart.

### Dimension

Select the column name from the dropdown to divide the pie chart into slices based on its distinct values.

### Custom Filters

You can filter the data in the final output on the dashboard according to your needs.

Choose whether to include data using the **=** operator or exclude it using the **!=** operator. You can also use the regex operator and provide the regex formula.

### Customize

<figure><img src="/files/wd829ysRBzZ5MMxn2uyY" alt=""><figcaption></figcaption></figure>

**Color:** You can customize the coloring for the pie chart.

**Pie Chart Type:** You can select whether you want Normal Pie Chart or Donut.

**Dimension Units:**&#x20;

Select the unit from the dropdown to be displayed on the dashboard.

Following unit options are available

{% tabs %}
{% tab title="Time" %}
Second = sec

Minutes = mins

Hours = hrs

Days = days

Week = week
{% endtab %}

{% tab title="Numbers" %}
Thousand = K

Lakh = L

Million = M

Billion = B
{% endtab %}
{% endtabs %}

### View Chart

Click on View Chart to preview it before adding it to the dashboard.


# Table

This visualization fetches only the required dimensions from the database. You can also add a derived dimension using the expression builder to calculate the values.

<figure><img src="/files/Ir3sac4nZUDuUMcPxr7y" alt=""><figcaption></figcaption></figure>

### Dimension Type

Select normal or derived dimension type for your column/dimension in the visualization table.

### Alias

Enter the name for your column/dimension, which will appear on your dashboard.

### Derived Formula

Select the column names from the dropdown which you want to use to calculate your new derived dimension.

### Expression Builder

Start typing the function you want to use and select it from the suggestions. Then, place the cursor inside the brackets and type the property name you selected in Properties as the function parameter for calculations. The aggregate function will be applied on the output of this expression builder.

The following options are available in the Expression Builder. `Ci` represents the attributes/properties selected by you

{% tabs %}
{% tab title="Arithmetic Functions" %}

<table><thead><tr><th width="172">Function</th><th width="287">Attribute Structure</th><th>Usage</th></tr></thead><tbody><tr><td>sum()</td><td>(attribute)</td><td>sum(C1)</td></tr><tr><td>sumIf()</td><td>(attribute, filter)</td><td>sumIf(C1, conditions)</td></tr><tr><td>avg()</td><td>(attribute)</td><td>avg(C1)</td></tr><tr><td>avgIf()</td><td>(attribute, filter)</td><td>avgIf(C1, conditions)</td></tr><tr><td>count()</td><td>(attribute)</td><td>count(C1)</td></tr><tr><td>countIf()</td><td>(attribute, filter)</td><td>countIf(C1, conditions)</td></tr><tr><td>uniq()</td><td>(attribute)</td><td>uniq(C1)</td></tr><tr><td>uniqIf()</td><td>(attribute, filter)</td><td>uniqIf(C1, conditions)</td></tr><tr><td>min()</td><td>(attribute)</td><td>min(C1)</td></tr><tr><td>max()</td><td>(attribute)</td><td>max(C1)</td></tr><tr><td>least()</td><td>(attribute1, attribute2)</td><td>least(C1, C2)</td></tr><tr><td>greatest()</td><td>(attribute1, attribute2)</td><td>greatest(C1, C2)</td></tr><tr><td>date_diff()</td><td>(return type, attribute1, attribute2)</td><td>date_diff('second', C1, C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Operators" %}

<table><thead><tr><th width="125" align="center">Operator</th><th>Action</th><th>Example Usage</th></tr></thead><tbody><tr><td align="center">+</td><td>Addition</td><td>uniq(C1) + uniq(C2)</td></tr><tr><td align="center">-</td><td>Subtraction</td><td>uniq(C1) - uniq(C2)</td></tr><tr><td align="center">/</td><td>Division</td><td>uniq(C1) / uniq(C2)</td></tr><tr><td align="center">*</td><td>Multiplication</td><td>uniq(C1) * uniq(C2)</td></tr></tbody></table>
{% endtab %}

{% tab title="Numeric Transformations" %}

<table><thead><tr><th width="122">Function</th><th width="346">Description</th><th>Usage</th></tr></thead><tbody><tr><td>abs()</td><td>Return the absolute value of a number</td><td>abs(C1)</td></tr><tr><td>toInt8()</td><td>Converts a value to an 8-bit integer</td><td>toInt8(C1)</td></tr><tr><td>toInt16()</td><td>Converts a value to an 16-bit integer</td><td>toInt16(C1)</td></tr><tr><td>toInt32()</td><td>Converts a value to an 32-bit integer</td><td>toInt32(C1)</td></tr><tr><td>toInt64()</td><td>Converts a value to an 64-bit integer</td><td>toInt64(C1)</td></tr><tr><td>toString()</td><td>Converts a value to a string</td><td>toString(C1)</td></tr></tbody></table>
{% endtab %}

{% tab title="Transformations" %}

<table><thead><tr><th width="193">Function</th><th width="269">Description</th><th>Usage</th></tr></thead><tbody><tr><td>toTimeStamp()</td><td>Converts a value to timestamp</td><td>toTimeStamp(C1)</td></tr><tr><td>toWeekDay()</td><td>Converts a date to the corresponding day of the week</td><td>toWeekDay(C1)</td></tr><tr><td>toUTCHour()</td><td>Converts a time to its UTC Hour</td><td>toUTCHour(C1)</td></tr><tr><td>toMonth()</td><td>Converts a date to its corresponding month</td><td>toMonth(C1)</td></tr><tr><td>toDate()</td><td>Converts a value to a date format</td><td>toDate(C1)</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### Final Transformation

Choose how you want your final query result in the new derived column to be from second to timestamp, milliseconds to timestamp, timestamp, days, hour, month or date.

### Custom Filters

You can filter the data in the final output on the dashboard according to your needs.

Choose whether to include data using the **=** operator or exclude it using the **!=** operator. You can also use the regex operator and provide the regex formula.

### View Chart

Click on View Chart to preview it before adding it to the dashboard.


# Insights


# Activation Analysis

The future depends on what we do in the present - Mahatma Gandhi

***"what my users should do in the pre period to retain/uninstall/ activate to specific event in the post period". - Apxor Insights***

### Objective:

To figure out what are the actions that are taken by the user inside the app are leading to certain metrics like Retention, Churn or Doing a aha moment and many more.

### How to Do:

![](/files/FSgv1viPyJJlYSrWQbtC)

#### Pre Period:

* Select the user journey days in the app in which you believe the opportunity window to nudge the user that will lead for the conversion event in the post period
* Include a event or list of events, on which you are sure that they will have the impact on the conversion event
* Exclude a event or list of events, which you don’t want to include this analysis, might be some SYSTEM EVENTS etc

#### Post Period:

* Select the user journey days in the app in which the conversion event should happen
* Select Metrics such as “Retention” or “Activation”
  * Retention: Opening the app in the post period
  * Activation: Select the event that you want to label as the conversion event

#### Users:

* Select whether this analysis should be performed on
  * All users: who ever opened the app
  * Segment: A pre defined segment based on certain specific user behavior
  * Cohort: A fixed set of users, that you obtained it from some other platform

Once you fill these details, click on “Generate Results”

**Note:**

The report generation might take 2 to 3 minutes based upon the data that is being analyzed

### Results:

![](/files/4LGBFu4NaidAb3pRe3dO)

* By default, the analysis will be run on the last 30 days data, and once can change to last 15Days or last 7 Days.

The table will provide the following:

* Event: the event name that is done in the pre period
* Impact: indicates whether it has the positive impact on the metric selected during the post period
* Score: It is the uplift in the conversion when the user has done this event in the pre-period , compared to just opening in the app
* Confidence: It is the statistical significance that doing this event has significantly effect on the conversion during the post period. Usually the events that bear ≥0.95 can be considered as significant events that have impact on the conversions
* % Users: It is vital to observe the percentage of users that have done the specific event in the pre period. One can considers such events that are done by at lease 1% of the users in the pre period

From the above table, one can select the events for further analysis based on the frequency that the specific action is performed:

* Pick Automatically: By checking the box “Pick Automatically”, we will select the events automatically and dig further on the **Frequency Chart**
* Using the corresponding values, pick the events you want to analyze further using the **Frequency Chart**

### Frequency Chart:

This chart lets you know how many times an event should be done ideally in the pre-period so that the user converts in the post period.

* The X-axis will denote the number of times an event is done in the pre period
* The Y-axis will denote the score, uplift from the baseline conversion that is opened the app in the pre-period
* On hovering , we can observe,
  * Event: Name of the event
  * Score: Uplift from the baseline
  * Count: the number of times the pre-event is done
  * Confidence: Statistical significance
* Using this one can observe the following patterns:
  * The score increases as the frequency increases - indicates that user must habituate to this action in the pre period
  * The score increases till N number of times and starts descending from there- indicates that the user will get vexed once he does the action N number of times
  * The score will keep steady after N number of times - indicates that there would not be much difference , once he does the action N number of times and there after
  * The score decreases as the frequency increases- indicates that the action negatively impacts the conversion


# Correlation Analysis

**“Opportunity is missed by most people because it is dressed in overalls and looks like work.” - Thomas A. Edison**

***"Am I loosing an opportunity if my users don’t do specific actions in the pre period to retain/uninstall/ activate to specific event in the post period". - Apxor Insights***

### Objective:

To figure out what are the actions that are taken by the user inside the app are leading to certain metrics like Retention, Churn or Doing a aha moment and many more and effecting the conversions heavily when they are not done in the pre period.

### How to Do:

![](/files/A8HayjS5y4Gw4j1J4ZAq)

#### Pre Period:

* Select the user journey days in the app in which you believe the opportunity window to nudge the user that will lead for the conversion event in the post period
* Include a event or list of events, on which you are sure that they will have the impact on the conversion event
* Exclude a event or list of events, which you don’t want to include this analysis, might be some SYSTEM EVENTS etc.

#### Post Period:

* Select the user journey days in the app in which the conversion event should happen
* Select Metrics such as “Retention” or “Activation”
  * Retention: Opening the app in the post period
  * Activation: Select the event that you want to label as the conversion event

#### Users:

* Select whether this analysis should be performed on
  * All users: who ever opened the app
  * Segment: A pre defined segment based on certain specific user behavior
  * Cohort: A fixed set of users, that you obtained it from some other platform

Once you fill these details, click on “Generate Results”

**Note:**

The report generation might take 2 to 3 minutes based upon the data that is being analyzed

### Results:

![](/files/VPSuKqkWbyCg2yEZVpUC)

* By default, the analysis will be run on the last 30 days data, and once can change to last 15Days or last 7 Days.

The table will provide the following:

* Event: the event name that is done in the pre period
* Correlation (F-score): quantifies the relationship between the event and the metric selected during the post period. It lies between 0 to 1 and usually ≥0.25 indicates strong correlation.
* % Users: It is vital to observe the percentage of users that have done the specific event in the pre period. One can considers such events that are done by at lease 1% of the users in the pre period

From the above table, one can select the events for further analysis based on the frequency that the specific action is performed:

* Pick Automatically: By checking the box “Pick Automatically”, we will select the events automatically and dig further on the **Correlation Table**
* Using the corresponding values, pick the events you want to analyze further using the **Correlation Table**

### Correlation Table:

This is a 2 X 2 matrix representation where the rows will denote whether the event is performed at least once or not in the pre-period and the columns will denote whether they are in the TARGET GROUP (converted) or not in the post-period.

![](/files/i3tGgqc7rylkxvILF1qT)

* the element (1,1) denotes the number of users who converted in the post period after doing the event at least once in the pre period. The uplift in the brackets is calculated from the conversion percentage of the post event or metric out of the user who opened the app at least once. It should be a positive value (Green arrow)
* the element (1,2) denotes the number of users who has not converted in the post period after doing the event at least once in the pre period. The uplift in the brackets is calculated from the non conversion percentage of the post event or metric out of the user who opened the app at least once. It should be a negative value (Red arrow)
* the element (2,1) denotes the number of users who converted in the post period after not doing the event at all in the pre period. The uplift in the brackets is calculated from the conversion percentage of the post event or metric out of the user who opened the app at least once. It should be a negative value (Red arrow)
* the element (2,2) denotes the number of users who has not converted in the post period after not doing the event at all in the pre period. The uplift in the brackets is calculated from the non conversion percentage of the post event or metric out of the user who opened the app at least once. It should be ideally a positive value (Green arrow)
* Ideally, an event is said to have a correlation with the conversion, if the diagonal elements are positive and the non diagonals are negative.

Along with the matrix, we present the following metrics to quantify the correlation.

#### Correlation Table Metrics

The correlation table draws a comparison with the confusion matrix that is being used for assessing the quality of a classification modal in machine learning.

![](/files/erJRYK7ItYkJz6KYD85F)

* **Predicted Values-**
  * **Positive (1)** - Doing the event at least once in the pre period
  * **Negative (0)** - Not doing the event at all in the pre period
* **Actual Values-**
  * **Positive (1)** - Converting or doing the post metric in the post period
  * **Negative (0)** - Non conversion or not doing the post metric in the post period
* **True Positive (TP):** Doing the event at least once in the pre period and doing the post metric in the post period
* **False Positive (FP):** Doing the event at least once in the pre period not doing the post metric in the post period
* **False Negative (FN):** Not doing the event at all in the pre period not doing the post metric in the post period
* **False Positive (FP):** Not doing the event at all in the pre period and doing the post metric in the post period

Using this, we can define and interpret the following metrics:

![](/files/GaF9ncE1n27NBLzSj7Sm)

**Accuracy:**

![](/files/vjCdN9tR0TLamfbBr5ky)

This tells you, for how many of the users, it means that doing an event in the pre period is converting in the post period and not doing the event in the pre period refers to not converting in the post period.

**Precision:**

![](/files/Kfb2eHh6UDspFbOCqHeV)

Precision tells us how many of the users who did the event in the pre period actually turned out to be converted.

Precision is a useful metric in cases where False Positive is a higher concern than False Negatives.

**Recall Or Sensitivity:**

![](/files/VpUYYuViRXkEZv0G5g0P)

Recall tells us how many of the actual converted users in the post period have done the event in the pre period

Recall is a useful metric in cases where False Negative trumps False Positive.

**F1-Score:**

![](/files/httmr9ut62BbGm6JdyvC)

**F1-score is a harmonic mean of Precision and Recall**, and so it gives a combined idea about these two metrics. It is maximum when Precision is equal to Recall.

F1-score is useful when there is no clear distinction between whether **Precision** is more important or **Recall**

**True Negative Rate Or Specificity:**

![](/files/f1tQor2nfbc6GXnAJj6D)

Specificity tells us how many of the actual non converted users in the post period have not done the event in the pre period. It is counter part of the Sensitivity.

Specificity is a useful metric in cases where False Negative trumps False Positive.

**False Positive Rate or Type-I Error:**

![](/files/FCPBNrFKjh8GzHUsEM8Q)

False Positive Rate is the percentage of users who have done the event in the pre period but not converted in the post period out of all those non converted users.

This is also called Type-1 Error. This gives us how many of the users we wrongly predicted that they will convert. This should be as minimal as it can be.

**False Negative Rate or Type-II Error:**

![](/files/VUOwPnDmXxiPxoKFWX80)

False Negative Rate is the percentage of users who have not done the event in the pre period but converted in the post period out of all those converted users.

This is also called Type-II Error. This gives us how many of the users we wrongly predicted that they will not convert. This should be as minimal as it can be.

A trade off should be taken between type-I and type-II errors in view of understanding which can be a costly mistake to commit.

**Note: Apxor by default sorts the event in the order of F1-score. But, customers should take the final decision based on the type of metric that they are considering as conversion.**


# Adding a Test Device

{% embed url="<https://youtu.be/4p3qdbJEsFY>" %}

You must select a test device for the templates that will anchor to a UI element and preview the nudges on the test device. For the same, you need to register your device as a test device with Apxor.

{% hint style="info" %}
**Note**

You need to add the test device again if you reinstall the application or clear the application data.
{% endhint %}

There are three CTAs to register a new test device from the dashboard.

1. From the Settings section

   1. Go to **Settings** in the left panel
   2. Click on Test Devices on the left side of the Settings screen&#x20;

      <figure><img src="/files/egKrCHCyTJKg1t7L21aT" alt=""><figcaption></figcaption></figure>
   3. Click on **Register Test Device** CTA in the top right corner
   4. In the pop-up that appears enter your email id. You can enter multiple email ids, press enter/return after entering your correct email id and click on the **Send Email** Button.&#x20;

      <figure><img src="/files/kOxhEubtdC8AcLod32d4" alt=""><figcaption></figcaption></figure>

   Alternatively you can click on "**Try smart way to select device**". A QR code will be shown on your device, scan the same with your mobile device's camera and click on the link shown.

   1. This will take you to your pre-installed app in the device and a pop-up will ask to add the device nickname. This nickname will be displayed to you in the dashboard which will be used to [select the test device](/product-guides/create-a-campaign/mobile#select-test-device).&#x20;

      <figure><img src="/files/ZGQ2CyI7ei7hU7kNvSqq" alt="" width="180"><figcaption></figcaption></figure>
   2. After entering the device nickname click on **Add** button. You will see a success message after this.&#x20;

      <figure><img src="/files/UEahl3v68cpbchalSdzf" alt="" width="180"><figcaption></figcaption></figure>
2. While selecting a template for a campaign that will anchor to a UI element

   1. After selecting the tooltip, coachmark or badge, while selecting the UI element, you can click on **Register New Device** under the SELECT YOUR TEST DEVICE dropdown.&#x20;

      <figure><img src="/files/Ve5VF7WzwZHdUf0kPMuo" alt=""><figcaption></figcaption></figure>
   2. In the pop-up, enter your email id/s. You can enter multiple email ids, press enter/return after entering your correct email id and click on the **Send Email** Button.&#x20;

      <figure><img src="/files/oF9UYEdDPA4y5nFmkV3K" alt=""><figcaption></figcaption></figure>

   Alternatively you can click on "**Try smart way to select device**". A QR code will be shown on your device, scan the same with your mobile device's camera and click on the link shown.

   1. This will take you to your pre-installed app in the device and a pop-up will ask to add the device nickname. This nickname will be displayed to you in the dashboard which will be used to [select the test device](/product-guides/create-a-campaign/mobile#select-test-device).&#x20;

      <figure><img src="/files/ZGQ2CyI7ei7hU7kNvSqq" alt="" width="180"><figcaption></figcaption></figure>
   2. After entering the device nickname click on **Add** button. You will see a success message after this.&#x20;

      <figure><img src="/files/UEahl3v68cpbchalSdzf" alt="" width="180"><figcaption></figcaption></figure>
3. From the Preview On Device section while designing the campaign

   1. After selecting In-App Messages template, while designing the template, you can find the **Preview On Device** section in the bottom center. Click on **No device selected**, then click on **Register New Device** in the dropdown. Refer the highlighted part in the image below.

      <figure><img src="/files/9jNLeipTG86UFu9EJAvA" alt=""><figcaption></figcaption></figure>
   2. In the pop-up, enter your email id/s. You can enter multiple email ids, press enter/return after entering your correct email id and click on the **Send Email** Button.&#x20;

      <figure><img src="/files/oF9UYEdDPA4y5nFmkV3K" alt=""><figcaption></figcaption></figure>

   Alternatively you can click on "**Try smart way to select device**". A QR code will be shown on your device, scan the same with your mobile device's camera and click on the link shown.

   1. This will take you to your pre-installed app in the device and a pop-up will ask to add the device nickname. This nickname will be displayed to you in the dashboard which will be used to [select the test device](/product-guides/create-a-campaign/mobile#select-test-device).&#x20;

      <figure><img src="/files/ZGQ2CyI7ei7hU7kNvSqq" alt="" width="180"><figcaption></figcaption></figure>
   2. After entering the device nickname click on **Add** button. You will see a success message after this.&#x20;

      <figure><img src="/files/UEahl3v68cpbchalSdzf" alt="" width="180"><figcaption></figcaption></figure>
4. You will receive an email on the mentioned email id/s from **<updates@apxor.com>** titled **Continue adding test device to Apxor.**&#x20;

   <figure><img src="/files/kooLZ3JjuDwX0qdZwUwy" alt=""><figcaption></figcaption></figure>
5. Open this email on the device you want to register with Apxor. If you are using a simulator open the email in the browser inside the simulator.
6. You will get CTAs in the email for your applications. Click on the CTA of your desired application
7. This will take you to your pre-installed app in the device and a pop-up will ask to add the device nickname. This nickname will be displayed to you in the dashboard which will be used to [select the test device](/product-guides/create-a-campaign/mobile#select-test-device).&#x20;

   <figure><img src="/files/ZGQ2CyI7ei7hU7kNvSqq" alt="" width="180"><figcaption></figcaption></figure>
8. After entering the device nickname click on **Add** button. You will see a success message after this.&#x20;

   <figure><img src="/files/UEahl3v68cpbchalSdzf" alt="" width="180"><figcaption></figcaption></figure>

You have successfully registered the new device. [Create your campaign](/product-guides/create-a-campaign/mobile) now.


# Preview vs. Test vs. Publish

| Preview                                                                                                                                                                                                                    | Test                                                                                                                                                                            | Publish                                                                                                                                                                                     |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Preview allows you to see how a configured nudge (tooltip, in-app message, coachmark or badge) will appear on a selected test device.                                                                                      | Test mode is used to display the configured nudge on a set of selected test devices after specific context or conditions are met by the users on those devices.                 | Publish means launching the campaign for all the targeted users, making the configured nudges visible to end users.                                                                         |
| It doesn't check for the set context to be met. In other words, it shows you the nudge as it would look, but it doesn't take into account whether the conditions or criteria for displaying the nudge have been satisfied. | Test mode considers the context, which means the nudge will only be shown to the selected test devices on their devices if they meet the specified criteria or conditions.      | This is the live deployment of the nudge to the broader audience, and it occurs once the specified context or criteria are met on the end users' devices.                                   |
| Preview is typically used for internal testing or to visualize the appearance of a nudge without affecting real end users.                                                                                                 | Testing is a crucial step to ensure that the nudge is displayed correctly to the intended users under the right circumstances. This is also typically used for internal testing | Publishing the campaign is the final step where the nudge is presented to all users who meet the predefined conditions, and it is part of the active user engagement or marketing strategy. |

In summary, Preview is for internal testing and visualization, Test ensures the nudge is shown to the right users when specific conditions are met, and Publish releases the nudge to the broader audience for whom all the pre-set criteria are satisfied.


# Dynamic Script

You can write a script (a new language that Apxor has created which somewhat looks like Javascript) instead of plain text to substitute 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 a keyed tag (apx\_view\_tag).

#### The Apxor Language <a href="#the-apxor-language" id="the-apxor-language"></a>

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 dialogue that Apxor Dashboard provides to you.

We support the 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 the string

```javascript
format(
  "Hello {}. We are excited to give you {} reward points. You can see these points in the Rewards section:",
  UserName,
  toInt(RewardPoints)
);
```

* Conditional Dynamic Text

```javascript
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

```javascript
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"));
```


# Partner Integrations


# Mixpanel

Easily sync user cohorts from Mixpanel to Apxor

### Prerequisites

1. A Mixpanel account
2. User cohorts that you want to send to Apxor

### Step 1. Select Integrations from the "Data Management" dropdown

<figure><img src="/files/6joubw2hbRPYi8IvNI1H" alt=""><figcaption></figcaption></figure>

### Step 2. Scroll down and select the "Custom Webhook" option. Click on "Connect"

<figure><img src="/files/1KuTS2A9oIiPhFEbEYgJ" alt=""><figcaption></figcaption></figure>

### Step 3. Now, enter the URL. The URL will be

**“<https://server.apxor.com/v1/cohorts/mxp/sync/:appId”>**, where **appId** is the unique identifier of the customer in the Apxor dashboard.

<figure><img src="/files/eaoyABdrRJHeXvf4xzbK" alt=""><figcaption></figcaption></figure>

### Step 4. Enter ApxCohortSync in the username field and auth token given by the Apxor team in the password field. Click "Continue".

<figure><img src="/files/JPmM0i5D3alxdlgRO1uV" alt=""><figcaption></figcaption></figure>

### Step 5. Once a custom webhook is created, you can export the cohorts to that webhook. Navigate to the Data Management dropdown and select "Cohorts."

<figure><img src="/files/dRbI1mYSVud66yHNX5T8" alt=""><figcaption></figcaption></figure>

### Step 6. Click on the options button for a cohort and export it to the webhook you just created.

<figure><img src="/files/o7w5gavdxFDTNh4Xxf3z" alt=""><figcaption></figcaption></figure>

### Step 7. After this, you will be able to export Cohorts from Mixpanel to Apxor as a One-time export or a Recurring sync.

### Step 8. The same cohort will be visible on the Apxor dashboard in the "Cohorts" tab, with Source set as "MIXPANEL". It might take up to 20 minutes for the cohort to sync in Apxor on the cohorts page.


# MoEngage

Easily synchronize user segments from MoEngage to Apxor

### Prerequisites: <a href="#id-6ce55d5a-a1e9-456d-8172-153c8d629f23" id="id-6ce55d5a-a1e9-456d-8172-153c8d629f23"></a>

* MoEngage Account
* Segments that you want to send to Apxor

## 1. Create a Custom Destination

### **Step 1:** Open the Moengage dashboard and hover on the left panel

* Click on <mark style="color:red;">`App Marketplace`</mark>

<figure><img src="/files/4MUP4KK15wgdgQsgeSsT" alt=""><figcaption></figcaption></figure>

### Step 2: Scroll down and click on <mark style="color:red;">`Custom destinations`</mark>

<figure><img src="/files/fYxex6hNpTHM2r4oU7kG" alt=""><figcaption></figcaption></figure>

### Step 3: Click on <mark style="color:red;">`Add Custom Destination`</mark>

<figure><img src="/files/9DLD8UzXbix2KLZQ9Pch" alt=""><figcaption></figcaption></figure>

### Step 4: Give a name to the destination and click on <mark style="color:red;">`Add`</mark>

<figure><img src="/files/nkOrbsA9Gdr2pXUfCq0R" alt=""><figcaption></figcaption></figure>

## 2. Create an Integration

### **Step 1:** Click on Integrate and then select <mark style="color:red;">`+ Add Integration`</mark>

<figure><img src="/files/61M3LZzmWS3TxwvtsUQ4" alt=""><figcaption></figcaption></figure>

### Step 2: Enter a name to identify the integration

* Select the POST method
* Now, enter the URL as “\*\*<https://server.apxor.com/v1/cohorts/moe/sync/:appId**”>, where <mark style="color:red;">`appId`</mark> is the customer's unique identifier in the Apxor dashboard.

<figure><img src="/files/S7HVqqarag7xrnvJY3Lv" alt=""><figcaption></figcaption></figure>

### Step 3: Authentication

Under Authentication, select <mark style="color:red;">`Basic Auth`</mark> and enter **ApxCohortSync** in the *username* field and <mark style="color:red;">**`auth token`**</mark> given by the Apxor team in the *password* field.

<figure><img src="/files/5NXI97UG1l68ugdEfsVX" alt=""><figcaption></figcaption></figure>

### Step 4: Configure

* In **Map user identities**, set <mark style="color:red;">`Destination identifier`</mark> as **custom\_user\_id**
* In the **Request body,** change `add_users` to <mark style="color:orange;">`add_members`</mark> and `remove_users` to <mark style="color:orange;">`remove_members`</mark>
* Set the **Throttle** to **5000** users at a time

<figure><img src="/files/zIcUJVOvmAtKZ00mYR1w" alt=""><figcaption></figcaption></figure>

* The request preview should match the highlights in the snapshot below
* Click on Next

<figure><img src="/files/zC6CWCHNm4AGFYQ7SPd6" alt=""><figcaption></figcaption></figure>

### Step 5: Test

* In the test page enter a example custom\_user\_id in the **User value** and click on **test**
* The response should be **Success** with response code **200**

<figure><img src="/files/nC96sRhK05G7MTuPZItI" alt=""><figcaption></figcaption></figure>

* Click on Add integration
* Integration has been created successfully!

## 3. Segment Sync

### Step 1: Navigate to **All Segments** tab in the left panel

Navigate to **All Segments** tab in the left panel and click on the options button for the segment you want to sync and select **Sync Segment**

<figure><img src="/files/Qv7tR7YggdfAXmYJdHPG" alt=""><figcaption></figcaption></figure>

### Step 2: Click on the destination dropdown

* Now click on the **Destination** drop-down and select the integration that you wish to sync with.
* You can also add a Destination and create an Integration from the **Add Destination** option in the drop-down menu. Follow the above procedures.

<figure><img src="/files/cqQAu8Fxr0RjlM1qQzIe" alt=""><figcaption></figcaption></figure>

* Select the sync frequency **(one-time or recurring)**, configure notification settings, and click on **Save Sync**

<figure><img src="/files/79aiALvpgcwWXvE4I22X" alt=""><figcaption></figcaption></figure>

* The segment sync status and history can be seen on the **Segment Sync Info** page

<figure><img src="/files/dFSMOKFaBwYWNqfDcCsU" alt=""><figcaption></figcaption></figure>

* The same segment will be visible on the **Apxor** dashboard in the "**Cohorts**" tab, with the source set as "MOENGAGE". It might take up to 20 minutes for the segment to sync with Apxor on the cohorts page.


# Amplitude

This integration lets you sync cohorts from Amplitude to Apxor.

## Get API key from Apxor Dashboard

1. On Apxor’s dashboard, navigate to the Connections tab.
2. Click on Amplitude under the Sources section.
3. Click Connect and copy the API key.

## Amplitude Setup

1. In Amplitude Data, click Catalog and select the Destinations tab.
2. In the Cohort section, click Apxor.
3. Enter Name and paste in the API key you copied from Apxor.
4. Map the same Amplitude User\_ID with the primary key from the Apxor panel.
5. Save when finished.

## Sync a cohort

To sync your first cohort, follow these steps:

1. In Amplitude, open the cohort you want to sync, then click Sync.
2. Select Apxor, then click Next.
3. Choose the account you want to sync to.
4. Choose the sync cadence.
5. When finished, save your work.




---

[Next Page](/llms-full.txt/1)

