Userpilot Cardova Module enables you to capture user insights and deliver personalized in-app experiences in real time. With just a one-time setup, you can immediately begin leveraging Userpilot’s analytics and engagement features to understand user behaviors and guide their journeys in-app. This document provides a step-by-step walkthrough of the installation and initialization process, as well as instructions on using the SDK’s public APIs.

Prerequisites

Cordova

Your application should use Cordova version 10+ with cordova-cli installed globally.

Android

Your application’s build.gradle must have a compileSdkVersion of 34+ and minSdkVersion of 21+, and use Android Gradle Plugin (AGP) 8+.
<platform name="android">
    <preference name="android-minSdkVersion" value="21" />
    <preference name="android-compileSdkVersion" value="35" />
    <preference name="android-targetSdkVersion" value="35" />
    <preference name="GradlePluginKotlinEnabled" value="true" />
</platform>
Android Gradle Plugin, If you are using AGP 8.8.0+, the Android Gradle Plugin will automatically use Build Tools version 35.0.0, regardless of the value you specify. comment it or update its value to buildToolsVersion = 35.0.0 To ensure full compatibility with our SDK, please upgrade your app’s target and compile SDK version to 35.

iOS

Your application must target iOS 13+ to install the SDK, Update the iOS project xcodeproj to set the deployment target. Update your config.xml to set the deployment target.
<platform name="ios">
    <preference name="deployment-target" value="13.0" />
    <preference name="SwiftVersion" value="5.0" />
</platform>

Installation

Add the Userpilot Cordova Plugin dependency to your application.
  1. In your app’s root directory, install the Userpilot Cordova Plugin. You can fetch the latest version from here.
cordova plugin add @userpilot/cordova
  1. Prepare your platforms:
cordova prepare

Initialization

To use Userpilot, initialize it once in your Application class. This ensures the SDK is ready as soon as your app starts. Update your Application class. Replace <APP_TOKEN> with your Application Token, which can be fetched from your Environments Page.
// API
setup(token, options, onSuccess, onError)

// Example
document.addEventListener('deviceready', function() {
	const options = {
        logging: true,         // Enable/disable SDK logging
        useInAppBrowser: true  // Enable/disable in-app browser for links - Works for Android
    };

    window.userpilot.setup('<APP_TOKEN>', options,
        function(success) {
            console.log('Userpilot initialized successfully');
        },
        function(error) {
            console.error('Failed to initialize Userpilot:', error);
        }
    );
}, false);

Using the SDK

Once initialized, the SDK provides straightforward APIs for identifying users, tracking events, and screen views.

Identifying Users

This API is used to identify unique users and companies (groups of users) and set their properties. Once identified, all subsequent tracked events and screens will be attributed to that user.]
ImportantIt’s crucial to call the Userpilot identify function; without it, Userpilot won’t be able to recognize your users, and mobile content won’t be displayed to them.
Recommended Usage:
  • On user authentication (login): Immediately call identify when a user signs in to establish their identity for all future events.
  • On app launch for authenticated users: If the user has a valid authenticated session, call identify at app launch.
  • Upon property updates: Whenever user or company properties change.
// API
identify(userID, properties, company, onSuccess, onError)

// Example
window.userpilot.identify(
    '<USER_ID>',
    {
        'name': 'John Doe', 
        'email': 'user@example.com', 
        'created_at': '2019-10-17', 
        'role': 'Admin'
    },
    {
        'id': 'company123', 
        'name': 'Acme Labs', 
        'created_at': '2019-10-17', 
        'plan': 'Free'
    },
    function(success) {
        console.log('User identified successfully');
    },
    function(error) {
        console.error('Failed to identify user:', error);
    }
);
Properties Guidelines
  • Key id is required in company properties, to identify a unique company.
  • Userpilot supports String, Numeric, and Date types.
  • Make sure you’re sending date values in ISO8601 format.
  • If you are planning to use Userpilot’s localization features, make sure you are passing user property locale_code with a value that adheres to ISO 639-1 format.
  • Userpilot’s reserved properties’ have pre-determined types and improve profiles interface in the dashboard:
    • Use key email to pass the user’s email.
    • Use key name to pass the user’s or company’s name.
    • Use key created_at to pass the user’s or company’s signed up date.
Notes
  • Ensure the User ID source is consistent across Web, Android, and iOS.
  • While properties are optional, setting them enhances Userpilot’s segmentation capabilities.

Tracking Screens (Required)

Calling screen is crucial for unlocking Userpilot’s core engagement and analytics capabilities. When a user navigates to a particular screen, invoking screen records that view and triggers any eligible in-app experiences. Subsequent events are also attributed to the most recently tracked screen, providing context for richer analytical insights. For these reasons, we strongly recommend tracking all of your app’s screen views.
// API
screen(screenName, onSuccess, onError)

// Example
window.userpilot.screen('Profile',
    function(success) {
        console.log('Screen tracked successfully');
    },
    function(error) {
        console.error('Failed to track screen:', error);
    }
);

Tracking Events

Log any meaningful action the user performs. Events can be button clicks, form submissions, or any custom activity you want to analyze. Optionally, you can pass metadata with the event to provide specific context.
// API
track(name, properties, onSuccess, onError)

// Example
window.userpilot.track('Added to Cart', 
    { 
        itemId: 'sku_456', 
        price: 29.99 
    },
    function(success) {
        console.log('Event tracked successfully');
    },
    function(error) {
        console.error('Failed to track event:', error);
    }
);

Logging Out

When a user logs out, call logout() to clear the current user context. This ensures subsequent events are no longer associated with the previous user.
// API
logout(onSuccess, onError)

// Example
window.userpilot.logout(
    function(success) {
        console.log('User logged out successfully');
    },
    function(error) {
        console.error('Failed to logout user:', error);
    }
);

Anonymous Users

If a user is not authenticated, call anonymous() to track events without a user ID. This is useful for pre-signup flows or guest user sessions.
// API
anonymous(onSuccess, onError)

// Example
window.userpilot.anonymous(
    function(success) {
        console.log('Anonymous user set successfully');
    },
    function(error) {
        console.error('Failed to set anonymous user:', error);
    }
);
Anonymous users count towards your Monthly Active Users usage. Consider your MAU limits before using this API.

Experience

Triggers a specific experience programmatically using it’s ID. This API allows you to manually initiate an experience within your application.
// API
triggerExperience(experienceId, onSuccess, onError)

// Example
window.userpilot.triggerExperience('<EXPERIENCE_ID>',
    function(success) {
        console.log('Experience triggered successfully');
    },
    function(error) {
        console.error('Failed to trigger experience:', error);
    }
);
To end current active experience
// API
endExperience(onSuccess, onError)

// Example
window.userpilot.endExperience(
    function(success) {
        console.log('Experience ended successfully');  
    },
    function(error) {
        console.error('Failed to end experience:', error);
    }
);

SDK callbacks

Userpilot SDK provides three types of callbacks:
  • Navigation Listener
  • Analytics Listener
  • Experience Listener
Triggered when a deep link is invoked from an experience or push notification.

Parameters

  • url: string – The custom deep link URL that should be handled by the host (client) app.

Analytics Listener

Triggered when the client app reports an analytics event to the SDK.

Parameters

  • analytic: string – The name or type of the analytic event ("Identify" , "Screen" , "Event" ).
  • value: string – The value associated with the event.
  • properties: Map<string, any> – Additional key-value pairs providing context for the event.

Experience Listener

Provides callbacks related to the lifecycle of experiences and their steps within the SDK.

Callbacks

  • onExperienceStateChanged(id: int, state: string) Called when the overall state of an experience changes.
    • id : Experience ID (optional)
    • state : New state — "Started", "Completed", "Dismissed", "Skipped", or "Submitted"
    • experienceType : "Flow", "Survey", or "NPS"
  • onExperienceStepStateChanged(id: int, state: string, experienceId: int, step: int, totalSteps: int) Called when the state of a specific step in an experience changes.
    • id : Step ID
    • state : New step state — "Started", "Completed", "Dismissed", "Skipped", or "Submitted"
    • experienceId : Associated experience ID
    • experienceType : "Flow", "Survey", or "NPS"
    • step : Current step index (optional)
    • totalSteps : Total number of steps in the experience (optional)
Note: Both onExperienceStateChanged and onExperienceStepStateChanged events are sent under the key UserpilotExperienceEvent .
// Register for callbacks
window.userpilot.registerCallbacks(
    function(event) {
        console.log('Callback received:', event);
    },
    function(error) {
        console.error('Failed to register callbacks:', error);
    }
);

// Set up individual event listeners
window.userpilot.onUserpilotNavigationEvent((data) => {
    console.log('Navigation Event:', data);
    // Handle deep link navigation
    if (data.url) {
        handleDeepLink(data.url);
    }
});

window.userpilot.onUserpilotAnalyticsEvent((data) => {
    console.log('Analytics Event:', data);
});

window.userpilot.onUserpilotExperienceEvent((data) => {
    console.log('Experience Event:', data);
});

Push Notifications

Userpilot SDK supports handling push notifications to help you deliver targeted messages and enhance user engagement. For Expo apps, setting up Userpilot Push Notifications requires configuration through the Expo Config Plugin. Refer to the official documentation for detailed setup instructions.

AndroidSetup:

Prerequisites It is recommended to configure your Android push settings in the Userpilot Settings Studio before setting up push notifications in your app. To obtain the required keys and configuration details, please refer to the Android Push Notification Guide. Setting up This guide assumes this is the first time code is being added to your project related to setting up push notifications using Google services (Firebase Cloud Messaging). In the case your project is already configured for push, proceed to Step 2. Step 1. Add Firebase Follow the steps in the official Google documentation on How to add Firebase to your project. Step 2. Request Notifications Permission Starting from Android 13 (API level 33), apps **must explicitly request the **POST_NOTIFICATIONS permission in order to display push notifications.
  • Declare the Permission in the Manifest file, under example -> android -> app -> manifest
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  • Request the Permission at Runtime
For example using : "cordova-plugin-android-permissions": "^1.1.5"
// index.js
document.addEventListener('deviceready', onDeviceReady, false);

function onDeviceReady() {
  const permissions = cordova.plugins.permissions;

  const notificationPermission = permissions.POST_NOTIFICATIONS;

  permissions.checkPermission(notificationPermission, function(status) {
    if (!status.hasPermission) {
      // Request the permission
      permissions.requestPermission(notificationPermission, function(status) {
        if (status.hasPermission) {
          console.log("✅ Notification permission granted");
        } else {
          console.warn("❌ Notification permission denied");
        }
      }, function() {
        console.error("⚠️ Failed to request permission");
      });
    } else {
      console.log("✅ Notification permission already granted");
    }
  }, function() {
    console.error("⚠️ Failed to check permission");
  });
}
Step 3. Add the Userpilot Firebase Messaging Service Firebase connects to your app through a <service> . Go to your Manifest file under example -> android -> app -> manifest and add:
<service
  android:name="com.userpilot.pushNotifications.UserpilotFirebaseMessagingService"
  android:exported="false">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>
If your project has already added a child of FirebaseMessagingService, you can leave it as is, and instead plug in UserpilotFirebaseMessagingService to your service class.
import com.userpilot.pushNotifications.UserpilotFirebaseMessagingService
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class CustomFirebaseMessageService : FirebaseMessagingService() {
    override fun onMessageReceived(message: RemoteMessage) {
        if (UserpilotFirebaseMessagingService.handleMessage(baseContext, message)) {
           // handled as Userpilot message
           return
        }

        // not Userpilot message
        super.onMessageReceived(message)
        }

    override fun onNewToken(token: String) {
       // sets new token from the callback
       UserpilotFirebaseMessagingService.setToken(token)

       super.onNewToken(token)
    }
}
Step 4. Deep Linking: Launching Your App When a Notification is Clicked To ensure your app opens automatically when a Userpilot push notification is clicked, you need to configure an intent-filter in your app’s **entry **Activity under example -> android -> app -> manifest . This configuration enables deep linking based on a custom scheme defined in your app. Define the Deep Link Scheme In your userpilot.xml configuration file, you should have defined a value for userpilot_push_notification , check Step 5. Update Manifest file to include the intent-filter as below. Make sure to set host="sdk" .
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"
  android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
  android:launchMode="singleTask"
  android:windowSoftInputMode="adjustResize"
  android:exported="true">
  <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
  <intent-filter>
    <data android:scheme="userpilot_push_notification" android:host="sdk"/>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
  </intent-filter>
</activity>
Inside your MainActivity under example -> android -> app , pass intent to Userpilot SDK to handle it.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Cordova implementation
       
    handleIntent(getIntent());
}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    handleIntent(intent);
}

private void handleIntent(Intent intent) {
    if (UserpilotCordovaPlugin.handleIntent(intent)) return;
}
Step 5. Customizing The Userpilot SDK allows for some customizations that will change how your messages will be delivered to your end users. These properties are set as <resources> properties. In order change those properties create a file under res/values under example -> android -> app and set it to desired values.
<resources>
    <!-- Small icon displayed in the notification bar -->
    <drawable name="userpilot_notification_small_icon">@drawable/ic_notification</drawable>

    <!-- Accent color applied to notification UI elements -->
    <color name="userpilot_notification_color">#6765E8</color>

    <!-- Determines if notifications are visible on the lock screen (true = visible) -->
    <bool name="userpilot_notification_channel_lock_screen_visibility">true</bool>

    <!-- Enables notification lights for the channel -->
    <bool name="userpilot_notification_channel_enable_light">true</bool>

    <!-- Enables vibration for the notifications -->
    <bool name="userpilot_notification_channel_enable_vibration">true</bool>

    <!-- Unique ID for the notification channel -->
    <string name="userpilot_notification_channel_id">com.userpilot.general.channel</string>

    <!-- Human-readable name for the notification channel -->
    <string name="userpilot_notification_channel_name">General</string>

    <!-- Description shown to the user about this notification channel -->
    <string name="userpilot_notification_channel_description">Default channel used for app messages</string>

    <!-- Importance level of the notification channel (0 = NONE, 5 = MAX) -->
    <integer name="userpilot_notification_channel_importance">3</integer>

    <!-- Key used to identify Userpilot push notifications -->
    <string name="userpilot_push_notification">userpilot_push_notification</string>
</resources>

iOS Setup

Prerequisites It is recommended to configure your iOS push settings in the Userpilot Settings Studio before setting up push notifications in your app. To obtain the required keys and configuration details, please refer to the iOS Push Notification Guide. Enabling Push Notification Capabilities In Xcode, navigate to the Signing & Capabilities section of your main app target and add the Push Notifications capability. Configuring Push Notifications The Userpilot iOS SDK supports receiving push notification so you can reach your users whenever the moment is right. There are two options for configuring push notification: automatic or manual. Automatic configuration is the quickest and simplest way to configure push notifications and is recommended for most customers. Automatic App Configuration Automatic configuration takes advantage of swizzling to automatically provide the necessary implementations of the required UIApplicationDelegate and UNUserNotificationCenterDelegate methods. To enable automatic configuration, call Userpilot.enableAutomaticPushConfig() from UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:) inside example -> ios -> AppDelegate.swift .
func application(
_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
   // Automatically configure for push notifications
   Userpilot.enableAutomaticPushConfig()

   // Override point for customization after application launch.
}
Automatic configuration seamlessly integrates with your app’s existing push notification handling. It processes only Userpilot notifications, while ensuring that all other notifications continue to be handled by your app’s original logic. Manually Configuring Push Notifications Step 1. Enable push capabilities
Step 2. Register for push notifications
Step 3. Set push token for Userpilot
Step 4. Enable push response handling
Step 5. Configure foreground handling
Full source code:
// AppDelegate+PushNotification.swift

import Foundation
import UserNotifications
import UserpilotReactNative

typealias UserpilotImplementation = Implementation

extension AppDelegate: UNUserNotificationCenterDelegate {
    /// Call from `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`
    func setupPush(application: UIApplication) {
        requestPushNotificationPermission()
        
        // 1: Register to get a device token
        application.registerForRemoteNotifications()

        UNUserNotificationCenter.current().delegate = self
    }

    // MARK: - Push Notification Permission Request, In case you didn't request it from your Cordova app.
    private func requestPushNotificationPermission() {
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]

        // Check if the app has already been authorized
        UNUserNotificationCenter.current().getNotificationSettings { (settings) in
            if settings.authorizationStatus == .authorized {
                // App is already authorized for push notifications
                // Register for remote notifications again to get the device token
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            } else {
                // If not authorized, request permission
                UNUserNotificationCenter.current().requestAuthorization(options: options) { (granted, error) in
                    if granted {
                        DispatchQueue.main.async {
                            UIApplication.shared.registerForRemoteNotifications()
                        }
                    } else {
                        if let errorDescription = error?.localizedDescription {
                            print("Permission denied or failed to request: \(errorDescription)")
                        } else {
                            print("Permission denied or failed to request: Unknown error")
                        }
                    }
                }
            }
        }
    }

    // 2: Pass device token to Userpilot
    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      UserpilotCordovaPlugin.setPushToken(deviceToken)
    }

    // 3: Pass the user's response to a delivered notification to Userpilot
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        if UserpilotCordovaPlugin.didReceiveNotification(response: response, completionHandler: completionHandler) {
            return
        }

        completionHandler()
    }

    // 4: Configure handling for notifications that arrive while the app is in the foreground
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        if #available(iOS 14.0, *) {
            completionHandler([.banner, .list])
        } else {
            completionHandler(.alert)
        }
    }
}