Leanplum's user guides and developer documentation.

Suggest Edits

Leanplum SDK setup

An introduction to Leanplum and our SDK

 

Leanplum allows mobile teams to go from insight to action quickly using the lean cycle of releasing, analyzing, and optimizing content and messaging. See below to learn more about our SDK setup and features.

Setting up the SDK

Follow our setup guides to integrate the Leanplum SDK with your app.

Messaging

With Leanplum's messaging features, you can send customized messages to users and analyze your results from the Leanplum dashboard. You can also send messages manually via our API, depending on your organization's needs.

Once you integrate the Leanplum SDK, in-app messaging should be ready to use. Next, set up Push notification registration to send push notifications directly from the Leanplum dashboard. We also offer email services as an add-on feature, so your team can manage all of your app's messaging channels from one place.

Variables

Variables and resources will appear in the Variables tab automatically once they are detected by the SDK. After your variables are defined, you'll be able to change your variable values from the dashboard, without writing additional code or waiting for App Store approval.

You can preview variable changes on your device instantly before send them out to your users. After you publish your changes, your users will see any updates the next time they open the app. You can also target variable changes to specific user segments to personalize their in-app experience.

After you install the SDK, see Defining variables and Variable types for more.

Analytics

With 19 out-of-the-box metrics, Leanplum's Analytics tab allows you to start gathering intelligence on your app from the moment the SDK is integrated. Our goal is to give you the data and tools you need to create an informed and results-driven content strategy. By seeing which metrics need improvement, you can decide whether to continue with your current strategy or A/B test a new one.

In addition to the metrics calculated automatically by Leanplum, you can also track custom Events and States in your app. Doing so allows you to create custom metrics in the Analytics dashboard. You can also trigger messages and other content changes for your users based on an event or state change.

A/B Testing

Testing different feature releases and messaging strategies ensures that you are rolling out the most effective content for your users. After you set up the Leanplum SDK (along with any custom variables, events, etc.) you'll be able to test different versions of messages or UI changes on a smaller pool of users before releasing changes to your entire userbase.

Once you've collected enough data, Leanplum will notify you of any statistically significant changes in your metrics. Then you can decide which message version or UI change you want to roll out to all of your users.

Suggest Edits

iOS setup

Get started setting up Leanplum with your app

 

Initial setup

The steps below use CocoaPods to integrate the Leanplum SDK.

Supports iOS 7.0 and above.

For more detail, you can also check out our generated iOS docs or review the source code on Github.

Download CocoaPods

CocoaPods is the dependency manager for Objective-C and Swift projects. If you haven't already, install CocoaPods by running the following command in the terminal:

$ sudo gem install cocoapods

For issues installing CocoaPods, see their website for help.

Add a Podfile

In the terminal, navigate to your app's directory. Add a Podfile to your app by running the following command:

$ pod init

Edit your Podfile

Open your Podfile by running the following command:

$ open -a Xcode Podfile

Insert the following into your Podfile:

pod 'Leanplum-iOS-SDK'

# Uncomment for UI Editor.
# pod 'Leanplum-iOS-UIEditor'

# Uncomment one of the following for Location Services.
# pod 'Leanplum-iOS-Location'
# pod 'Leanplum-iOS-LocationAndBeacons'

See Geofencing and location for more on setting up location services.

Install your pods

Now, install the Leanplum SDK pods by running the following command:

$ pod install

If you prefer to use Carthage, you can simply add the following to your Cartfile.

github "Leanplum/Leanplum-iOS-SDK"

# Uncomment for UI Editor.
# github "Leanplum/Leanplum-iOS-UIEditor"

# Uncomment one of the following for Location Services.
# github "Leanplum/Leanplum-iOS-Location"
# github "Leanplum/Leanplum-iOS-LocationAndBeacons"

Add DEBUG flag (Swift only)

In your Build Settings, add -D DEBUG to Debug mode in Other Swift Flags.

Edit your AppDelegate

Remember to import Leanplum before doing anything. You can avoid this by adding the import to your app's prefix header (.pch) file.

For tighter security, remove your development key from your app delegate before submitting to the App Store.

import UIKit
#if DEBUG
    import AdSupport
#endif
import Leanplum

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
  // We've inserted your Test API keys here for you :)
  #if DEBUG
    Leanplum.setDeviceId(ASIdentifierManager.shared().advertisingIdentifier.uuidString)
    Leanplum.setAppId("YOUR_APP_ID",
      withDevelopmentKey:"YOUR_DEVELOPMENT_KEY")
  #else
    Leanplum.setAppId("YOUR_APP_ID",
      withProductionKey: "YOUR_PRODUCTION_KEY")
  #endif

  // Optional: Tracks in-app purchases automatically as the "Purchase" event.
  // To require valid receipts upon purchase or change your reported
  // currency code from USD, update your app settings.
  // Leanplum.trackInAppPurchases()

  // Optional: Tracks all screens in your app as states in Leanplum.
  // Leanplum.trackAllAppScreens()

  // Optional: Activates UI Editor.
  // Requires the Leanplum-iOS-UIEditor framework.
  // LeanplumUIEditor.shared().allowInterfaceEditing()

  // Starts a new session and updates the app content from Leanplum.
  Leanplum.start()

  return true
}
...
#import "AppDelegate.h"
#import <Leanplum/Leanplum.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // Insert your API keys here.
  #ifdef DEBUG
    LEANPLUM_USE_ADVERTISING_ID;
    [Leanplum setAppId:@"YOUR_APP_ID"
     withDevelopmentKey:@"YOUR_DEVELOPMENT_KEY"];
  #else
    [Leanplum setAppId:@"YOUR_APP_ID"
     withProductionKey:@"YOUR_PRODUCTION_KEY"];
  #endif

  // Optional: Tracks in-app purchases automatically as the "Purchase" event.
  // To require valid receipts upon purchase or change your reported
  // currency code from USD, update your app settings.
  // [Leanplum trackInAppPurchases];

  // Optional: Tracks all screens in your app as states in Leanplum.
  // [Leanplum trackAllAppScreens];

  // Optional: Activates UI Editor.
  // Requires the Leanplum-iOS-UIEditor framework.
  // [[LeanplumUIEditor sharedEditor] allowInterfaceEditing];

  // Sets the app version, which otherwise defaults to
  // the build number (CFBundleVersion).
  [Leanplum setAppVersion:@"2.4.1"];

  // Starts a new session and updates the app content from Leanplum.
  [Leanplum start];
  return YES;
}
...

@end

Verify your setup (iOS)

When testing your build, run your app in Debug/development mode using the Development key. Use the Production key when the app is pushed live (to be used by real users/in production).

The Development key is used to:

  • Send data to the development/test pipeline (via an open web socket in real-time)
  • Log processes in the debugger for validation
  • See and register your developer devices in the dashboard
  • Force your test device into specific A/B test variants
  • Keep your data segregated from the live users (instead it will show up in the Developer Activity section)
  • Update custom templates and variables to the content management system

Never use a development key in a production/live build.

A development key uses an open socket for real-time analytics — this pipeline cannot support real users (in a production build). Additionally, any user data will be lost as it is not captured in analytics.

Run your project and register your device

Registering a test device will allow you to test your messages, variable changes, and other Leanplum projects on a real device.

To register your device, first make sure you're in Debug mode. To ensure Debug mode is enabled, make sure the DEBUG preprocessor macro is set in Build Settings.

Next, go to Devices in the Leanplum dashboard, then hover over your device and click Register.

Test in-app messaging

Send yourself an in-app message to see it in action. While running your device in Debug mode, go to the Leanplum Message Composer. Create a new message and click Send Preview. The message will be sent to all registered test devices.

Create a custom variable (optional)

Variables you define will show up in the Leanplum dashboard, where you can change them, segment them, and A/B test them without having to update your app. You can verify the variable has been set by checking the Variables tab in the Leanplum dashboard.

Add the following lines to your app delegate or another class of your choosing:

#import <Leanplum/Leanplum.h>

DEFINE_VAR_STRING(welcomeMessage, @"Welcome to Leanplum!");

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ ...
  [Leanplum onVariablesChanged:^{
    NSLog(@"%@", welcomeMessage.stringValue);
  }];
  return YES;
}
...
@end
import UIKit
import Foundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var welcomeMessage = LPVar.define("welcomeMessage",
    withString: "Welcome to Leanplum!")

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        ...
        Leanplum.onVariablesChanged({
            NSLog((self.welcomeMessage?.stringValue())!)
        })
        ...
        return true
    }
...
}

See Defining variables for more on setting up variables.

It's important to use callbacks if the value is needed around the time the app starts. This guarantees the latest value. See more on how to handle asynchronous code with Callbacks.

Track an event (optional)

Events allow you to measure statistics about what your users do inside your app. You can verify an event is tracked in the Debugger or Events tabs in the Dashboard.

Add the following lines of code to track an event. You can place it anywhere after calling start; this is just an example:

#import <Leanplum/Leanplum.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ ...
  [Leanplum onVariablesChanged:^{
    NSLog(@"%@", welcomeMessage.stringValue);
    [Leanplum track:@"Launch"];
  }];
  return YES;
}
...
@end
import UIKit
import Foundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var welcomeMessage = LPVar.define("welcomeMessage", withString: "Welcome to Leanplum!")

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        ...
        Leanplum.onVariablesChanged({
            NSLog((self.welcomeMessage?.stringValue())!)
            Leanplum.track("Launch")
        })
        ...
        return true
    }
		...
}

See Events for more on tracking custom events with Leanplum.

iOS extensions

Leanplum can be used from iOS extensions. Before calling [Leanplum start] when your ViewController loads, you need to call [Leanplum setExtensionContext:self.extensionContext].

Suggest Edits

Android setup

 

The following setup guide is for developers using Gradle to manage dependencies.

Supports Android 4.0.1 (API Level 14) and above.

For more detail, feel free to check out our generated Javadoc or view the source code on Github.

Update your gradle files

In your project-level build.gradle build file:

  1. add the Leanplum repo to your allproject repositories.
  2. add google-services to your dependencies for Firebase Cloud Messaging.

Here's a simple example:

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:2.2.3'

    // For Firebase Cloud Messaging.
    classpath 'com.google.gms:google-services:3.2.0'
  }
}
allprojects {
  repositories {
    jcenter()
    maven {
      url "https://repo.leanplum.com/"
    }
    maven {
      url "https://maven.google.com"
  }
}

In your module-level build.gradle build file:

  1. Add the required Leanplum libraries in your dependencies, based on which Leanplum services you intend to use (see below).

In SDK 4.0+, our features are split into modular libraries.

Library
Description

leanplum-fcm OR leanplum-gcm

Enables push notifications through Leanplum. You must choose one, depending on which service you use (FCM/GCM).

leanplum-location

Enables location-based messaging. See more here.

leanplum-uieditor

Enables UI changes through the Leanplum dashboard. See more here.

leanplum-core

Enables core Leanplum functionality: in-app messages, a/b tests, states/events tracking, etc.

You can use any combination of these libraries except:

  • You cannot use FCM and GCM libraries together — only one Leanplum push service per app.
  • You do not need to add core with other libraries (if using Gradle). All of our feature-specific libraries automatically include core, so you should only add core if you don’t include any other Leanplum libraries.

Given that, here is a fully-loaded gradle file.

 dependencies {
  
  // Firebase messaging.
  // Only include if you plan to use Firebase for Leanplum push messaging.
  // Minimum supported version of Firebase is 10.0.1.
  implementation 'com.leanplum:leanplum-fcm:+'
  implementation 'com.google.firebase:firebase-messaging:11.8+'

  // Location services.
  // Only include if you need location-based messaging.
  // Minimum supported version of play location is:
  // 8.3.0 for GCM, 10.0.1 for FCM.
  implementation 'com.leanplum:leanplum-location:+'
  implementation 'com.google.android.gms:play-services-location:11.8+'
  
  // UI Editor
  // Only include if you need the UI Editor.
  implementation 'com.leanplum:leanplum-uieditor:+'
  
}
// Include for FCM.
apply plugin: 'com.google.gms.google-services'

Or if you want to use GCM instead of Firebase, replace the first two dependencies:

dependencies {

  // GCM messaging.
  // Minimum supported version of GCM is 8.3.0.
  implementation 'com.leanplum:leanplum-gcm:+' // Use this instead of our Firebase library.
  implementation 'com.google.android.gms:play-services-gcm:11.8+' // Use Google's GCM library.

  ... // The rest remains the same as above.

}
// No plugin required.

Or, if you just want core functionality (aka "none of the above"):

dependencies {

  // NONE OF THE ABOVE
  // Automatically included with any/all of the above Leanplum libraries.
  // Only include if you do not use any other Leanplum libraries.
  implementation 'com.leanplum:leanplum-core:+'

}

You can see more detailed examples in our guide to updating to Android SDK 4.0.

With previous versions of our SDK (< 4.0), you only needed to include com.leanplum:Leanplum (and optionally com.leanplum:UIEditor). The Leanplum library included GCM, FCM, and geolocation libraries.

Edit your manifest

On Android SDK 2.1.0+, we support manifest merging with gradle only which will add all needed services into your manifest automatically, including GCM or FCM services.

Want to install our Android SDK manually?

Download our SDK here. Be sure to drag the .jar file for each required library into your project's libs/ folder. Also be sure to include leanplum-core (and leanplum-push if using either push library). See the .jar manifest files below for more info.

Here are example AndroidManifest.xml files, including two full manifest files for .jar setups (non-gradle).

<?xml version="1.0" encoding="utf-8"?>
<manifest package="[com.YOUR_PACKAGE]"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >

  <uses-sdk
      android:minSdkVersion="14"
      tools:overrideLibrary="com.leanplum, com.google.android.gms"/>

  <!-- These permissions are required only for push notifications. -->

  <!-- GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4). -->
  <uses-permission android:name="android.permission.GET_ACCOUNTS"/>

  <!-- Optional. Prevents the device from sleeping when a message is received. -->
  <uses-permission android:name="android.permission.WAKE_LOCK"/>

  <!-- These permissions are required only for geofencing. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

  <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:name=".[YOUR_APPLICATION_CLASS]" >
      <meta-data
          android:name="com.google.android.gms.version"
          android:value="@integer/google_play_services_version" />
    ...
  </application>

</manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="[com.YOUR_PACKAGE]"
    android:versionCode="1"
    android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="14" />
<!-- Base permissions for Leanplum Android SDK. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

<!-- Optional. Prevents the device from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission android:name="[com.YOUR_PACKAGE].permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="[com.YOUR_PACKAGE].permission.C2D_MESSAGE" />

<!-- These permissions are required only for geofencing. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

<application
  android:allowBackup="true"
  android:icon="@drawable/ic_launcher"
  android:label="@string/app_name"
  android:theme="@style/AppTheme"
  android:name=".[YOUR_APPLICATION_CLASS]" >

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <receiver
        android:name="com.leanplum.LeanplumPushReceiver"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.leanplum.LeanplumPushFirebaseMessagingService" />
        </intent-filter>
    </receiver>


    <service android:name="com.leanplum.LeanplumLocalPushListenerService" />

    <service android:name="com.leanplum.LeanplumPushRegistrationService" />

    <service
        android:name="com.leanplum.LeanplumPushFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    <service
        android:name="com.leanplum.LeanplumPushFcmListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

  <!-- For geofencing only -->
  <service android:name="com.leanplum.ReceiveTransitionsIntentService" />

  <activity
      android:name="[com.YOUR_PACKAGE].MainActivity"
      android:label="@string/app_name" >
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  </activity>
</application>

</manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="[com.YOUR_PACKAGE]"
    android:versionCode="1"
    android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="14" />
<!-- Base permissions for Leanplum Android SDK. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

<!-- GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4). -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

<!-- Optional. Prevents the device from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission android:name="[com.YOUR_PACKAGE].permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="[com.YOUR_PACKAGE].permission.C2D_MESSAGE" />

<!-- These permissions are required only for geofencing. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

<application
  android:allowBackup="true"
  android:icon="@drawable/ic_launcher"
  android:label="@string/app_name"
  android:theme="@style/AppTheme"
  android:name=".[YOUR_APPLICATION_CLASS]" >

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="[com.YOUR_PACKAGE]" />
        </intent-filter>
    </receiver>

    <receiver
        android:name="com.leanplum.LeanplumPushReceiver"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.leanplum.LeanplumPushListenerService" />
        </intent-filter>
    </receiver>


    <service android:name="com.leanplum.LeanplumLocalPushListenerService" />

    <service android:name="com.leanplum.LeanplumPushRegistrationService" />

    <service
        android:name="com.leanplum.LeanplumPushListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>

    <service
        android:name="com.leanplum.LeanplumPushInstanceIDService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID" />
        </intent-filter>
    </service>

  <!-- For geofencing only -->
  <service android:name="com.leanplum.ReceiveTransitionsIntentService" />

  <activity
      android:name="[com.YOUR_PACKAGE].MainActivity"
      android:label="@string/app_name" >
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
  </activity>
</application>

</manifest>

Edit your application class

Add the following to your application class. If your application class does not extend LeanplumApplication, you must call enableLifecycleCallbacks (like the example below). Failure to do so will prevent the SDK from properly tracking states and displaying in-app messages on app resume.

If you want to use one or more push services alongside Leanplum's push service, you'll need to create a custom class that extends the correct Leanplum push messaging class. See our guide here.

For tighter security, remove your development key from your application class before submitting to the Play Store.

package [com.YOUR_PACKAGE];

import com.leanplum.Leanplum;

// For tracking user sessions.
import com.leanplum.LeanplumActivityHelper;
// For push notifications.
import com.leanplum.LeanplumPushService;

import com.leanplum.annotations.Parser;
import com.leanplum.annotations.Variable;
import com.leanplum.callbacks.StartCallback;
import com.leanplum.callbacks.VariablesChangedCallback;

public class ApplicationClass extends Application {

  @Override
  public void onCreate() {
    super.onCreate();

    Leanplum.setApplicationContext(this);
    Parser.parseVariables(this);
    //  For session lifecyle tracking.
    LeanplumActivityHelper.enableLifecycleCallbacks(this);

    // Insert your API keys here.
    if (BuildConfig.DEBUG) {
      Leanplum.setAppIdForDevelopmentMode("Your App ID", "Your Development Key");
    } else {
      Leanplum.setAppIdForProductionMode("Your App ID", "Your Production Key");
    }

    // Optional: Tracks all screens in your app as states in Leanplum.
    // Leanplum.trackAllAppScreens();

    // This will only run once per session, even if the activity is restarted.
    Leanplum.start(this);
    ...
  }
  ...
}

If you are still using Google Cloud Messaging, you'll need to call setGcmSenderId in the onCreate method of your Application class. See more below.

// Optional: For Google Cloud Messaging ONLY
LeanplumPushService.setGcmSenderId(SENDER_ID);

Set up push notifications

Below are setup instructions for using either FCM or GCM. To use one of these push services with Leanplum, see our guide to using multiple push services.

If you target Android 8.0 (API level 26) or above, you must register at least one notification channel in order to send notifications to users with devices running Android 8.0 (level 26) or later. See our guide to Using Android Notification Channels.

To use Firebase Cloud Messaging (FCM) with Leanplum, you need to:

  1. Verify that your Gradle files include the correct FCM and Leanplum libraries (see above).
  2. Download your google-services.json config file (see how here).
  3. Add the above file to your root app/ folder.
Adding config file to app folder

Adding config file to app folder

  1. Copy your FCM Server Key. In the Firebase console, click the gear icon next to Overview, then click Project Settings.
Open settings in Firebase console

Open settings in Firebase console

Then, in your project's settings, go to the Cloud Messaging tab. In this section of your settings, you will see your Server key. Copy the key.

Server key in FCM Console

Server key in FCM Console

  1. Add your FCM Server Key to Leanplum. In the Leanplum dashboard, in your App Settings click Keys & Settings. Go to the Push Notifications tab and enter/paste your key into the Google API key field.
Add key to Leanplum dashboard

Add key to Leanplum dashboard

To use Google Cloud Messaging (instead of Firebase), you need to:

  1. Register your GCM Push service in your Application class. You can do this one of three ways:
// OPTION 1: Register with Leanplum's Sender ID.
// LeanplumPushService.setGcmSenderId(LeanplumPushService.LEANPLUM_SENDER_ID);

// OPTION 2: Register your own Sender ID.
// LeanplumPushService.setGcmSenderId(YOUR_SENDER_ID);

// OPTION 3: Register with a Registration Id.
// LeanplumPushService.setGcmRegistrationId(YOUR_REGISTRATION_ID);

Leanplum.start();
  1. Add your Legacy Server Key to Leanplum. If you use your own ID, you need to give Leanplum permission to send notifications on your behalf. Paste your Legacy Server Key (this is different from your sender ID!) into the Google API Key field in the Push Notification tab of your App's Keys & Settings. You do not need to do this if you register with the LEANPLUM_SENDER_ID.

Google is deprecating GCM. To see how to switch to FCM, see our guide on Migrating to Firebase, or Google's setup instructions for more information.

Add Proguard configuration

This is only needed in your proguard-project.txt if you use Proguard to obfuscate your code, and if you install via JAR. Our AAR library already includes this configuration.

-keepclassmembers class *
{
  @com.leanplum.annotations.* <fields>;
}
-keep class com.leanplum.** { *; }
-dontwarn com.leanplum.**

Verify your setup (Android)

For testing purposes, run your app in Debug/development mode using the Development key. The Production key should be used when the app is pushed live and used by real users in production.

The Development key is used to:

  • Send data to the development/test pipeline (via an open web socket in real-time)
  • Log processes in the debugger for validation
  • See and register your developer devices in the dashboard
  • Force your test device into specific A/B test variants
  • Keep your data segregated from the live users (instead it will show up in the Developer Activity section)
  • Update custom templates and variables to the content management system

Never use a development key in a production/live build.

Using a development key utilizes an open socket for real-time analytics, but this pipeline cannot support real users (in a production build). Additionally, any user data will be lost as it is not captured in analytics.

Run your project and register your device

Registering a test device will allow you to test your messages, variable changes, and other Leanplum projects on a real device.

To register your device, first make sure you're in Debug mode. Then, from the Leanplum dashboard, go to Devices then hover over your device and click Register.

Next, go to Devices in the Leanplum dashboard, then hover over your device and click Register.

Test in-app messaging

Send yourself an in-app message to see it in action. While running your device in Debug mode, go to the Leanplum Message Composer. Create a new message and click Send Preview. The message will be sent to all registered test devices.

Create a custom variable (optional)

Variables you define will show up in the Leanplum dashboard, where you can change them, segment them, and A/B test them without having to update your app. You can verify the variable has been set by checking the Variables tab in the Leanplum dashboard.

Add the following lines to your application class or another class of your choosing:

import com.leanplum.annotations.Variable;
import com.leanplum.annotations.Parser;

public class ApplicationClass extends Application {

  // All variables must be defined before calling Leanplum.start.
  // Use the Parser class (see docs) since your variables are outside of your main activity.
  @Variable public static String welcomeMessage = "Welcome to Leanplum!";

  @Override
  public void onCreate() {
    ...
    // Be sure to set the context to this in the Parser.
    Parser.parseVariables(this);

    // It's important to use the variables changed callback if the value is needed
    // around the time the app starts, so that we're guaranteed to have the latest value.
    Leanplum.addVariablesChangedHandler(new VariablesChangedCallback() {
      @Override
      public void variablesChanged() {
        Log.i("Test", welcomeMessage);
      }
    });
    ...

    Leanplum.start();
  }
}

See Defining variables for more on setting up variables.

Track an event (Optional)

Events allow you to measure statistics about what your users do inside your app. You can also use events to target users for certain messages, tests, or other content changes. You can verify when an event is tracked in the Debugger or the Events tab in the Leanplum dashboard.

Add the following lines of code to track an event. You can place the Leanplum track call anywhere after calling start. For example:

import com.leanplum.annotations.Variable;
import com.leanplum.annotations.Parser;

public class ApplicationClass extends Application {

  @Variable public static String welcomeMessage = "Welcome to Leanplum!";

  @Override
  public void onCreate() {
    ...
    Parser.parseVariables(this);

    Leanplum.addVariablesChangedHandler(new VariablesChangedCallback() {
      @Override
      public void variablesChanged() {
        Log.i("Test", welcomeMessage);
        Leanplum.track("Launch");
      }
    });
    ...

    Leanplum.start();
  }
}

See Events for more on tracking events in Leanplum.

Suggest Edits

Unity setup

 

Our Unity SDK includes both a native Unity implementation of the Leanplum SDK as well as wrappers around the native iOS and Android SDKs. This setup allows us to provide feature parity on the iOS and Android platforms while still retaining support for other Unity platforms. The following matrix shows the features supported on each platform:

Feature
iOS
Android
Standalone

Data modeling

Analytics

Unity asset bundles

-

-

In-app messaging

-

Push notifications

-

Supports Unity 5.0 and above for Android, iOS, and Standalone platforms.

Import the UnityPackage into your project

Make sure you import the directories Plugins and Standard Assets. Optionally import Editor, and/or LeanplumSample to include a sample project demonstrating how to manipulate the speed of rain with a Leanplum variable.

Add the Leanplum Prefab

Copy the Leanplum Prefab from Standard Assets/Leanplum into the first scene in your project that loads. Make sure the prefab is linked with the script LeanplumWrapper.cs. This GameObject will persist across scene changes so you don't have to worry about adding it to other scenes.

Add your app keys

Copy your app ID and keys into the Leanplum GameObject's inspector. You can find these in App Settings > Keys & Settings.

Initialize the SDK

The code in LeanplumWrapper.cs initializes the SDK. If you require asset bundle support on iOS and Android, you can switch to use the native Unity implementation for all platforms. However, this means that you won't get in-app messaging or push notification support.

The code snippets below exist only in the LeanplumSDK namespace. Remember to add the following to every source file that calls Leanplum's functions.

using LeanplumSDK;

See below for more on defining variables and tracking events.

Verify the setup

For testing purposes, run your app in Debug/development mode using the Development key. The Production key should be used when the app is pushed live and used by real users in production.

The Development key is used to:

  • Send data to the development/test pipeline (via an open web socket in real-time)
  • Log processes in the debugger for validation
  • See and register your developer devices in the dashboard
  • Force your test device into specific A/B test variants
  • Keep your data segregated from the live users (instead it will show up in the Developer Activity section)
  • Update custom templates and variables to the content management system

Never use a development key in a production/live build.

A development key uses an open socket for real-time analytics, but this pipeline cannot support real users (in a production build). Additionally, any user data will be lost as it is not captured in analytics.

Run your project and register your device

Make sure the Development Build checkbox is checked in Unity's Build Settings menu. From the Leanplum dashboard, go to Devices then hover over your device and click Register.

Create a custom variable (optional — Unity)

The variables you define with Leanplum will show up in the Leanplum dashboard, where you can change them, segment them, and A/B test them without having to update your app. You can verify the variable has been set by viewing the Variables tab in Leanplum.

Add the highlighted lines to your app delegate or another class of your choosing:

using LeanplumSDK;

public class LeanplumWrapper : MonoBehaviour
{   ...
    private Var<string> welcomeMessage;

    void Start()
    {   ...
        // Avoid assigning the variable where its declared up top becuase
        // that code may run multiple times and will produce an error.
        welcomeMessage = Var<string>.Define("welcomeMessage", "Welcome to Leanplum!");
        Leanplum.Start();
    }

    void OnEnable()
    {
        // It's important to use the variables changed callback or welcomeMessage.ValueChanged if the
        // value is needed around the time the app starts, so that we're guaranteed to have the latest value.
        Leanplum.VariablesChanged += OnLeanplumOnVariablesChanged;
    }

    void OnDisable()
    {
        Leanplum.VariablesChanged -= OnLeanplumOnVariablesChanged;
    }

    private void OnLeanplumOnVariablesChanged()
    {
        Debug.Log(welcomeMessage.Value);
    }
}

See Defining variables for more on using variables with Leanplum.

Track an event (optional)

Events allow you to measure statistics about what your users do inside your app. You can also trigger messages and other content changes after certain events. You can verify an event is tracked in the Debugger or Events tabs in the Dashboard.

Add the highlighted line of code to track an event. You can place it anywhere after calling start. Example:

using LeanplumSDK;

public class LeanplumWrapper : MonoBehaviour
{   ...
    void Start()
    {   ...
      Leanplum.Track("Launch");
    }
}

See Events for more on tracking events with Leanplum.

Suggest Edits

JavaScript setup

 

Install the SDK

Download Leanplum JavaScript SDK

Add leanplum.js to your project

<script type="text/javascript" src="leanplum.js"></script>

Add sw.min.js to your project

To use web push in your app, you must add the Service Worker file sw.min.js from our SDK to your root directory, then register the Service Worker and user for push notifications.

For more see Push notifications.

Initialize Leanplum

// This value should be set to true only if you're developing on your server.
var isDevelopmentMode = true;

// Sample variables. This can be any JSON object.
var variables = {
 items: {
   color: 'red',
   size: 20,
   showBadges: true
 },
 showAds: true
};

// We've inserted your Test API keys here for you :)
if (isDevelopmentMode) {
 Leanplum.setAppIdForDevelopmentMode("YOUR_APP_ID", "YOUR_DEVELOPMENT_KEY");
} else {
 Leanplum.setAppIdForProductionMode("YOUR_APP_ID", "YOUR_PRODUCTION_KEY");
}

Leanplum.setVariables(variables);
Leanplum.start(function(success) {
 console.log('Success: ' + success);
 console.log('Variables', Leanplum.getVariables());
});

Verify the setup

For testing purposes, run your app in Debug/development mode using the Development key. The Production key should be used when the app is pushed live and used by real users in production.

The Development key is used to:

  • Send data to the development/test pipeline (via an open web socket in real-time)
  • Log processes in the debugger for validation
  • See and register your developer devices in the dashboard
  • Force your test device into specific A/B test variants
  • Keep your data segregated from the live users (instead it will show up in the Developer Activity section)
  • Update custom templates and variables to the content management system

Never use a development key in a production/live build.

Using a development key utilizes an open socket for real-time analytics, but this pipeline cannot support real users (in a production build). Additionally, any user data will be lost as it is not captured in analytics.

Register your device

Be sure to run your app in development mode. From the Leanplum dashboard, go to Devices then hover over your device and click Register.

How to track events in your app

Leanplum.track("View Cart");
Leanplum.track("View Cart", {itemsInCart: 4});
Leanplum.track("Purchase", 4.99, {itemCategory: 'Apparel', itemName: 'Shoes'});

How to track states transitions. These are sections of your app the user is in.

Leanplum.advanceTo("Cart");
Leanplum.advanceTo("Level", level.name);

// The 'null' state. Causes the user to leave the current state and not enter another one.
Leanplum.advanceTo(null);

Passing custom user IDs.

Leanplum.start('mike3958');

Passing user attributes. User attributes are applied to the user, so they're saved across sessions. If an attribute no longer applies, you can set it to null.

Leanplum.start({hasFacebookProfile: true});
Leanplum.start('userId', {age: 20, gender: 'Male'}, callback);

Starts Leanplum by simply loading the cached variables, and doesn't log a new session. Useful for subsequent page loads inside the app.

Leanplum.startFromCache('mike3958');

How to track the session lifecycle.

Leanplum.pauseSession();  // Pauses the current session.
Leanplum.resumeSession();  // Resumes the current session.
Leanplum.stop();  // Ends the current session. Sessions will automatically timeout after 2 hours if stop isn't called explicitly (30 minutes if paused).

Javascript SDK settings

Set the path of the API server.

Leanplum.setApiPath('https://www.leanplum.com/api');

Set the email address of the developer. This prevents the email prompt from being displayed. Set a blank email to prevent Leanplum from being registered.

Leanplum.setEmail('myself@gmail.com');

Sets whether Leanplum checks for and alerts about updates at startup in development mode (Default: true).

Leanplum.setUpdateCheckingEnabledInDevelopmentMode(false);

Sets the network timeout in seconds. (Default: 10).

Leanplum.setNetworkTimeout(5);

Sets the request batching strategy. This applies to production mode only. The default behavior is to batch every 5 seconds.

Leanplum.setRequestBatching(false); // No batching.
Leanplum.setRequestBatching(true); // Batching enabled. Unsent requests are sent on start, pauseSession, resumeSession, and stop
Leanplum.setRequestBatching(true, 30); // Same as above except unsent requests are also sent every 30 seconds.

Sets a function for prompting the user for information. This is called to ask for an email address in development mode.

Leanplum.setPromptFunction(function(message, defaultValue, callback) {
  callback(prompt(message, defaultValue));
});

Enables development mode, and sets the app ID and client key.

Leanplum.setAppIdForDevelopmentMode('appId', 'clientKey');

Enables production mode, and sets the app ID and client key.

Leanplum.setAppIdForProductionMode('appId', 'clientKey');

Sets a custom device ID. If this is not called, Leanplum will assign a device ID automatically.

Leanplum.setDeviceId('DevId');

Sets the current version of your app.

Leanplum.setAppVersion('1.0.1');

Sets the device name to override the default.

Leanplum.setDeviceName("Andrew's iMac");

Sets the device model to override the default.

Leanplum.setDeviceModel('Mac');

Sets the system name to override the default.

Leanplum.setSystemName('Mac OS X');

Sets the system version to override the default.

Leanplum.setSystemVersion('10.8');
Suggest Edits

Manual SDK setup

 

We generally recommend installing the SDK using our dependency managers, but if you'd rather set up your SDK manually, see below for iOS and Android instructions.

Suggest Edits

Manual setup iOS

Setting up the SDK manually

 

You can install our SDK manually using the steps below for iOS.

Install the SDK

First, Download Leanplum iOS SDK.

Supports iOS 7.0 and above.

Add Leanplum.framework to your project

Drop the .framework package into the "Embedded Binaries" list in your targets > general tab. This will add the .framework to "Linked Frameworks and Libraries" as well.

If you are using the static version of our framework, you only need to add it to "Linked Frameworks and Libraries".

If you want to use Location services on Leanplum, add LeanplumLocation.framework. Alternatively, if you also need iBeacon services on Leanplum, add LeanplumLocationAndBeacons.framework.

Add Leanplum frameworks to your project

Add CFNetwork, SystemConfiguration, Security, AdSupport, and StoreKit frameworks. AdSupport and StoreKit can be marked as Optional. IDFA is only used (optionally) in development mode and not in the build sent to the App Store. If you're linking LeanplumLocation or LeanplumLocationAndBeacons, add CoreLocation.

Add the -ObjC -fobjc-arc linker flags (optional)

This is only needed if your project has CLANG_ENABLE_OBJC_ARC or Objective-C Automatic Reference Counting set to NO (aka ARC disabled). By default ARC is enabled, so this flag is only needed if you have disabled ARC.

The -ObjC flag may not be compatible with certain libraries. You can replace it with -force_load ${SRCROOT}/Leanplum.framework/Leanplum. Make sure the path matches the location of Leanplum.framework on your filesystem.

Strip framework script (for release builds)

In order to submit a release build of the app to the App Store, you must make sure that the following script is in place to strip the framework to valid architectures. Navigate to 'Build Phases' in your project, add 'New Run Script', and move the 'New Run Script' after the Embed Frameworks. Then add the following code:

cd "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Leanplum.framework/"
lipo -remove i386 -remove x86_64 Leanplum -output Leanplum

Make sure to check 'Run script only when installing'. Once completed, the setup should look like the following:

Add DEBUG flag (optional)

Add -D DEBUG to Other Swift Flags only for Debug mode.

Edit your AppDelegate

Remember to import Leanplum before doing anything. You can avoid this by adding the import to your app's prefix header (.pch) file.

For tighter security, remove your development key from your app delegate before submitting to the App Store.

import UIKit
#if DEBUG
    import AdSupport
#endif
import Leanplum

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
  // We've inserted your Test API keys here for you :)
  #if DEBUG
    Leanplum.setDeviceId(ASIdentifierManager.shared().advertisingIdentifier.uuidString)
    Leanplum.setAppId("YOUR_APP_ID",
      withDevelopmentKey:"YOUR_DEVELOPMENT_KEY")
  #else
    Leanplum.setAppId("YOUR_APP_ID",
      withProductionKey: "YOUR_PRODUCTION_KEY")
  #endif

  // Optional: Tracks in-app purchases automatically as the "Purchase" event.
  // To require valid receipts upon purchase or change your reported
  // currency code from USD, update your app settings.
  // Leanplum.trackInAppPurchases()

  // Optional: Tracks all screens in your app as states in Leanplum.
  // Leanplum.trackAllAppScreens()

  // Optional: Activates UI Editor.
  // Requires the Leanplum-iOS-UIEditor framework.
  // LeanplumUIEditor.shared().allowInterfaceEditing()

  // Starts a new session and updates the app content from Leanplum.
  Leanplum.start()

  return true
}
...
#import "AppDelegate.h"
#import <Leanplum/Leanplum.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // Insert your API keys here.
  #ifdef DEBUG
    LEANPLUM_USE_ADVERTISING_ID;
    [Leanplum setAppId:@"YOUR_APP_ID"
     withDevelopmentKey:@"YOUR_DEVELOPMENT_KEY"];
  #else
    [Leanplum setAppId:@"YOUR_APP_ID"
     withProductionKey:@"YOUR_PRODUCTION_KEY"];
  #endif

  // Optional: Tracks in-app purchases automatically as the "Purchase" event.
  // To require valid receipts upon purchase or change your reported
  // currency code from USD, update your app settings.
  // [Leanplum trackInAppPurchases];

  // Optional: Tracks all screens in your app as states in Leanplum.
  // [Leanplum trackAllAppScreens];

  // Optional: Activates UI Editor.
  // Requires the Leanplum-iOS-UIEditor framework.
  // [[LeanplumUIEditor sharedEditor] allowInterfaceEditing];

  // Sets the app version, which otherwise defaults to
  // the build number (CFBundleVersion).
  [Leanplum setAppVersion:@"2.4.1"];

  // Starts a new session and updates the app content from Leanplum.
  [Leanplum start];
  return YES;
}
...

@end

Verify the setup

Verify the setup

When testing your build, run your app in Debug/development mode using the Development key. Use the Production key when the app is pushed live (to be used by real users/in production).

The Development key is used to:

  • Send data to the development/test pipeline (via an open web socket in real-time)
  • Log processes in the debugger for validation
  • See and register your developer devices in the dashboard
  • Force your test device into specific A/B test variants
  • Keep your data segregated from the live users (instead it will show up in the Developer Activity section)
  • Update custom templates and variables to the content management system

Never use a development key in a production/live build.

Using a development key utilizes an open socket for real-time analytics, but this pipeline cannot support real users (in a production build). Additionally, any user data will be lost as it is not captured in analytics.

Run your project and register your device

Make sure you're in Debug mode. To ensure Debug mode is enabled, make sure the DEBUG preprocessor macro is set in Build Settings.

From the Leanplum dashboard, go to Devices then hover over your device and click Register.

Test in-app messaging

Send yourself an in-app message to see it in action. While running your device in Debug mode, go to the Leanplum Message Composer. Create a new message and click Send Preview. The message will be sent to all registered test devices.

Create a custom variable (optional)

The variables you define will show up in the Leanplum dashboard, where you can change them, segment them, and A/B test them without having to update your app. You can verify the variable has been set by viewing the Variables tab in the Leanplum dashboard.

Add the following lines to your app delegate or another class of your choosing:

import UIKit
import Foundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var welcomeMessage = LPVar.define("welcomeMessage",
    withString: "Welcome to Leanplum!")

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        ...
        Leanplum.onVariablesChanged({
            NSLog((self.welcomeMessage?.stringValue())!)
        })
        ...
        return true
    }
...
#import <Leanplum/Leanplum.h>

DEFINE_VAR_STRING(welcomeMessage, @"Welcome to Leanplum!");

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ ...
  [Leanplum onVariablesChanged:^{
    NSLog(@"%@", welcomeMessage.stringValue);
  }];
  return YES;
}
...
@end

It's important to use the variables changed callback onVariablesChanged, or welcomeMessage.onValueChanged (for our example variable welcomeMessage), if the value is needed around the time the app starts. This guarantees the latest value. See more on how to handle asynchronous code with Callbacks.

For more on Variables, see Defining variables.

Track an event (optional)

Events allow you to measure statistics about what your users do in your app. You can also use events to trigger messages and other content changes. You can verify an event is tracked in the Debugger or Events tabs in the Leanplum dashboard.

Add the following lines of code to track an event. You can place it anywhere after calling start. Example:

import UIKit
import Foundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var welcomeMessage = LPVar.define("welcomeMessage", withString: "Welcome to Leanplum!")

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        ...
        Leanplum.onVariablesChanged({
            NSLog((self.welcomeMessage?.stringValue())!)
            Leanplum.track("Launch")
        })
        ...
        return true
    }
...
#import <Leanplum/Leanplum.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ ...
  [Leanplum onVariablesChanged:^{
    NSLog(@"%@", welcomeMessage.stringValue);
    [Leanplum track:@"Launch"];
  }];
  return YES;
}
...
@end

For more on tracking events with Leanplum, see Events.

Suggest Edits

Variables

Defining variables with the Leanplum SDK

 

You can create variables that can take on new values from the server. Using variables in the Leanplum dashboard allows you to roll out changes without having to push an update through the App Store or Google Play. You can also create A/B tests to change variables for only a percentage of your users.

Variable data comes back asynchronously after you call start. If you need to use a variable when the app starts, make sure you use Callbacks.

When you define a variable in your code, it will appear in the Variables tab in Leanplum the next time your app starts in development mode.

iOS

It's important to define all of your variables before calling Leanplum.Start. Use periods to group variables on the dashboard.

Objective-C

Define variables outside of your methods, like you would a constant, using our DEFINE_VAR macros. Use underscores in the name to group values into a structured variable. See Modeling structured data for examples.

Swift

Swift doesn't support macros like Objective-C. Instead, define variables using LPVar.define directly. Use dots in the name to group values into a structured variable. See Modeling structured data for examples.

With Swift, you must define all of your Leanplum variables before calling Leanplum.start.

To access a variable in another controller or file, call define again; the first define call (before start) will set the value, subsequent calls will return the cached value. Be careful where you place define calls to ensure the first call is truly called first.

See Variable types for more specifics on each type of variable.

Android (Java)

There are two ways to define variables.

  1. Using the @Variable annotation on public static class members
    This is the easiest and most convenient way to define variables.
public class MainActivity extends LeanplumActivity {
    @Variable public static String welcomeLabel = "Welcome!";
    ...
}

You can use this method to define variables:

  • Inside your Application class if it extends LeanplumApplication.
  • In your main activity if it extends one of the LeanplumActivityclasses and calls Leanplum.start.
  • In another class. Use the Parser class to detect the annotations before calling Leanplum.start.

If you choose to define variables in an Activity or Class that does make your start call, you will need to use Parser.parseVariablesForClasses to collect these variable definitions before your start call.

For example, if we have variables defined in ClassA and ClassB, we need to add the following to our ApplicationClass before start:

...
import com.leanplum.annotations.Parser;
...
public class ApplicationClass extends LeanplumApplication {

  @Override
  public void onCreate() {
    super.onCreate();
    Leanplum.setApplicationContext(this);
    ...
    // Parse variables from other classes.
    Parser.parseVariablesForClasses(ClassA.class, ClassB.class);
    // Then, call start.
    Leanplum.start();
  }

}

If you define your variables in an ApplicationClass or Activity where you call start, and the class does not extend LeanplumApplication or LeanplumActivity, then you must use the Parser class to detect that class's variable annotations.

...
import com.leanplum.annotations.Parser;
...
public class ApplicationClass extends Application {

  @Variable
  public static String welcome = "Hi there!";

  @Override
  public void onCreate() {
    super.onCreate();
    Leanplum.setApplicationContext(this);
    ...
    // Parse variables from this class.
    Parser.parseVariables(this);
    // Then, call start.
    Leanplum.start();
  }

}
  1. Using Var.define
public class MainActivity extends LeanplumActivity {
    public static Var<String> welcomeLabel = Var.define("welcomeLabel", "Welcome!");
  ...
}

You must define variables with this method before calling Leanplum.start.

Unity

It's important to define all of your variables before calling Leanplum.Start. Use periods to group variables on the dashboard.

JavaScript (HTML5)

Sets your variables:

Leanplum.setVariables({
  StoreTitle: "Powerup Store",
  Items: [
    {
      name: "Speed Boost",
      price: 100
    }, {
      name: "Health Boost",
      price: 150
    }
  ]
});

Gets your variables:

var variables = Leanplum.getVariables();
//Gets a particular variable.
var title = Leanplum.getVariable('StoreTitle');
var speedBoost = Leanplum.getVariable('Items', 0);
var healthBoostName = Leanplum.getVariable('Items', 1, 'name');

See Variable types for more specifics on each type of variable.

Suggest Edits

Variable types

Examples of how to set and access variable values for different types of variables in Leanplum.

 

Float

//Set the value with the macro LPVar.define. To access the value in your code, use the floatValue method.

var shootSpeed = LPVar.define("shootSpeed", with:1.0); // How fast your ship shoots.
...
Leanplum.onVariablesChanged {
  // Move ship according to its speed.
  myShip.moveWithSpeed(shootSpeed?.floatValue())
}
//Set the value with the macro DEFINE_VAR_FLOAT. To access the value in your code, use the floatValue method.

DEFINE_VAR_FLOAT(shootSpeed, 1.0);  // How fast your ship shoots.
...
[Leanplum onVariablesChanged:^() {
  // Move ship according to its speed.
  [myShip moveWithSpeed:shootSpeed.floatValue];
}];
@Variable public static float shootSpeed = 1;  // How fast your ship shoots.
Var<float> shootSpeed = Var<float>.Define("shootSpeed", 1.0);  // How fast your ship shoots.
...
void MoveShip() {
    MoveWithSpeed(shootSpeed.Value);
}

Boolean

//Set the value with the macro LPVar.define. To access the value in your code, use the boolValue method.

var showAds = LPVar.define("showAds", with: false) // Whether or not to show ads in the app.
...
Leanplum.onVariablesChanged {
  if(showAds?.boolValue())! {
    self.view.addSubview(adView)
  }
}
//Set the value with the macro DEFINE_VAR_BOOL. To access the value in your code, use the boolValue method.

DEFINE_VAR_BOOL(showAds, false);  // Whether or not to show ads in the app.
...
[Leanplum onVariablesChanged:^() {
  if (showAds.boolValue) {
    [self.view addSubview:adView];
  }
}];
// The variable showAds will show up on our dashboard as "Show Ads".
@Variable(name="Show Ads") public static boolean showAds = false;  // Whether or not to show ads in the app.
// Boolean with custom name: the variable showAds will show up on our dashboard as "Show Ads".
Var<bool> showAds = Var<bool>.Define("Show Ads", false);
...
void ShowAds() {
  if (showAds.Value) {
    MakeAdBanner();
  }
}

String

//Set the value with the macro LPVar.define. To access the value in your code, use the stringValue method.

var startLabel = LPVar.define("startLabel", with: "Start") // Label of the "Start" button
...
Leanplum.onVariablesChanged {
  let startButton: UIButton = UIButton()
  startButton.setTitle(startLabel?.stringValue(), for: .normal)
  self.view.addSubview(startButton)
}
//Set the value with the macro DEFINE_VAR_STRING. To access the value in your code, use the stringValue method.

DEFINE_VAR_STRING(startLabel, @"Start");  // Label of the "Start" button.
...
[Leanplum onVariablesChanged:^() {
  UIButton* startButton = [[UIButton alloc] init];
  startButton.text = startLabel.stringValue;
  [self.view addSubview:startButton];
}];
// The variable startLabel will show up on our dashboard within the group "mainScreen".
@Variable(group="mainScreen") public static String startLabel = "Start";  // Label of the "Start" button.

// Use "." to nest groups. You can also use "." with the "name" argument.
@Variable(group="screens.mainScreen") public static String startLabel = "Start";  // Label of the "Start" button.
String
Var<string> startLabel = Var<string>.Define("startLabel", "Start");  // Label for "Start" button.
...
void CreateStartButton() {
  AddButtonWithText(startLabel.Value);
}

Color

//Set the value with the macro LPVar.define. 
//To access the value in your code, use the colorValue method.

var myColor = LPVar.define("myColor", with: UIColor.gray)
...
Leanplum.onVariablesChanged {
  startButton.setTitleColor(myColor?.colorValue(), for: .normal)
}
//Set the value with the macro DEFINE_VAR_COLOR. To access the value in your code, use the colorValue method.

DEFINE_VAR_COLOR(myColor, [UIColor colorWithRed:14.0/255.0 green:114.0/255.0 blue:199.0/255.0 alpha:1]);
...
[Leanplum onVariablesChanged:^() {
  [startButton setTitleColor:myColor.colorValue];
}];

Assets

File variables work like variables except that the file data comes back from Leanplum separately. When you edit a file variable, you change its filename. If a file with the same name does not exist on the device, it will download from Leanplum.

//Set the value with the macro LPVar.define using a withFile parameter. To access the value in your code, use the fileValue or imageValue method.

// Image
var goldStar = LPVar.define("goldStar", withFile: "gold_star.png") // Location of Gold Star image file.
...
Leanplum.onVariablesChanged {
  self.splashView?.image = goldStar?.imageValue()
}
//Set the value with the macro DEFINE_VAR_FILE. To access the value in your code, use the fileValue or imageValue method.

// Image and file.
DEFINE_VAR_FILE(goldStar, @"gold_star.png");  // Location of Gold Star image file.
DEFINE_VAR_FILE(config, @"config.plist");
...
[Leanplum onVariablesChanged:^() {
  // imageValue is compatible with Asset Catalogs.
  self.splashView.image = goldStar.imageValue;
  NSDictionary* config = [NSDictionary dictionaryWithContentsOfFile:config.fileValue];
}];
public static Var<String> mario = Var.defineAsset("Mario", "Mario.png");
...
mario.addFileReadyHandler(new VariableCallback<String>() {
    @Override
    public void handle(Var<String> variable) {
        im.setImageBitmap(BitmapFactory.decodeStream(mario.stream()));
    }
});
// It is necessary to specify platform-specific AssetBundles as they are not cross-platform.
// The filenames specified when defining an AssetBundle represent the default
// bundles that will be loaded if present in Leanplum's file manager.

Var<AssetBundle> background = Var<AssetBundle>.DefineAssetBundle(
    "forestBackground",
    standaloneBundleName: "Standalone-Forest.unity3d",
    androidBundleName: "Android-Forest.unity3d",
    iosBundleName: "iOS-Forest.unity3d");
...
void LoadBackground() {
  if (background.Value != null) {
    Instantiate(background.Value.mainAsset);
  }
}

Dictionary

//Set the value with the macro LPVar.define. 
//To access a dictionary value in your code, use the objectForKey method to get to the correct property, then use an accessor method (stringValue, boolValue, floatValue, etc.) to get the actual value. 
//In Swift, you may need to cast after using objectForKey.

let powerUp = LPVar.define("powerUp", with: [
  "name": "Turbo Boost",
  "price": 150,
  "speedMultiplier": 1.5,
  "timeout": 15])
...
Leanplum.onVariablesChanged {
  self.speed = (powerUp?.object(forKey: "speedMultiplier") as! NSNumber).floatValue
}
//Set the value with the macro DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS. To access a dictionary value in your code, use the objectForKey method to get to the correct property, then use an accessor method (stringValue, boolValue, floatValue, etc.) to get the actual value. 

DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS(
  powerUp,
  @"Turbo Boost", @"name",
  @150, @"price",
  @1.5, @"speedMultiplier",
  @15, @"timeout",
  nil);
...
[Leanplum onVariablesChanged:^() {
  self.speed *= [[powerUp objectForKey:@"speedMultiplier"] floatValue];
}];
@Variable public static Map<String, Object> powerup = new HashMap<String, Object>() {
    {
        put("name", "Turbo Boost");
        put("price", 150);
        put("speedMultiplier", 1.5);
        put("timeout", 15);
        put("slots", Arrays.asList(1, 2, 3));
    }
};
Dictionary<string, object> powerupInit = new Dictionary<string, object>();
powerupInit.Add("price", 150);
powerupInit.Add("speedMultiplier", 1.5);
powerupInit.Add("timeout", 15);
Var<Dictionary<string, object>> powerup = Var<Dictionary<string, object>>.Define("powerup", powerupInit);

Array (List)

//Set the value with the macro LPVar.define.  
//To access a dictionary value in your code, use the objectAtIndex method to get to the correct object, then use an accessor method (stringValue, boolValue, floatValue, etc.) to get the actual value. 
//In Swift, you may need to cast after using objectAtIndex.

let storeItemsOrder = LPVar.define("storeItemsOrder", with: [0, 1, 2, 3, 4])
Leanplum.onVariablesChanged {
  for var i in 0..<storeItemsOrder!.count(){
    let item = storeItemsOrder!.object(at: i) as! NSNumber
    print(item.intValue)
    i += 1
  }
}
//Set the value with the macro DEFINE_VAR_ARRAY_WITH_OBJECTS.  To access a dictionary value in your code, use the objectAtIndex method to get to the correct object, then use an accessor method (stringValue, boolValue, floatValue, etc.) to get the actual value.

DEFINE_VAR_ARRAY_WITH_OBJECTS(storeItemsOrder, @0, @1, @2, @3, @4, nil);
...
[Leanplum onVariablesChanged:^(){
  for (int i = 0; i < storeItemsOrder.count; i++) {
    int item = [[storeItemsOrder objectAtIndex:i] intValue];
    NSLog(@"%i", item);
  }
}];
@Variable public static List<Integer> storeItemsOrder = Arrays.asList(1, 2, 3, 4);
Var<List<Object>> storeItemsOrder = Var<List<Object>>.Define("storeItemsOrder", new List<Object> { 0, 1, 2, 3, 4 });
Suggest Edits

Modeling structured data

 

Say you have a bunch of items in your app, and each item has properties. Leanplum gives you the flexibility to model one property of the object at a time, one object at a time, or the entire structure at once, depending on how you'd like to set up your code.

For example, if you want to create a structure like this:

Powerups: {
    Speed: {
        Price: 10,
        Duration: 5,
        OrderInStore: 0
    },
    Power: {
        Price: 15,
        Duration: 5,
        OrderInStore: 1
    }
}

You could model each individual field like so:

// Names or groups with a '.' are grouped automatically.
var speedPrice = LPVar.define("Powerups.Speed.Price", with:10)
var speedDuration = LPVar.define("Powerups.Speed.Duration", with:5)
var speedOrder = LPVar.define("Powerups.Speed.OrderInStore", with:0)

var powerPrice = LPVar.define("Powerups.Power.Price", with:15)
var powerDuration = LPVar.define("Powerups.Power.Duration", with:5)
var powerOrder = LPVar.define("Powerups.Power.OrderInStore", with:1)
// Names or groups with an '_' are grouped automatically.
DEFINE_VAR_FLOAT(Powerups_Speed_Price, 10);
DEFINE_VAR_FLOAT(Powerups_Speed_Duration, 5);
DEFINE_VAR_FLOAT(Powerups_Speed_OrderInStore, 0);

DEFINE_VAR_FLOAT(Powerups_Power_Price, 15);
DEFINE_VAR_FLOAT(Powerups_Power_Duration, 5);
DEFINE_VAR_FLOAT(Powerups_Power_OrderInStore, 1);
// Names or groups with a '.' are grouped automatically.
@Variable(name="Powerups.Speed.Price") double speedPrice = 10;
@Variable(name="Powerups.Speed.Duration") double speedDuration = 5;
@Variable(name="Powerups.Speed.OrderInStore") int speedOrder = 0;

@Variable(name="Powerups.Power.Price") double powerPrice = 15;
@Variable(name="Powerups.Power.Duration") double powerDuration = 5;
@Variable(name="Powerups.Power.OrderInStore") int powerOrder = 1;
// Names with a '.' are grouped automatically.
Var<int> speedPrice = Var<int>.Define("Powerups.Speed.Price", 10);
Var<int> speedDuration = Var<int>.Define("Powerups.Speed.Duration", 5);
Var<int> speedOrder = Var<int>.Define("Powerups.Speed.Order in Store", 0);

Var<int> powerPrice = Var<int>.Define("Powerups.Power.Price", 15);
Var<int> powerDuration = Var<int>.Define("Powerups.Power.Duration", 5);
Var<int> powerOrder = Var<int>.Define("Powerups.Power.Order in Store", 1);

Or you could model each object:

var powerUpsSpeed = LPVar.define("Powerups.Speed", with: [
  "Price": 10,
  "Duration": 5,
  "OrderInStore": 0
])
var powerUpsPower = LPVar.define("Powerups.Power", with: [
  "Price": 15,
  "Duration": 5,
  "OrderInStore": 1
])
DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS(Powerups_Speed, @10, @"Price", @5, @"Duration", @0, @"OrderInStore", nil);
DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS(Powerups_Power, @15, @"Price", @5, @"Duration", @1, @"OrderInStore", nil);
// Using the Google Guava library for brevity.
@Variable(group="Powerups") Map<String, Object> speed =
    ImmutableMap.of("Price", 10.0, "Duration", 5.0, "OrderInStore", 0);
@Variable(group="Powerups") Map<String, Object> duration =
    ImmutableMap.of("Price", 15.0, "Duration", 5.0, "OrderInStore", 1);
Var<Dictionary<string, object>> speed = Var<Dictionary<string, object>>.Define(
    "Powerups.Speed", new Dictionary<string, object>>() {
        { "Price", 10 },
        { "Duration", 5 },
        { "OrderInStore", 0 } });
Var<Dictionary<string, object>> power = Var<Dictionary<string, object>>.Define(
    "Powerups.Power", new Dictionary<string, object>>() {
        { "Price", 15 },
        { "Duration", 5 },
        { "OrderInStore", 1 } });

Or the entire structure:

var powerups = LPVar.define("Powerups", with: [
  "Speed": [
    "Price": 10,
    "Duration": 5,
    "OrderInStore": 0
  ],
  "Power": [
    "Price": 15,
    "Duration": 5,
    "OrderInStore": 1
  ]
])
LPVar* powerups;
static void __attribute__((constructor)) initObjects() {
    @autoreleasepool {
        powerups = [LPVar define:@"Powerups" withDictionary:@{
            @"Speed": @{@"Price" : @10, @"Duration": @5, @"OrderInStore": 0},
            @"Power": @{@"Price" : @15, @"Duration": @5, @"OrderInStore": 1}
        }];
    }
}
@Variable Map<String, Object> powerups = ImmutableMap.of(
    "Speed", ImmutableMap.of("Price", 10.0, "Duration", 5.0, "OrderInStore", 0),
    "Power", ImmutableMap.of("Price", 15.0, "Duration", 5.0, "OrderInStore", 1));
Var<Dictionary<string, Dictionary<string, object>>> speed = Var<Dictionary<string, Dictionary<string, object>>>.Define(
    "Powerups", new Dictionary<string, Dictionary<string, object>>() {
        { "Speed", new Dictionary<string, object>() {
            { "Price", 10 },
            { "Duration", 5 },
            { "Order in Store", 0 } } },
        { "Power", new Dictionary<string, object>() {
            { "Price", 15 },
            { "Duration", 5 },
            { "Order in Store", 1 } } }
        });

All of the above declarations will show up identically on our dashboard. Leanplum understands to group variables that use underscores (ObjC) or dots (Swift) in their names. The last method is convenient because instead of specifying the JSON data in code, you could potentially load it from a file and then convert it to a dictionary.

When the variable values are ready, you can get different slices of the variables using objectForKey[Path].

Using objectForKey:

NSDictionary* allPowerups = [powerups objectForKeyPath:nil];
NSDictionary* speedPowerup = [powerups objectForKey:@"Speed"];
float speedPrice = [[powerups objectForKeyPath:@"Speed", @"Price", nil] floatValue];
Map<String, Object> allPowerups = powerups.objectForKeyPath();
Map<String, Object> speedPowerup = powerups.objectForKeyPath("Speed");
float speedPrice = powerups.objectForKeyPath("Speed", "Price");
Suggest Edits

Callbacks

 

Because Leanplum variables and resources are retrieved from the server asynchronously after start, you need to wait for the values to be downloaded before using them in your code. The proper way to do this is to use one of the callbacks provided by our SDK.

The SDK will use locally-cached values, if available, and changes will only be synced on start or forceContentUpdate.

You can use callbacks multiple times across different classes in your app. However, where you place the callback may influence when it is executed. If you call one after the necessary variables (and/or files) for that callback have been synced, the code in the callback will just execute again immediately.

Timing

All callbacks are executed on start, regardless of whether the file(s) or variable(s) have changed. The distinction between our callbacks is their behavior on forceContentUpdate — namely, which files or variables will trigger the callback. You can watch a single variable, a single file, all variables, or all variables and all files.

You must be on version 1.3.0 or newer of our Javascript SDK for the forceContentUpdate method.

callback
executed when
  • start finishes.
  • start finishes.
  • forceContentUpdate finishes and a specific variable has changed.
  • start finishes.
  • forceContentUpdate finishes and any variable has changed.
  • start finishes.
  • forceContentUpdate finishes and a specific file has changed.
  • start finishes.
  • forceContentUpdate finishes and a file or variable has changed.

After Leanplum start

This callback is executed only when the start call finishes and all variables and files are returned from the Leanplum server. It will not be executed on forceContentUpdate.

You can use this callback with a splash screen to wait and then load a new view after start finishes, so you don't have to worry about checking when your variables have their values.

// Add a callback.
Leanplum.onStartResponse{ (success:Bool) in
  // Insert code here.
}
Leanplum.start()

// Or, add a responder that will be executed as a callback.
Leanplum.addStartResponseResponder(self, with: #selector(mySelector(success:)))

func mySelector(success:Bool){
  // Insert code here.
}
// Add a callback.
[Leanplum onStartResponse:^(BOOL success) {
  // Insert code here.
}];
[Leanplum start];

// Or, add a responder that will be executed as a callback.
[Leanplum addStartResponseResponder:self withSelector:@selector(mySelector:)];

- (void)mySelector:(BOOL) success {
  // Insert code here.
}
// Add a new callback.
Leanplum.addStartResponseHandler(new StartCallback() {
  @Override
  public void onResponse(boolean b) {
    // Insert code here.
  }
});
// Add a callback.
Leanplum.Started += delegate(bool success) {
  // Insert code here.
};
Leanplum.Start();
// Add a callback.
Leanplum.addStartResponseHandler(function(success) {
  // Insert code here.
});
Leanplum.start();

When a variable is ready

This callback is executed after start every time, but only after forceContentUpdate if a specific variable has changed (not supported on JavaScript).

// Define the variable with LPVar.define.
var startLabel = LPVar.define("startLabel", with: "Start")

// Then wrap your code in the callback.
startLabel?.onValueChanged({
  self.startButton.titleLabel.text = self.startLabel?.stringValue()
  // Insert code here.
})
// Define the variable with the correct macro.
DEFINE_VAR_STRING(startLabel, @"Start");

// Then wrap your code in the callback.
[startLabel onValueChanged:^{
  self.startButton.titleLabel.text = startLabel.stringValue;
  // Insert code here.
}];
// Define the file variable with Var.define.
Var<String> startLabel = Var.define("welcomeMessage", "Start");

// Then add a handler and pass it a new callback.
startLabel.addValueChangedHandler(new VariableCallback<String>() {
  @Override
  public void handle(Var<String> var) {
    // Insert code here.
  }
});
// Define the variable.
Var<string> startLabel = Var<string>.Define("startLabel", "Start");  

// Then, insert your code in a delegate added to ValueChanged.
startLabel.ValueChanged += delegate {
  // Insert code here.
};

This callback does not wait for files to finish downloading. If you are using file variables, see below.

When all variables are ready

This callback is executed after start every time, but only after forceContentUpdate if any variable has changed.

You can use forceContentUpdate (except in JavaScript) to re-sync with Leanplum during an active session.

Leanplum.onVariablesChanged { () in
  // Insert code here.
}
[Leanplum onVariablesChanged:^() {
  // Insert code here.
}];
Leanplum.addVariablesChangedHandler(new VariablesChangedCallback() {
  @Override
  public void variablesChanged() {
    // Insert code here.
  }
});
Leanplum.VariablesChanged += delegate {
  // Insert code here.
};
Leanplum.addVariablesChangedHandler(function(success){
  // Insert code here.
});

This callback does not wait for files to finish downloading. If you are using file variables, see below.

When a file is ready

This callback will execute after start every time, but only after forceContentUpdate when the file has changed. If the file is unchanged, no download will occur and the callback will not be executed.

// Define the file variable with LPVar.define.
var goldstarImage = LPVar.define("goldStar", withFile: "gold_star.png")

goldStar?.onFileReady { () in
  goldStarImage = UIImage.init(contentsOfFile: (goldStar?.fileValue())!)
}
// Define the file variable with the correct macro.
DEFINE_VAR_FILE(goldStar, @"gold_star.png");

[goldStar onFileReady:^() {
  goldStarImage = [UIImage imageWithContentsOfFile:[goldStar fileValue]];
}];
// Define the file variable with defineAsset.
Var<String> kitten = Var.defineAsset("kitten", "kitten.jpg");

kitten.addFileReadyHandler(new VariableCallback<String>() {
  @Override
  public void handle(Var<String> variable) {
    // Insert code here.
  }
});

When all variables and files are ready

You can also wait for all variable changes and file downloads. This callback will execute after start, but only after forceContentUpdate if any of your Leanplum variables or files have changed.

// Add a callback.
Leanplum.onVariablesChangedAndNoDownloadsPending { () in
  // Insert code here.
}

// Or, add a responder to be executed as a callback.
Leanplum.addVariablesChangedAndNoDownloadsPendingResponder(self, with: #selector(self.customResponder))

func customResponder() {
  // Insert code here.
}
// Add a callback.
[Leanplum onVariablesChangedAndNoDownloadsPending:^() {
  goldStarImage = [UIImage imageWithContentsOfFile:[goldStar fileValue]];
}];
  
// Or, add a responder to be executed as a callback.
[Leanplum addVariablesChangedAndNoDownloadsPendingResponder:self withSelector:@selector(customResponder)];

- (void)customResponder {
  // Insert code here.
}
// Add a callback.
Leanplum.addVariablesChangedAndNoDownloadsPendingHandler(new VariablesChangedCallback() {
    @Override
    public void variablesChanged() {
        // Insert code here.
    }
});
// Add a callback.
Leanplum.VariablesChangedAndNoDownloadsPending += delegate {
  // Insert code here.
};

Testing callbacks in development mode

When you're testing your app, it's often useful to tweak values and see the result instantly. If you use Variable callbacks, your variables will change immediately after you change them in the Leanplum dashboard.

If you want to mimic your users' experience and don't want to see real-time changes when testing, use the start callback, which is only triggered the first time variables receive their values on start.

Leanplum will tell you if it couldn't connect to the server, in which case the values will be whatever they were the last time the app was run (or their default values set in the code if the app hasn't been run yet).

Suggest Edits

Syncing with Leanplum mid-session

Use forceContentUpdate to sync during a user's session, instead of just at session start.

 

Leanplum’s SDK is designed to sync variables, user attributes, messages, and A/B tests on Leanplum.start, at the beginning of a new session. This ensures users receive the latest updates and messages, and that they are entered into latest A/B tests.

A session starts when a unique user has opened the app and initialized Leanplum (calling Leanplum.start). The session end is defined by 30 minutes or more inactivity after the app is backgrounded. A session will also end if the app remains open but inactive for two or more hours. A force quit of the app (killing the app) also counts as a session end.

By default, we do not sync these values in the middle of a user’s session (after the initial call to start). Our SDK was designed this way to keep it as efficient as possible, requiring only one call to Leanplum’s servers for an entire session, and to keep your app as stable as possible by not altering the app as your users use it.

For most cases, syncing on start is the easiest and best way to keep variables, message targeting and A/B test segments up-to-date.

Using forceContentUpdate

However, there may be some cases where you want to update your messaging or A/B tests mid-session, to be sure a user is appropriately targeted and/or included in a test.

Some examples might be:

  • when a user comes back from backgrounding the app (and something may have changed server-side)
  • when a user levels up in a game (State or Event change)
  • when a user goes from a silver member to gold (User Attribute change)

For these cases, you can force a content update by calling Leanplum.forceContentUpdate(), which syncs variables, user attributes, messages, and A/B tests. Any callbacks you have set up, like onVariablesChanged, will be invoked again automatically.

Calling forceContentUpdate will update all of your variables, user attributes, messages and A/B tests, so it can (depending on how your app is set up to work with Leanplum) affect the functionality and UI of your app. Make sure you consider this when implementing forceContentUpdate.

Suggest Edits

Visual editor (UI)

Set up and use the Visual Editor in Leanplum

 

You can edit your app's user interface (UI) using the Leanplum Visual Editor in the dashboard. You only need to add com.leanplum:UIEditor as a dependency. It is activated by including the package in your build.gradle (module) file, without the need for calling any method.

You can edit your app's user interface (UI) and even create new Events using the Leanplum Visual Editor. To do so, you'll need to add the following dependency to your podfile (iOS) or build.gradle (Android).

//Add this to your pod file:
pod 'Leanplum-iOS-UIEditor'

//Also, be sure to include the package in your AppDelegate.
import LeanplumUIEditor

//Then, add a single line of code before [Leanplum start].
LeanplumUIEditor.shared().allowInterfaceEditing()
//Add this to your podfile:
pod 'Leanplum-iOS-UIEditor'

//Also, be sure to include the package in your AppDelegate.
#import <LeanplumUIEditor/LeanplumUIEditor.h>

//Then, add a single line of code before [Leanplum start].
[[LeanplumUIEditor sharedEditor] allowInterfaceEditing];
//Add this to your build.gradle's dependencies:
com.leanplum:UIEditor

//The final product should look something like this:
dependencies {

  ...
  compile 'com.leanplum:Leanplum:2.+'
  compile 'com.leanplum:UIEditor:2.+'
  ...

}

Older versions of our SDK (< 2.0.0) included the UI Editor in the Leanplum package. If you are using one of these versions, you need to call Leanplum.allowInterfaceEditing() before Leanplum.start() to activate the UI Editor.

Then, run your app in development mode, and click the UI tab in the Dashboard.

UI Editor

To create a new interface, click the New button.

  1. Navigate and scroll to any screen in your app you would like to change
  2. Click any element in the Editor to start editing.
  3. Turn your device sideways to see landscape view.

Once you select an element, like a button, you can edit its properties on the right side of the Editor.

To create your interface, click Save & Exit.

This will load the saved interface to the UI Dashboard, where you can target the new interface to select users or A/B test it.

To publish the interface, click the circle next to your interface name and click Active.

Visual events

Create a new event

To create a new event, run your device in development mode. Then, from the Events tab in the Leanplum dashboard, click Create Visual Event.

  1. Follow the instructions to select a view or element to attach an event.
  1. Give your event a name and click Save & Exit.

View results for an event (visual events)

You can track the occurrences of this event in Analytics.

  1. In the Analytics sidebar, click Developer Activity.
  2. Under Daily Breakdown section, click the + tile to create a new metric.
  3. Under Events, select the visual event you created and choose which metrics you wish to track.
  1. To ensure your event tracking is working, run your app in developer mode and perform the event that you chose in step 4. You should see the value on your tile increase to 1.

To track the metric on a release build, wait about 2 hours after creating your event, then create your event-based metric by following steps 2 and 3 in the "User Activity" tab of the Analytics sidebar.

Suggest Edits

Event and parameter tracking

 

Events allow you to track user activity in your app. You can also use events to target users for certain messages, tests, or other content changes. You can verify when an event is tracked in the Debugger or the Events tab in the Leanplum dashboard.

An event is anything that can occur in your app. Events include clicking on a link, sharing, purchasing, killing enemies, etc. All events are timestamped according to when they occur. Thus, it is not advisable to log too many events, as each one will have to be sent to our server.

500 event limit

Note that there is a limit of 500 events per app in Leanplum. Since events are not unlimited, it's best to track more general events, and use parameters to track specific information associated with the event.

For example, you should use a simple name for a purchase event, such as LP_PURCHASE_EVENT and pass a purchase ID or item ID as a parameter.

A parameter is a piece of data associated with an event or state. You can supply parameters as a dictionary along with events and states. Here are some reports you can run with parameters:

  • Filter reports by event parameter values
  • Group metrics by distinct event parameter values (creates a bar graph + table).
    • Example: Show me my top purchased items.
  • Group metrics by ranges of event parameter values (creates a histogram + table).
    • Example: Show me the distribution of purchase prices. Example: Show me the distribution of points scored.
  • Create custom metrics for numeric parameter values, like totals and averages.
    • Example: For a purchase event, track the average revenue and the amount of currency bought per user.

Parameter limitations

Parameters and Event Values are not available in Developer activity analytics, but you can verify your parameters are being tracked correctly in the Debugger console.

Also, with the out-of-box Leanplum SDK, parameters cannot be used as a criteria to target users. For example, if you have an event "Favorite_Color_Selected" with parameters for each color, you would not be able to target users who completed the Favorite color select event and chose the color blue.

Events and states accumulate over time, and we send events in batches periodically to minimize network usage and maximize battery life.

Tracking an event

Add the following lines of code to track an event. You can place the Leanplum track call anywhere as long as it executes after start (examples below):

//This example tracks the event "Launch" after defining the variable "welcomeMessage". 
import UIKit
import Foundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var welcomeMessage = LPVar.define("welcomeMessage", withString: "Welcome to Leanplum!")

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        ...
        Leanplum.onVariablesChanged({
            NSLog((self.welcomeMessage?.stringValue())!)
            Leanplum.track("Launch")
        })
        ...
        return true
    }
...
//This example tracks the event "Launch" after defining the variable "welcomeMessage". 
#import <Leanplum/Leanplum.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ ...
  [Leanplum onVariablesChanged:^{
    NSLog(@"%@", welcomeMessage.stringValue);
    [Leanplum track:@"Launch"];
  }];
  return YES;
}
...
@end
//This example tracks the event "Launch" after defining the variable "welcomeMessage".
import com.leanplum.annotations.Variable;
import com.leanplum.annotations.Parser;

public class ApplicationClass extends Application {

  @Variable public static String welcomeMessage = "Welcome to Leanplum!";

  @Override
  public void onCreate() {
    ...
    Parser.parseVariables(this);

    Leanplum.addVariablesChangedHandler(new VariablesChangedCallback() {
      @Override
      public void variablesChanged() {
        Log.i("Test", welcomeMessage);
        Leanplum.track("Launch");
      }
    });
    ...

    Leanplum.start();
  }
}
//This example tracks the event "Launch".
using LeanplumSDK;

public class LeanplumWrapper : MonoBehaviour
{   ...
    void Start()
    {   ...
      Leanplum.Track("Launch");
    }
}
//Tracks view cart event for a user.
Leanplum.track("View Cart");

Here are some more examples:

// User killed an enemy.
Leanplum.track("Kills")

// User completed a challenge.
Leanplum.track("Score", withValue: 1)
Leanplum.track("Challenges")

// User liked a post.
Leanplum.track("Likes", withInfo: post.id)

// Or, you can supply a dictionary with up to 200 numerical or string parameters.
Leanplum.track("Likes", withParameters:["post":post.id])
// User killed an enemy.
[Leanplum track:@"Kills"];

// User completed a challenge.
[Leanplum track:@"Score" withValue:@1];
[Leanplum track:@"Challenges"];

// User liked a post.
[Leanplum track:@"Likes" withInfo:@"Post Info"];

// Or, you can supply a dictionary with up to 200 numerical or string parameters.
[Leanplum track:@"Likes" withParameters:@{@"post":post.id}];
// User killed an enemy.
Leanplum.track("Kills");

// User completed a challenge.
Leanplum.track("Score", challengeValue);
Leanplum.track("Challenges");

// User liked a post.
Leanplum.track("Likes", post.id());

// Or, you can supply a dictionary with up to 200 numerical or string parameters.
Map<String, Object> params = new HashMap<String, Object>();
params.put("post", post.id());
Leanplum.track("Likes", params);
// User killed an enemy.
Leanplum.Track("Kills");

// User completed a challenge.
Leanplum.Track("Score", challengeValue);
Leanplum.Track("Challenges");

// User liked a post.
Leanplum.Track("Likes", post.id());

// Or, you can supply a dictionary with up to 200 numerical or string parameters.
Dictionary<string, object> params = new Dictionary<string, object>();
params.Add("post", post.id());
Leanplum.Track("Likes", params);

// You can also pass a value and parameters.
// User made a purchase. Use Leanplum.PURCHASE_EVENT_NAME to indicate a purchase.
Dictionary<string, object> item = new Dictionary<string, object>();
params.Add("itemCategory", "Apparel");
Leanplum.Track(Leanplum.PURCHASE_EVENT_NAME, 19.99, item);
// Tracks view cart event for a user.
Leanplum.track("View Cart");

// Tracks view cart event with numeric event parameter, itemsInCart.
Leanplum.track("View Cart", {itemsInCart: 4});

// Tracks an event with a value and two event parameters.
Leanplum.track("Purchase", 4.99, {itemCategory: 'Apparel', itemName: 'Shoes'});

Tracking purchase and monetization events

You can track purchases or other monetization events in Leanplum, which will provide you with revenue metrics in your Analytics reports.

In-app purchases (iOS)

Leanplum supports receipt validation with the App Store and Google Play. On iOS, you can track in-app purchases automatically. Simply add this line of code before Leanplum starts:

Leanplum.trackInAppPurchases()
[Leanplum trackInAppPurchases];
//For iOS
Leanplum.TrackIOSInAppPurchases();

//For Android see Android-specific instructions below.

Leanplum will also convert all purchases to USD. To require valid receipts upon purchase or change your preferred currency, update your preferences in App settings in the dashboard.

To reach your currency settings, click your name in the upper right corner of the dashboard , then select App settings. Next, select "Keys & Settings" next to your app to open this dialogue.

To reach your currency settings, click your name in the upper right corner of the dashboard , then select App settings. Next, select "Keys & Settings" next to your app to open this dialogue.

Android in-app purchases

If your app uses Google Play In-App Billing, Leanplum can automatically track those purchases and validate receipts with the Google Play store. First, provide us with your Google Play license key. Next, add the following code sample in your class that implements ``com.android.vending.billing.util.IabHelper.OnIabPurchaseFinishedListener:

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

import android.util.Log;

import com.android.vending.billing.util.IabHelper.QueryInventoryFinishedListener;
import com.android.vending.billing.util.IabResult;
import com.android.vending.billing.util.Inventory;
import com.android.vending.billing.util.Purchase;
import com.android.vending.billing.util.SkuDetails;

import com.leanplum.Leanplum;
...
@Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
  final Purchase purchase = info;
  billingHelper.queryInventoryAsync(new QueryInventoryFinishedListener() {
    @Override
    public void onQueryInventoryFinished(IabResult result, Inventory inv) {
      // Track in-app purchase.
      SkuDetails skuDetails = inv.getSkuDetails(purchase.getSku());
      try {
        JSONObject skuData = new JSONObject(skuDetails.toString()
            .substring(skuDetails.toString().indexOf(":") + 1));
        Leanplum.trackGooglePlayPurchase(
            skuData.getString("title"), // Alternatively, skuData.getString("productId"), if you like.
            skuData.getLong("price_amount_micros"),
            skuData.getString("price_currency_code"),
            purchase.getOriginalJson(), purchase.getSignature()
            /* optionally supply event parameters as an additional argument */);
      } catch (JSONException e) {
        Log.e("Leanplum", "Cannot get purchase price from improperly formatted SKU");
      }

      // Code to consume purchase.
      // It's important that you do not consume while querying inventory, or you'll receive
      // an IllegalStateException.
      // billingHelper.consumeAsync(purchase, null);
    }
  });
}

Manually tracking monetization events

You can manually track your monetization event within the app. To do so you have to pass a purchase event name, a purchase value, the currency code, and parameters with info about the purchase event with each purchase (all the parameters are required).

The purchase event name is defined by default as “Purchase”. Based on the currency code being passed, the value will be converted to USD automatically in the Dashboard.

Leanplum.trackPurchase(LP_PURCHASE_EVENT, withValue: 5.0, andCurrencyCode: "EUR", andParameters: ["serial" : 12345, "name":"coffee"])
[Leanplum trackPurchase:LP_PURCHASE_EVENT withValue:5.0 andCurrencyCode:@"EUR" andParameters:@{@"serial": @12345, @"name": @"coffee"}];
Map<String, Object> purchaseParams = new HashMap<String, Object>();
...
purchaseParams.put("Item code", 12345);
purchaseParams.put("Name", "Coffee");
Leanplum.trackPurchase(Leanplum.PURCHASE_EVENT_NAME, 5, "EUR", purchaseParams);

Other monetization events

You can also use the standard event tracking for monetization events as well. It works like any other event — just use "Purchase" as the event name and a value.

The only difference is that unlike using trackPurchase, the normal Leanplum.track call will not automatically convert different currencies to USD.

Leanplum.track(LP_PURCHASE_EVENT, withValue:19.99)
[Leanplum track:LP_PURCHASE_EVENT withValue:19.99];
Leanplum.track(Leanplum.PURCHASE_EVENT_NAME, 19.99, item);

The value should be the revenue for the transaction in a common currency.

If you prefer to use a different event name than "Purchase", you can choose a different name. Select the + tile on the Analytics page for a new metric. In the dialogue box that opens, select the Monetization category and edit the purchase event. The changes will be applied retroactively.

Editing the purchase event in Analytics.

Editing the purchase event in Analytics.

Whether you choose your own name for purchase events or use the default LP_PURCHASE_EVENT, make sure to stay consistent and always use the same event name.

Suggest Edits

State tracking

 

A state is any part of your app a user can be in. For example, some states can include being in a particular level, watching a video, or browsing an in-app store.

All states have a time and a duration. The duration is set automatically — when one state begins, the previous one ends.

Advancing to a state

This example is called when the user advances to the next level.

Leanplum.advance(to: "Level", withInfo:level.name)
[Leanplum advanceTo:@"Level" withInfo:level.name];
Leanplum.advanceTo("Level", level.name());
Leanplum.AdvanceTo("Level", level.Name);
// Tracks a state with a numeric parameter.
Leanplum.advanceTo("Cart", {numItems: 2});

Pausing and resuming

This is useful if your game has a "pause" mode. You shouldn't call it when someone switches out of your app because that's done automatically.

Leanplum.advance(to:nil)
[Leanplum advanceTo:nil];
Leanplum.pauseState();
Leanplum.resumeState();
Leanplum.PauseState();
Leanplum.ResumeState();
Leanplum.pauseState();
Leanplum.resumeState();

The nil / null state

This state causes the user to leave the current state and not enter another one.

Leanplum.advance(to:nil)
[Leanplum advanceTo:nil];
Leanplum.advanceTo(null);
Leanplum.AdvanceTo(null);
Leanplum.advanceTo(null);

Automatically track states for each view

// Automatically track states for each view controller - this currently requires the UIEditor module.
// This code should appear before you display any view controllers in your app.
Leanplum.trackAllAppScreens()
//Automatically track states for each view controller - this currently requires the UIEditor module.
// This code should appear before you display any view controllers in your app.
[Leanplum trackAllAppScreens];
// This code should appear before you display any views in your app.
// Place in the application class before calling Leanplum.start().
Leanplum.trackAllAppScreens();
Suggest Edits

User and device tracking

 

When Leanplum starts for the first time in your app, it creates a new user profile or User ID. Unless you set up your own concept of User IDs, the UserID value will be identical to the DeviceID value, and Leanplum will start tracking sessions for this user.

Sessions are how Leanplum organizes each user's events, states, and other general activity.

See below for more on handling user IDs, devices, and sessions.

Suggest Edits

Device IDs

 

The device ID uniquely identifies the devices and is determined automatically by the SDK. See below for details on iOS and Android device IDs.

If you plan on using external attribution services, make sure the device ID you set matches the device ID sent by your attribution provider (e.g. IDFV -> IDFV). See How to integrate external Attribution services for more.

iOS device ID

On iOS, by default, we use the identifierForVendor. If the device is pre-iOS 6, we use a hash of the MAC address, and in development mode, we use the advertising identifier.

You can choose how the device ID is set the first time start is called on that device by calling one of these before start:

  • LEANPLUM_USE_ADVERTISING_ID: a macro that uses the advertising identifier.
  • [Leanplum setDeviceId:@"customAndUniqueId"]: Sets the device ID to a custom ID. Make sure that your custom ID is unique per device.

The deviceId is set when Leanplum start runs for the first time on that device. After this, it cannot be changed unless the user completely uninstalls and reinstalls your app.

Android device ID

On Android, by default, we use an MD5 hash of the MAC address if the user is on a version prior to Marshmallow (Android 6) and if your app has ACCESS_WIFI_STATE permissions. Otherwise, we use the ANDROID_ID.

You can choose how the device ID will be set the first time start is called on that device by calling one of these before start:

  • Leanplum.setDeviceIdMode(LeanplumDeviceIdMode.ANDROID_ID) Uses the ANDROID_ID.
  • Leanplum.setDeviceIdMode(LeanplumDeviceIdMode.ADVERTISING_ID) Uses advertising ID if available; otherwise, uses the MD5 hash of the MAC address if the user is on a version prior to Marshmallow (Android 6) and your app has ACCESS_WIFI_STATE permissions. Otherwise, we use the ANDROID_ID.
  • Leanplum.setDeviceId("customAndUniqueId") Sets the device ID to a custom ID. Make sure that your custom ID is unique per device.

The deviceId is set when Leanplum start runs for the first time on that device. After this, it cannot be changed unless the user completely uninstalls and reinstalls your app.

Whether or not you set a DeviceIdMode, the SDK uses the following logic to set the deviceId (unless you use setDeviceId):

  1. If DeviceIdMode is set to ADVERTISING_ID, use ADVERTISING_ID if available. Otherwise, continue.
  2. If DeviceIdMode is set to ANDROID_ID, use ANDROID_ID if available. Otherwise, continue.
  3. If a MAC address is available (Android < 6.0 and ACCESS_WIFI_STATE permission), use a hash of the MAC address. Otherwise, continue.
  4. If ANDROID_ID is available, use ANDROID_ID. Otherwise, continue.
  5. Otherwise, use a randomly generated device ID.

You can view the source code here.

Unity device ID

The device ID uniquely identifies the devices and is determined automatically by the SDK. On Unity, we use SystemInfo.deviceUniqueIdentifier to get the device ID. Refer to the Unity documentation to learn more.

JavaScript (HTML5) device ID

The device ID uniquely identifies the devices and is determined automatically by the SDK. In the JavaScript SDK, we generate a unique device ID from a random selection of numbers and letters totaling 16 characters. We take that device ID and persist it using localStorage. You can set a custom device ID instead using Leanplum.setDeviceId.

 

When Leanplum start is called for the first time on a device, a new user profile is created and Leanplum starts tracking activity and sessions for this user. If no custom User ID is sent with the start call, the User ID value is set to the Device ID.

If you have your own concept of User IDs, you can pass a User ID in the start call. This way, if the user has multiple devices, we will count them as the same user and merge their profiles.

Leanplum.start(withUserId: "user1234")
[Leanplum startWithUserId:@"user1234"];
Leanplum.start(this, "user1234");
Leanplum.Start("user1234");
Leanplum.start('user1234');

// Start with user ID and attributes.
Leanplum.start('user1234', {'gender': 'Female'});

In some cases, you can also set the User ID after start. See more below:

Logins

Passing a user ID with start may not work well if you have a login system. You should still call start early on to track user activity, then set the user ID later on with setUserId when the user logs in.

Leanplum.setUserId("user1234")
[Leanplum setUserId:@"user1234"];
Leanplum.setUserId("user1234");
Leanplum.SetUserId("user1234");
Leanplum.setUserId("user1234");

// Set user attributes and ID at the same time.
Leanplum.setUserAttributes('user1234', {'gender': 'Female'});

When the user ID is set for the first time on a device, the existing profile in Leanplum is updated with that user ID and all previously tracked data remains.

After the first setUserId call, each subsequent call that includes a different ID will end the current User session, and create a new session for the new User. If the new User ID doesn't exist, a new User Profile will be created in Leanplum.

Here's how setting the user ID with setUserId works with typical registration and login scenarios:

  • Register: If a user ID has not been set on this device yet and the supplied user ID does not exist, Leanplum will update the current user profile (created on start) with the supplied user ID (replacing the device ID).
  • Login: If a user ID has not been set on this device yet and the supplied user ID does exist, the current and existing user profiles will be merged. This ensures that users with multiple devices are tracked as one user. If the same user logs back in on this device, no changes will be made to their profile since their user ID is already set.
  • Switch user: If a user ID has been set on this device and the supplied user ID is different, the current session will be ended and a new session will be started for the supplied user ID. A user with the supplied user ID will be created if one does not already exist.

Logouts

Leanplum will not end the session after a user logs out and does not include any methods to do so. All user activity is tracked and attributed to the last logged-in user (set by the setUserId call). This allows you to track activity in your app even while the user is logged out.

If you want to keep track of which users are logged in and which are logged out, set a user attribute (e.g. logged_in).

Do not set a different user ID to handle logouts. This will create a new user profile in Leanplum and start a new session for them, which will skew your analytics.

Suggest Edits

User attributes

 

A user attribute is any piece of data associated with a user that you provide to the SDK. Each session has its own user attributes, but they get copied from one session to the next. This is in contrast to event parameters, which may take on different values per event. For this reason, you generally use user attributes for things that do not change much within the session, or with which you want the entire session associated.

Uses:

  • Personalizing content (variables, messages, resources, and interfaces) to different types of users.
  • Targeting an A/B test.
  • Filtering reports by a particular user attribute, like only looking at data for "whales".
  • Grouping reports (constructing a bar graph or histogram), by different attribute values. E.g. Create a histogram of average session length by number of friends.

Examples:

  • Gender
  • Age
  • Number of friends
  • User interests

Constraints:

  • Up to 200 attributes can be defined for your app.
  • Attribute names must be strings, and values must be strings or numbers.
  • Attribute values will be the same across all events and states in a particular session.
// Passing attributes at session start allows us to target content based on the attributes.
Leanplum.start(userAttributes: ["gender":"Female", "age": 29])

// You can also pass them later on in the session, but you won't be able to
// target variables or messages at these for that session.
Leanplum.setUserAttributes(["gender":"Female", "age": 29])

// Clear an attribute.
Leanplum.start(userAttributes: ["gender":NSNull()])
// Passing attributes at session start allows us to target content based on the attributes.
[Leanplum startWithUserAttributes:@{@"gender": @"Female", @"age": @29}];

// You can also pass them later on in the session, but you won't be able to
// target variables or messages at these for that session.
[Leanplum setUserAttributes:@{@"gender": @"Female", @"age": @29}];

// Clear an attribute.
[Leanplum startWithUserAttributes:@{@"gender": [NSNull null]}];
// Passing attributes at session start allows us to target content based on the attributes.
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("gender", "Female");
attributes.put("age", 29);
Leanplum.start(this, attributes);

// You can also pass them later on in the session, but you won't be able to
// target variables or messages at these for that session.
Leanplum.setUserAttributes(attributes);

// Clear the attributes.
attributes.put("gender", null);
attributes.put("age", null);
Leanplum.setUserAttributes(attributes);
// Passing attributes at session start allows us to target content based on the attributes.
Dictionary<string, object> attributes = new Dictionary<string, object>();
attributes.Add("gender", "Female");
attributes.Add("age", 29);
Leanplum.Start(attributes);

// You can also pass them later on in the session, but you won't be able to
// target variables or messages at these for that session.
Leanplum.SetUserAttributes(attributes);

// Clear the attributes.
attributes.Add("gender", null);
attributes.Add("age", null);
Leanplum.SetUserAttributes(attributes);
// Passing attributes at session start allows us to target content based on the attributes.
var attributes = {'gender': 'Female', 'age': 29};
Leanplum.start(attributes);

// You can also pass them later on in the session, but you won't be able to
// target variables or messages at these for that session.
Leanplum.setUserAttributes(attributes);

// Clear the attributes.
Leanplum.setUserAttributes({'gender': null, 'age': null});
Suggest Edits

In-app messaging

 

Leanplum comes with a number of in-app message templates, including alerts, confirmation messages, popups, and full-screen interstitials. They are all open source, so you can customize them however you want, and you can even create your own templates.

To enable in-app messaging, you'll need to integrate the Leanplum SDK and run your app at least once in development mode.

Once you finish the SDK setup, you can trigger in-app messages to send after an event or when the app starts. Any trigger events must be tracked with our SDK, but there's no additional coding needed.

Suggest Edits

Customizing in-app message templates

 

Our in-app messaging templates are open-source, which means you can modify them, delete them, or create your own. The Leanplum dashboard will reflect your new templates the next time you run your app.

Once the templates are created or customized, they can be synced with Leanplum, just like Variables, by running the app in Development mode on a registered test device. The process of customizing these templates differs slightly depending on the platform:

iOS custom templates

The files LPMessageTemplates.h and LPMessageTemplates.m come with the SDK. Just download the SDK, unzip, and put the template files in your project. Then, initialize them before the [Leanplum start] call with:

[LPMessageTemplates sharedTemplates];

Take a look at LPMessageTemplates.m to see how the messages are implemented.

To define a new template, use the method:

[Leanplum defineAction:ofKind:withArguments:withResponder:]

Here's how it works:

  • defineAction: The name of the action or message type you are defining.
  • ofKind: One or more action kinds OR'ed together. kLeanplumActionKindMessage will appear in the Message Type list for creating message campaigns. kLeanplumActionKindAction will appear in the dropdown when choosing an action within a message.
  • withArguments: A list of LPActionArg objects, with each one being an argument that the marketer can fill out on the dashboard. For example, Title, Accept action, or Color.
  • withResponder: A block that accepts an LPActionContext and returns a BOOL whether the action was handled or not. You may decide not to handle the action based on some additional logic defined in the responder. From the context, you can access the values for any argument you defined in the template, as well as some other special methods:
    • [LPActionContext runActionNamed:]: Runs another action when this action is done. The action name should correspond to a named LPActionArg of kind Action.
    • [LPActionContext runTrackedActionNamed:]: Runs another action and tracks an event that the action occurred.
    • [LPActionContext track:withValue:andParameters:]: Tracks an event associated with the current action.
    • [LPActionContext muteFutureMessagesOfSameKind]: Don't show the current message campaign again on this device. For example, if you have a survey popup every 10th session, you may want the ability for the user to decide to remind them later, which simply dismisses the message, or the option to never see this survey again.

iOS sample project: custom template

Take a look at the sample project here.

In this sample, we are adding a new in-app message template — specifically, a three-button Confirm message.

First, open the AppDelegate.m and import the LPMessageTemplate class. Then put [LPMessageTemplates sharedTemplates] before [Leanplum start];

OpenLPMessageTemplates.m and check in the sample where the "#### example" comments are placed — you'll find the code parts being added to create the new in-app message template and comments describing each code part being added.

Next, build and run the project. If the device is registered as a Test Device, the three-button message will be added to the available in-app templates in the Dashboard. You may also have to hit the 'sync templates' button in the dashboard to see the final template.

Updates from your connected development device.

Updates from your connected development device.

Android custom templates

First, download the Leanplum Android SDK zip archive, if you haven't already.

Unzip the archive and look for src/com/leanplum/customtemplates. Add all of these files to your project, preserving the directory structure com/leanplum/customtemplates.

Initialize them in your Application class (and before calling Leanplum.start()):
com.leanplum.customtemplates.MessageTemplates.register(getApplicationContext());

Look at the provided files to see how the messages are implemented. To define a new template, use the method Leanplum.defineAction(). Here's how it works:

  • name: The name of the action or message type you are defining.
  • kind: One or more action kinds OR'ed together. Leanplum.ACTION_KIND_MESSAGE will appear in the Message Type list for creating message campaigns. Leanplum.ACTION_KIND_ACTION will appear in the dropdown when choosing an action within a message.
  • args: An ActionArgs instance, defining the options that the marketer can fill out on the dashboard. For example, Title, Accept action, or Color.
  • responder: A callback that accepts an ActionContext and returns a boolean whether the action was handled or not. You may decide not to handle the action based on some additional logic defined in the responder. From the context, you can access the values for any argument you defined in the template, as well as some other special methods:
    • ActionContext.runActionNamed(): Runs another action when this action is done. The action name should correspond to a named action argument defined within ActionArgs.
    • ActionContext runTrackedActionNamed(): Runs another action and tracks an event that the action occurred.
    • ActionContext.track(): Tracks an event associated with the current action.
    • ActionContext.muteFutureMessagesOfSameKind(): Don't show the current message campaign again on this device. For example, if you have a survey popup every 10th session, you may want the ability for the user to decide to remind them later, which simply dismisses the message, or the option to never see this survey again.

Android sample project: custom template

The project sample can be found here.

In this sample we are also adding a new In-App message — specifically, a three-button Confirm message.

Download the Android SDK from the Leanplum SDK Setup page and extract the archive. com/leanplum/customtemplates has been copied from the Android SDK folder and added to the project and in the Application class. Before Leanplum.start, com.leanplum.customtemplates.MessageTemplates.register(getApplicationContext()); is placed.

Unlike the iOS Message Templates, every template is included in its own class in Android.

Create a new class specific to the new message template. In the sample, we've called it 'Confirm3Buttons'. The class name will also be the new template's name in the Leanplum dashboard.

Open the Confirm3Buttons class and check for the "#### example" comments — you'll find the code parts being added to create the new in-app message template and comments describing each code part being added.

The last step is to register the newly added in-app message. Open the MessageTemplates class and add Confirm3Buttons.register(currentContext); in the 'register' function.

To sync the new template to the Leanplum dashboard, run the project on a registered test device. You may also have to hit the 'sync templates' button in the dashboard to see the final template.

Updates from your connected development device.

Updates from your connected development device.

Suggest Edits

Sending iOS 10.3+ app review requests

 

With iOS 10.3, Apple changed how apps can request reviews from users. Per their release notes, developers must now use the SKStoreReviewController API to ask users to rate or review the app while they're using it, without being redirected to the App Store. This is part of a larger overhaul of Apple's ratings and reviews.

To send an app review request on Android or iOS 10.2-, see Send an app review request (Android or iOS 10.2 and earlier).

You can now control when in your app to present the review prompt by calling the API in your app's code, or by using Leanplum's in-app messaging templates — follow the steps below to set up the new App review request.

Update Xcode and your pods/dependencies

Before you can take advantage of the new features in iOS 10.3, you'll need to update Xcode and update your pods/dependencies to get our latest SDK version (requires 1.7.0+).

  1. Update Xcode to version 8.3.
  2. Update your pods to Leanplum iOS SDK 1.7.0+. From the terminal or command prompt, go to your project's root directory and run: pod update
  3. Confirm in the pod notes that Leanplum SDK 1.7.0+ has been installed.
  4. Build and run your app using a registered test device.

If you do not see the "Request App Rating" under In-App Actions, you may need to click the refresh button at the top of the In-app templates dropdown menu, or refresh the page in your browser.

Our dashboard will not show the new in-app message template for app reviews until you run a test device built from Xcode 8.3 with the Leanplum iOS SDK 1.7.0+. If your test devices use older versions of our SDK, the dashboard will not display features exclusive to 1.7.0+.

Resubmit your app to the App Store

Once you've finished making the above changes and testing locally, you'll need to resubmit your app to the App Store. You can then start testing App Review prompts using Leanplum.

Suggest Edits

Push notifications

 

Setting up push notifications with Leanplum allows you to send notifications through the Leanplum dashboard or with the API. In the dashboard, you'll be able to customize the content of your push notifications and create campaigns that combine push with other messaging channels.

Select your OS or language below for specific instructions on setup and other push-related features.

iOS

More on setup, iOS notification types, badge counts, and more.

Android

More on setup and customizing android notifications.

Unity

More on setup for iOS and Android notifications.

JavaScript

More on web push notifications using our HTML5 SDK.

Suggest Edits

iOS push notifications

iOS push setup, categories, badge counts, alerts, and testing

 

To enable Push Notifications on iOS, you need to upload your certificates to Leanplum and register for remote notifications in your app.

iOS push setup

  1. Login to the iOS provisioning portal.
  2. In the Identifiers > App IDs, select your app, click Edit, and enable Push Notifications.
  3. Click Create Certificate for each of the Development and Production certificates and follow the onscreen instructions. You should not reuse existing certificates so that we can track delivery failures properly.
  4. Download your new certificate files from your browser. Open the files on your computer, which will launch Keychain.
  5. In Keychain, select the new certificates, expand them to view the private key, and then right click to export them as .p12 files. You must enter a password.
  6. In Leanplum, go to your app's Keys & Settings (App Settings > {Your app} > Keys & Settings). Under Push Notifications, upload your .p12 files to Leanplum and enter your passphrase from step 5 above.
  7. Configure your app to use push notifications in your app delegate's applicationDidFinishLaunching method. Example:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    //iOS-10
    if #available(iOS 10.0, *){
        let userNotifCenter = UNUserNotificationCenter.current()

        userNotifCenter.requestAuthorization(options: [.badge,.alert,.sound]){ (granted,error) in
            //Handle individual parts of the granting here.
        }
        UIApplication.shared.registerForRemoteNotifications()
    }
    //iOS 8-9
    else if #available(iOS 8.0, *){
        let settings = UIUserNotificationSettings.init(types: [UIUserNotificationType.alert,UIUserNotificationType.badge,UIUserNotificationType.sound],
                                        categories: nil)
        UIApplication.shared.registerUserNotificationSettings(settings)
        UIApplication.shared.registerForRemoteNotifications()
    }
    //iOS 7
    else{
        UIApplication.shared.registerForRemoteNotifications(matching:
            [UIRemoteNotificationType.alert,
             UIRemoteNotificationType.badge,
             UIRemoteNotificationType.sound])
    }
    //Other code.
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    id notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
    if (notificationCenterClass) {
        // iOS 10.
        SEL selector = NSSelectorFromString(@"currentNotificationCenter");
        id notificationCenter =
        ((id (*)(id, SEL)) [notificationCenterClass methodForSelector:selector])
        (notificationCenterClass, selector);
        if (notificationCenter) {
            selector = NSSelectorFromString(@"requestAuthorizationWithOptions:completionHandler:");
            IMP method = [notificationCenter methodForSelector:selector];
            void (*func)(id, SEL, unsigned long long, void (^)(BOOL, NSError *__nullable)) =
            (void *) method;
            func(notificationCenter, selector,
                 0b111, /* badges, sounds, alerts */
                 ^(BOOL granted, NSError *__nullable error) {
                     if (error) {
                         NSLog(@"Leanplum: Failed to request authorization for user "
                               "notifications: %@", error);
                     }
                 });
        }
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else if ([[UIApplication sharedApplication] respondsToSelector:
                @selector(registerUserNotificationSettings:)]) {
        // iOS 8-9.
        UIUserNotificationSettings *settings = [UIUserNotificationSettings
                                                settingsForTypes:UIUserNotificationTypeAlert |
                                                UIUserNotificationTypeBadge |
                                                UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        // iOS 7 and below.
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
        #pragma clang diagnostic pop
         UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge];
    }

    // Other code.
}

Note: You can choose any combination of formats — this is just an example.

If you are implementing application:didReceiveRemoteNotification:fetchCompletionHandler in your code, you should call the completion handler yourself.

Push categories

iOS 8 supports push notification categories, which allow you to provide interactivity to your notifications with custom actions. To use this, define categories in your code — check out Apple's dev docs.

Leanplum allows you to choose the category of your notifications from the dashboard, track each custom action, and even define the logic for what happens on each action. To use categories with Leanplum, you'll need additional calls to Leanplum to handle custom actions in your app delegate. If you call [Leanplum handleActionWithIdentifier], do not call completionHandler as Leanplum will call this internally when it's ready.

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier
    forRemoteNotification:(NSDictionary *)notification completionHandler:(void (^)())completionHandler
{
    [Leanplum handleActionWithIdentifier:identifier
                   forRemoteNotification:notification
                       completionHandler:completionHandler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler
{
    [Leanplum handleActionWithIdentifier:identifier
                    forLocalNotification:notification
                       completionHandler:completionHandler];
}
let generalCategory = UNNotificationCategory(identifier: "GENERAL",
                                             actions: [],
                                             intentIdentifiers: [],
                                             options: .customDismissAction)
 
// Register the category.
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([generalCategory])

It's a good practice to show additional information or navigate to the correct part of your app when users open your push notifications. You can do that using Leanplum's in-app messaging, which integrates nicely with push notifications. There's no additional coding needed.

Badge counts

The app icon badge is meant to display a count of unread items that await the user's attention. By design, this relies entirely on a remote server to be the system of record; each push notification can set the count with a badge attribute in the payload. If the value is 0, iOS will clear the count and remove the badge. If a value is not set in the payload, the count remains the same.

For example, this payload sets the badge to 9.

{
    "aps" : {
        "alert" : "You got your emails.",
        "badge" : 9
    },
    "acme1" : "bar",
    "acme2" : 42
}

This payload clears the badge, even if the user does not open the notification. A silent push works the same way, but would not include an alert value.

{
    "aps" : {
        "alert" : "You got your emails.",
        "badge": 0
    },
    "acme1" : "bar",
    "acme2" : 42
}

In the Composer, you can set the badge value in your push notification to any number. Leaving the field blank will do nothing (i.e. maintain the current badge count), and setting it to zero will clear the count.

You cannot increment the existing badge count directly from Leanplum's dashboard, but you can add some code to your app to increment and clear the badge count.

To increment the badge whenever a push is received in the background, add the following to didReceiveRemoteNotification in your delegate:

func application(_ application: UIApplication,
                          didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                          fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

  // Only increment badge if in background.
  if application.applicationState == .background {
    UIApplication.shared.applicationIconBadgeNumber += 1
  }

  completionHandler(.newData)
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

  // Only increment badge if in background.
  if(application.applicationState == UIApplicationStateBackground) {
    NSInteger badge = [[UIApplication sharedApplication] applicationIconBadgeNumber];
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: badge + 1];
  }

  completionHandler(UIBackgroundFetchResultNewData);
}

To clear the count on app start or resume, you could implement the following in your applicationDidBecomeActive delegate method. However, this would clear the count even if they open the app by some means other than opening the push notification.

func applicationDidBecomeActive(_ application: UIApplication) {
    // Clear app badge on start or resume.
    UIApplication.shared.applicationIconBadgeNumber = 0
}func applicationDidBecomeActive(_ application: UIApplication) {
    // Clear app badge on start or resume.
    UIApplication.shared.applicationIconBadgeNumber = 0
}
func applicationDidBecomeActive(_ application: UIApplication) {
    // Clear app badge on start or resume.
    UIApplication.shared.applicationIconBadgeNumber = 0
}

Custom alert sounds

You can set a custom alert sound for a push notification via the Leanplum Message Composer. However, before doing so, you must include the sound file in your app, following Apple's guidelines for file type, length and size. See Preparing Custom Alert Sounds.

Once the file is available in your app, simply enter the filename with the extension for the iOS push option sound for the message.

Testing

Once you've set up push notifications, test that it is working properly. Send a push notification to your development devices. Run your app, wait a few seconds, and then press the home button.

Troubleshooting

  1. On the device, verify the app is configured to enable pushes: Settings -> Notification Center -> {Your app name}
  2. Recreate the provisioning profile. See iOS provisioning portal.
Suggest Edits

Android push notifications

Android push setup, push services, notification channels, and customization

 

See more on push notification services, Android Notification Channels, and customizing push notifications:

Using push notification services (Android)

Generally, you can configure your Android project to use Leanplum push services with other custom or third-party push notification services by creating custom classes that extend the correct Leanplum push messaging classes.

Leanplum supports both Firebase Cloud Messaging (FCM) and Google Cloud Messaging (GCM), but you can only use one of them at a time to deliver push notifications from Leanplum.

Create a custom class to receive push messages

Regardless of whether you are using GCM or Firebase, you will need to create a custom class (if you haven't already) to define the behavior for your project after receiving a Push Message. The only difference (between GCM and Firebase) is which class you should extend.

For GCM, the new class .Custom_PushListener must extend the LeanplumPushListenerService class (which is extending GcmListenerService).

public class Custom_PushListener extends LeanplumPushListenerService {
// ...
    @Override
    public void onMessageReceived(String var, Bundle notificationPayload) {
        // This ensures the Leanplum code is executed once a Push Notification message is received
        super.onMessageReceived(var, notificationPayload);
        // The remaining code will be executed in addition to the Leanplum default behavior
        Log.i("### ", "Push received");
    }
}

For Firebase, the new class .Custom_FirebaseMessagingService must extend the LeanplumPushFirebaseMessagingService class (which is extending FirebaseMessagingService).

public class Custom_FirebaseMessagingService extends LeanplumPushFirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
       super.onMessageReceived(remoteMessage);
        Log.i("### ", "Firebase message received");
    }
}

For both GCM and Firebase, your custom class must include the onMessageReceived method, which should override its parent method but still call super.onMessageReceived(). This will make sure the Leanplum code in the extended class is executed when the push notification is received. You can place any custom code within this method after this call.

We will invoke this custom class later with a service in the Android Manifest.

Create a custom class to handle push token refreshes (Firebase only)

Because Leanplum needs to monitor any changes to the push token with Firebase, you must register a service around the com.google.firebase.INSTANCE_ID_EVENT intent. To do that, you first must create a .Custom_PushFcmListenerService class that extends the LeanplumPushFcmListenerService class (which is extending FirebaseInstanceIdService).

Note: This class must have an onTokenRefresh method that overrides its parent and also calls super.onTokenRefresh() to fetch the updated Instance ID token and notify Leanplum app's server of any changes.

public class Custom_PushFcmListenerService extends LeanplumPushFcmListenerService {
    @Override
    public void onTokenRefresh() {
        super.onTokenRefresh();
    }
}

Invoke the custom class(es) in your Manifest

Assuming you have already implemented our SDK and modified your Application class and AndroidManifest.xml file as documented in the Android setup, you will just need to make a few modifications to your Manifest in order to use the push services.

For GCM, you'll only need to modify a single service for the com.google.android.c2dm.intent.RECEIVE intent so that it will invoke the .Custom_PushListener class (created above).

Change the android:name attribute to point to your custom class.

<service
    <!-- android:name="com.leanplum.LeanplumPushListenerService" -->
    android:name=".Custom_PushListener"
    android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>

For Firebase, you will need to edit two services for the com.google.firebase.MESSAGING_EVENT and com.google.firebase.INSTANCE_ID_EVENT intents so that they invoke the .Custom_FirebaseMessagingService and .Custom_PushFcmListenerService classes respectively.

Change the android:name attributes to point to your custom classes.

<service
    <!-- android:name="com.leanplum.LeanplumPushFirebaseMessagingService" -->
    android:name=".Custom_FirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
<service
    <!-- android:name="com.leanplum.LeanplumPushFcmListenerService" -->
    android:name=".Custom_PushFcmListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>

Sample Projects for push services on Github

A sample GCM project demonstrating multiple push services is available here, and you can see its manifest file here.

A sample Firebase project is available here, and you can see its manifest file here.

Android Notification Channels

Introduced as part of Android 8.0 (Oreo), notification channels give developers more control over push notification customization and management.

If your audience includes Android 8 users, you must implement one or more notification channels in order to send notifications to your users. Sending a push notification to Android 8 users without specifying a valid notifications channel will cause the message to fail to post, and the system will log an error.

Notification channels allow app developers to categorize their push notifications based on the type of content. With channels, you can modify the color of the notification, the sound and vibration pattern it makes, how prominently the notification appears on the user's device, and more. See Android's documentation for more info.

1. Set up Android Notification Channels in Leanplum

Developers can add, delete, or modify notification channels via our API.

See our API docs for more on the methods addAndroidNotificationChannel and deleteAndroidNotificationChannel.

2. Send a push notification with Android Notification Channels

Once a developer adds a notification channel via our API, your new channel should be accessible for use in the Campaign Composer.

Select your desired channel from the dashboard to send a push notification. The Notification channel setting should be in Advanced options in the push notifiction's settings.

This is in the Edit window of the push notification action.

This is in the Edit window of the push notification action.

Make sure you test any new channels on a real device before sending notifications out to users.

3. See all notification channels defined in Leanplum

To see all the notification channels defined in Leanplum, see our API docs for more information on the getAndroidNotificationChannels API call.

These channels are also visible in the Leanplum Campaign Composer — just click the current Notification channel under Advanced Options to reveal a dropdown with all of your available Android notification channels.

Customizing push notifications 🎨

You can customize the appearance of notifications using LeanplumPushService.setCustomizer in your Application class's onCreate method. From there, you can perform any customizations you want to the NotificationCompat object. You can also use the customizer to easily be notified of incoming pushes from Leanplum. You can access some of the notification's properties, like the message, using bundle.getString("lp_message"), and any custom values you defined in Advanced Options > Data in the message config through the dashboard.

For a detailed example, see our guide on Customizing push notifications.

It's a good practice to show additional information or navigate to the correct part of your app when users open your push notifications. You can do that using Leanplum's in-app messaging, which integrates nicely with push notifications.

Suggest Edits

Unity push notifications

Unity push notifications setup

 

To setup push notification support, Leanplum provides a couple of built-in methods that will help you.

iOS setup for push

On iOS, use the following code to register your app for remote notifications after Leanplum starts. This simply registers through the iOS framework for alerts, badges, and sounds.

Leanplum.RegisterForIOSRemoteNotifications();
Alternatively, if you want to register in a custom way, you can add the registration code in your Objective-C code.

For iOS, you'll also need to upload your certificates to Leanplum. Refer to the iOS SDK docs for instructions.

Android setup for push

On Android, you need to setup your Google Cloud Messaging sender ID. You can do this in C# or in Java. Leanplum provides a built-in sender ID, or you can use your custom ID.

Make sure that the sender ID or IDs you pass to Leanplum are consistent with those used anywhere else in your app, including with other third-party SDKs. Inconsistent IDs could prevent your users from receiving some notifications. Use one of the following before Leanplum starts:

// Use the built-in sender ID.
Leanplum.SetGcmSenderId(Leanplum.LeanplumGcmSenderId);

// Use your own sender ID.
Leanplum.SetGcmSenderId("123456790abcdef");

// Use both sender IDs, for ex. if you want Leanplum to send notifications through Leanplum's ID
// and your own server to send notifications through your own ID.
Leanplum.SetGcmSenderIds("123456790abcdef", Leanplum.LeanplumGcmSenderId);

If you're using your own sender ID, you need to give Leanplum permission to send notifications on your behalf. Simply paste your Google API key (this is different from your sender ID) in your app's Push Notification settings.

On Android, you'll also need to add some items to your manifest. Refer to the Android SDK setup for the appropriate code.

It's a good practice to show additional information or navigate to the correct part of your app when users open your push notifications. You can do that using Leanplum's in-app messaging, which integrates nicely with push notifications. There's no additional coding needed.

Test Push Notifications

Once you've set up push notifications, test that it is working properly by sending a push notification to your development devices.

Suggest Edits

JavaScript push notifications

Web push notifications (HTML5)

 

Leanplum supports web push notifications (Contact your CSM to activate this feature). This is currently the only messaging channel for our Javascript SDK.

Supported browsers

Web Push is currently in beta and available for select browsers.

Due to an iOS limitation, we do not support web push on any mobile browsers on iOS, including Safari and Chrome.

Browser
Android
iPhone
Mac OSX
Windows PC

Chrome v52+

Yes

No

Yes

Yes

Firefox v46+

Yes

No

Yes

Yes

Opera v46+

Yes

No

No

No

Safari

No

No

No

No

Edge

No

No

No

No

Samsung Internet Browser

No

No

No

No

MacOS supports icons but does not support images. The push notification will still display, but the image will be ignored. See Google's developer docs for more.

New methods

Four public methods have been added to the HTML5 SDK to support web push.

Method
Description

isWebPushSupported

Determines if web push is supported by the user's browser. Returns a boolean of True or False.

isWebPushSubscribed

Determines if the user is subscribed for web push. Returns a boolean of True or False.

registerForWebPush

Registers the user's browser for web push.

unregisterFromWebPush

Unsubscribes the user and removes the push token. (Does not unregister the service worker registration.)

These can be used to prompt the user to register for web push. We have provided a sample implementation where a toggle registers and unregisters a user for web push. Specifically, see implementation for toggle initialization and toggle switching.

Enabling Web Push

To enable web push, you first need to include the Service Worker file in your root directory and register it in your code, so the browser can use it to run the necessary background processes.

Our SDK has a method that handles the Service Worker registration for you; you just need to pass the filepath to registerForWebPush. The Leanplum SDK also includes a fully working sw.min.js file that you can use as your Worker.

For security reasons, service workers only run over HTTPS.

Before registering the device for push, we recommend checking that the device and browser support web push, and that the device has not already been registered. You can do this with isWebPushSupported and isWebPushSubscribed, both of which return a boolean.

import leanplum from `leanplum-sdk`

let isSubscribedToWebPush = false;
let isWebPushSupported = leanplum.isWebPushSupported();
if(isWebPushSupported){
  leanplum.isWebPushSubscribed().then(subscriptionStatus => {
      isSubscribedToWebPush = subscriptionStatus;
  });
}

Then, you can register the device for push:

if(isWebPushSupported && !isSubscribedToWebPush){
  // Register by passing SW filepath (which is in our root directory).
  leanplum.registerForWebPush('/sw.min.js', subscriptionStatus => {
    console.log('Subscription status: %s', subscriptionStatus);
  });
}

After registering successfully, the device will be able to receive web push notifications, and the browser will handle displaying the messages themselves. The notification includes the title, message, icon, and push image (beta). However, Firefox and Opera do not support push images on any platform.

You can customize how your notification is displayed via the showNotification function.

  1. Title is required. If the push notification does not include a title, the showNotification function will drop the push on the SDK side.
  2. We only support Open URL as the action. The SDK will ignore other actions.

For more information on sending a web push from Leanplum, see how to Send a web push notification.

Suggest Edits

App inbox

iOS and Android instructions

 

App Inbox is a standalone messaging channel that doesn't require push certificates and can store messages for long periods of time.

There is no default UI for the inbox, so you can code your inbox to fit your app's branding and goals. Many Leanplum users make their inbox messages lead to a full-screen message when tapped, with a Back button that leads users back to the inbox.

There is no default UI for the inbox, so you can code your inbox to fit your app's branding and goals. Many Leanplum users make their inbox messages lead to a full-screen message when tapped, with a Back button that leads users back to the inbox.

To enable Inbox messaging, you'll need to integrate Leanplum iOS SDK version 1.6.0 or higher (previous versions use Newsfeed) in your app. After that, you can instantiate the LPInbox (iOS) or LeanplumInbox (Android) object by calling:

Leanplum.inbox()
[Leanplum inbox]
Leanplum.getInbox();

Getting data from Leanplum

Messages and Inbox data are retrieved from Leanplum on Leanplum.start(). The start method returns data asynchronously, so you should use the provided callback (onChanged for iOS and InboxChangedCallback for Android), which will be called automatically when updates to the inbox are finished loading from Leanplum.

Here is a simple example of how you can use the callback to update the number of unread messages:

Leanplum.inbox().onChanged({
    unreadCountLabel.text = String(Leanplum.inbox().unreadCount())
})
[[Leanplum inbox] onChanged:^() {
    unreadCountLabel.text = [NSString stringWithFormat:@"%@", @([[Leanplum inbox] unreadCount])];
}];
Leanplum.getInbox().addChangedHandler(new InboxChangedCallback() {
  @Override
  public void inboxChanged() {
    unreadCount.setText(Integer.toString(Leanplum.getInbox().unreadCount()));
  }
});

Because messages are only retrieved on start, a user will not receive a new message until they begin a new session. You can, however, use forceContentUpdate to re-sync with Leanplum mid-session, which will fetch any new App Inbox messages, and automatically invoke callbacks you have registered.

forceContentUpdate will also update all of your variables, user attributes, messages and A/B tests, so depending on how your app is set up to work with Leanplum, it can affect the functionality and UI of your app. For more on forceContentUpdate, including some precautions, see Syncing with Leanplum mid-session.

Inbox message counts

After data is finished loading from Leanplum, you can get the total and unread count of messages using the LPInbox (iOS) or LeanplumInbox (Android) object:

let inbox: LPInbox = Leanplum.inbox()
let count: UInt  = inbox.count()
let unreadCount: UInt = inbox.unreadCount()
LPInbox *inbox = [Leanplum inbox]; // get the shared Inbox object
NSUInteger count = [inbox count];
NSUInteger unreadCount = [inbox unreadCount];
LeanplumInbox inbox = Leanplum.getInbox(); // instantiate new Inbox object
int unread = inbox.unreadCount();
int total = inbox.count();

Inbox messages

After data is finished loading from Leanplum, you can use the following LPInbox (iOS) or LeanplumInbox (Android) methods to get a list of messages.

// Use the LPInbox instance inbox to get messages. You'll get an NSArray of message objects - either all or just the user's unread messages.
let allMessages: [LPInboxMessage] = inbox.allMessages() as! [LPInboxMessage]
let unreadMessages: [LPInboxMessage] = inbox.unreadMessages() as! [LPInboxMessage]
// Use the LPInbox instance inbox to get messages. You'll get an NSArray of message objects - either all or just the user's unread messages.
NSArray *allMessages = [inbox allMessages];
NSArray *unreadMessages = [inbox unreadMessages];
//This method currently returns a list of NewsfeedMessage objects, which you'll need to cast to the new InboxMessage objects.
List all = inbox.allMessages();
List<LeanplumInboxMessage> messages = (List<LeanplumInboxMessage>) all;
// Do stuff with messages.

Alternatively, you could use messagesIds to get an NSArray or list of all the message IDs, then loop through the returned items and call messageForId with each messageId to fetch each message:

// Use the LPInbox instance inbox to get message Ids.
let messageIds = inbox.messagesIds()
for messageId in messageIds! {
    let message: LPInboxMessage = inbox.message(forId: messageId as! String)
    // Do stuff with message.
}
// Use the LPInbox instance inbox to get message Ids.
NSArray *messageIds = [inbox messagesIds];
for(int i = 0; i < [messageIds count]; i++){
  LPInboxMessage *message = [inbox messageForId: messageIds[i]];
  // Do stuff with message.
}
LeanplumInbox inbox = Leanplum.getInbox(); // instantiate new Inbox object
List<String> messagesIds = inbox.messagesIds(); // get all message IDs
for (String messageId : messagesIds) {
    LeanplumInboxMessage message = inbox.messageForId(messageId);
    // Do stuff with the message.
}

Message attributes

Once you have the Message object, you can access its title, subtitle, and deliveryTimestamp for display.

let message: LPInboxMessage = Leanplum.inbox().message(forId: messageId)
let title: String = message.title()
let subtitle: String = message.subtitle()
let timestamp: Date = message.deliveryTimestamp()
LPInboxMessage *message = [[Leanplum inbox] messageForId: messageId];
NSString *title = [message title];
NSString *subtitle = [message subtitle];
NSDate *timestamp = [message deliveryTimestamp];
LeanplumInboxMessage message = inbox.messageForId(messageId);
String title = message.getTitle();
String subtitle = message.getSubtitle();
Date timestamp = message.getDeliveryTimestamp();

You can also easily test if an inbox message is read:

if(message.isRead()){
  // Do something if the message has been read.
}
if([message isRead]){
  // Do something if the message has been read.
}
if (message.isRead()) {
  // Do something if the message has been read.
}

Message image

We also support sending an image with Inbox messages, although the feature is currently in beta (contact your Customer Success Manager for details on getting access to this feature).

If you haven't disabled automatic image downloads (image prefetching), you can get the image path on the device:

let image: UIImage = UIImage.init(contentsOfFile: message.imageFilePath())
UIImage *image = [UIImage imageWithContentsOfFile:[message imageFilePath]];
String imageFilePath = message.getImageFilePath();
Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);

If you want to disable automatic image downloads on sync (image prefetching), you can do so with the LPInbox method disableImagePrefetching before calling start.

Leanplum.inbox().disableImagePrefetching()
Leanplum.start()
[[Leanplum inbox] disableImagePrefetching];
[Leanplum start];
LeanplumInbox.disableImagePrefetching();
Leanplum.start();

If you do so, you'll need to get the image URL for each message. For iOS, use LPInboxMessage method imageURL. For Android, use LeanplumInboxMessage method getImageUrl. Then download the files yourself later, or use a third-party solution to manage this for you.

If prefetch is enabled or the image has already been downloaded, imageURL(iOS) or getImageUrl(Android) will return the URI to the file on the device.

// Get the Image URL for a single LPInboxMessage.
let url: URL = message.imageURL()
// Use the URL to download the image.
// Get the Image URL for a single LPInboxMessage.
NSURL *url = [message imageURL];
// Use the URL to download the image.

Handling user interactions

After a user reads the message, you need to explicitly set the inbox message as read. You'll also need to remove the message if the user deletes it.

//Mark message as read.
message.read()

//Delete inbox message.
message.remove()
//Mark message as read.
[message read];

//Delete inbox message.
[message remove];
//Mark message as read.
message.read();

//Delete inbox message.
message.remove();

Implementing Inbox in your app (iOS only)

A natural UIView for App Inbox is UITableView because table cells have title, subtitle and image properties.

You can see our example implementation of App Inbox in a TableView in Objective C and in Swift.

Be sure to use onChanged to handle asynchronous changes from Leanplum.

Updating from newsfeed

In previous versions of our SDK (iOS SDK >= 1.3.8 < 1.6.0, Android SDK >= 1.2.17 < 2.1.0), App Inbox is called Newsfeed. We renamed the classes (and added a bit more functionality to the new classes) in iOS SDK 1.6.0 and Android 2.1.0.

Since the new classes have the same methods as the previous Newsfeed and NewsfeedMessage classes, actions like getting messages, getting message counts, marking messages as read, removing messages, etc. can be done as before using the same methods on the new classes.

iOS classes

Newsfeed is now LPInbox and NewsfeedMessage is now LPInboxMessage.

To update your code, you simply need to instantiate the Inbox with the new class and update your object types.

Android classes

Newsfeed is now LeanplumInbox and NewsfeedMessage is now LeanplumInboxMessage.

To update your code, you simply need to instantiate the Inbox with the new class and update your object types. For handling updates, you also need to switch to the new addChangedHandler method with an InboxChangedCallback for callbacks (these replace addNewsfeedChangedHandler and NewsfeedChangedCallback).

Suggest Edits

Geofencing and location-based messaging

Using location tracking with Leanplum

 

You can set up geofence and iBeacon regions as criteria to trigger in-app messages and push notifications, right from the dashboard.

To enable this functionality in your app, follow the setup instructions below:

iOS location services

Setting up iBeacons and location services

Android location services

Setting up location services

How it works

  • By default, Leanplum uses IP-based geolocation for all users. The Leanplum SDK also captures GPS/cell-based geolocation from the user's device when available.

  • GPS/cell-based information is always trusted more — when available, we use the latitude/longitude coordinates from the device and use reverse-geocoding to determine the name of the Country, Region, and City.

  • Geolocation is gathered only on app start or resume, so a user's location is based on their most recent session.

  • We provide methods to disable automatic collection of GPS/cell-based geolocation (not IP), as well as a method to set user location manually, which allows you to truncate the lat/long to a custom number of decimal points, ultimately limiting the precision of geolocation and protecting user privacy. You could, for example, truncate to two decimal places, blurring the accuracy to about 1 kilometer. See our iOS and Android location docs for more on these methods.

If you set up a message or campaign with a geofence region that has a radius smaller than 20km, we only include users with CELL or GPS Location accuracy. (Because this kind of campaign is very location-specific, we require a high degree of confidence to run it.) If the geofence radius is 20km or larger, we will also include users with IP Location accuracy.

Suggest Edits

iOS location services

Setting up geolocation regions and location-based messaging in Leanplum

 

Set up location services in Leanplum

To set up location services for iOS, you'll have to add our location framework to your Podfile, or as an additional linked framework:

pod 'Leanplum-iOS-Location'
pod 'Leanplum-iOS-LocationAndBeacons'

If you need iBeacons as well, include our Location and Beacons framework instead.

If you did a manual install, add CoreLocation to Build Phases -> Link Binary With Libraries.

Geolocation is only available on iOS SDK 1.4+.

Get permission from users

On iOS, your app must get permission from a user to access their location while using your app. Our SDK automatically asks a user for permission on your behalf. You simply need to import the Location library into your AppDelegate, and add NSLocationWhenInUseUsageDescription to your info.plist file.

import LeanplumLocation
#import <LeanplumLocation/LPLocationManager.h>

You can disable the automatic iOS prompt by setting the authorizeAutomatically property of LPLocationManager to false before calling start.

LPLocationManager.shared().authorizeAutomatically = false;
Leanplum.start()
[LPLocationManager sharedManager].authorizeAutomatically = NO;
[Leanplum start];

If you've disabled automatic authorization, you can request permission using the authorize method. Optionally, you can check if the user has already given permission with needsAuthorization.

if(LPLocationManager.shared().needsAuthorization) {
  LPLocationManager.shared().authorize()
}
LPLocationManager * LPLocation = [[LPLocationManager alloc] init];
if(LPLocation.needsAuthorization){
  [LPLocation authorize];
}

iOS will only allow you to request access to a user's location once. After that, the user must navigate to the privacy settings for your app in Settings.

Disabling location collection

If you do not want to send GPS/Cell location to Leanplum, then do not include either of the location frameworks above. Alternatively, you can include the frameworks and call disableLocationCollection before start.

Leanplum.disableLocationCollection()
[Leanplum disableLocationCollection];

Manually set user location (iOS SDK 1.4.3+)

Our SDK now allows you to set user location by calling setDeviceLocationWithLatitude after start. You should call disableLocationCollection before setting the user location.

Leanplum.setDeviceLocationWithLatitude(40.748817, longitude: -73.985428)

Set up location-based messaging

To trigger messages and push notifications based on geofence and iBeacon regions, you'll have to follow the setup instructions above, then add a few keys in your info.plist file:

  1. Add the key NSLocationWhenInUseUsageDescription: This text will appear to the user when prompting for permissions to enable location monitoring in the foreground on iOS 8+. (Required for in-app messages)
  2. Add the key NSLocationAlwaysUsageDescription: This text will appear to the user when prompting for permissions to enable location monitoring in the background on iOS 8+. (Required for push notifications)
  3. Add the key NSLocationUsageDescription: This text will appear to the user when prompting for permissions to enable location monitoring in the foreground or background on iOS 7. (Optional for in-app messaging and push notifications)
  4. Add the key Required background modes if it does not already exist. Within it, add a background mode App registers for location updates. (Required for push notifications)

iOS limits the number of locations that an app can save to 20, however, our SDK manages this for you by only storing the nearest 20 locations to each user's device at any given time. This way, you can have more than 20 locations saved in Leanplum, but your users will only have the 20 most relevant to them (i.e. the closest).

Region monitoring is available in iOS 7 and higher.

Suggest Edits

Android location services

Setting up geolocation regions and location-based messaging in Leanplum

 

In Android, our SDK (v1.3+) automatically tracks GPS/cell-based location if available to your app.

Disable location collection

If you do not want to send GPS/Cell location to Leanplum, you can call disableLocationCollection beforestart.

Leanplum.disableLocationCollection();

Manually set user location (Android SDK 2.0.0)

Our SDK allows you to set user location by calling setDeviceLocation with two arguments (see below) after calling start. You should call disableLocationCollection before setting the location.

Argument
Type
Description

location

android.location.Location

The location object representing the user's current location.

type

LeanplumLocationAccuracyType

The type of geolocation. Either CELL (default) or GPS (more precise).

setDeviceLocation(location, type);

Set up location-based messaging

To use geofence regions to trigger messages and push notifications in your app, you must add a few keys in your AndroidManifest.xml file:

  1. Add the permission <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> (Required for geofencing)
  2. Link the Google Play services library to your project and add the metadata in the application tag. <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> (Required for geofencing)

Due to a limitation with Android, you can only have 100 regions active for your app at any given time. Leanplum optimizes usage by not monitoring regions for messaging campaigns that don't target particular users.

Suggest Edits

How to integrate external Attribution services (App setup)

 

Integration

Leanplum integrates with many third-party attribution providers. The providers send Leanplum a postback that contains all of the publisher information, which in turn allows you to view the marketing channels in Leanplum, as well as target by them for A/B tests or marketing campaigns.

Before you turn the integration on with your specific partner, you need to confirm that your Leanplum integration is using the same device ID as the third-party you're hoping to integrate with. This is important because Leanplum matches the user install with the third-party postback using the device ID, so if they do not match Leanplum cannot report the data.

For example, Adjust sends IDFV device IDs for iOS, so in order for Leanplum to work with Adjust, you'll have to set your Leanplum device ID to IDFV as well. See Device IDs for more detail.

Once the device ID is confirmed, you can contact your third-party provider or log into their portal, and select Leanplum as the partner to send the postback to. You should then provide the App ID and Client Key specific to your Leanplum dashboard. These keys can be found in the Keys & Settings next to the app name in question.

To reach Keys & Settings, go to App Settings either by clicking on your name in the upper right-hand corner, or by clicking Manage Apps in the app selection bar at the top of the dashboard.

Device IDs in Leanplum

In Leanplum, the device IDs are captured automatically, but can vary depending on the version of the OS the device is running. Our SDK sets the device ID to the ANDROID_ID on newer versions (Android 6+), and an MD5 hash of the MAC address on older versions. The same is true for iOS: new versions (iOS 6+) use identifierForVendor while older versions use a hash of the MAC address.

You can, however, choose to set the device ID mode or the device ID yourself. See Device IDs for more detail.

Suggest Edits

API Introduction

Welcome! See what you can do with the Leanplum API

 

Leanplum is designed to integrate with your app using our SDKs. If you need to supplement our SDKs with information from your backend systems, you can use our API. The Leanplum API is only available to customers on full-service accounts. We recommend you contact your customer success manager to discuss your API integration needs, so we can help review your plan and share some best practices.

Check out the sample uses of our API on Github.

Tracking analytics data

Leanplum organizes its data within sessions. A session is one use of an application by a user. To start a session, use the start API method. Sessions may be paused and resumed as users exit and re-enter the app, using pauseSession and resumeSession.

Sessions also include user activity, such as events (things the user does), and states (parts of the app the user is in). Send events and states using track and advance. User attributes may change within a session using setUserAttributes. Sessions time out after 2 hours of inactivity, or 30 minutes after being paused. To keep a session alive, use heartbeat.

Some things can happen outside of sessions as well. For example, a user may receive a notification or a friend request while they're not using the app. You can use track (with disposition=passive) and setUserAttributes outside of sessions.

Updating user information

Leanplum stores many things in a user's profile, including user attributes and behavioral data, such as the lifetime occurrences of a particular event. You can update both of these with setUserAttributes. To retrieve a user's profile, use exportUser.

Sending messages

Leanplum allows you to create messages that are triggered based on user activity, such as when an event fires or a user attribute changes. But in some cases, you may need to trigger messages based on information available on your own server. Use the sendMessage API to send a push notification, newsfeed message, or other types of messages to a user.

The Leanplum SDK will automatically collect push tokens from your users, but if you need to import older push tokens (from users before Leanplum), you can set them in setDeviceAttributes.

Accessing content

There are APIs for receiving the user's variables and files set in the Leanplum dashboard in the Variables and A/B Testing tabs. Whenever a request executes the start method, the list of variables is returned. You can also get the user's variables without starting a new session using getVars. To access the file referenced by the value of a file variable, use downloadFile.

Attribution

Use setTrafficSourceInfo to send attribution data for a user. You can also use setUserAttributes.

Data export

You can export raw user activity data using exportData, export lists of users that match certain criteria using exportUsers, or export analytics reports using exportReport. You can also add postbacks to stream data to another location when those events occur using addPostback.

Getting info about content in Leanplum

You may need to retrieve information about A/B tests or messages created in the Leanplum dashboard. To retrieve information about A/B tests, use getAbTests, getAbTest , or getVariant. To retrieve information about messages, use getMessage or getMessages.

Suggest Edits

Making requests

 

All API requests must be made to https://www.leanplum.com/api. The API is very flexible and supports GET and POST request formats. Our docs, generally, use POST examples for methods that might update/change Leanplum data (e.g. start or setUserAttributes), but both GET and POST request methods are acceptable.

Request formats

GET

The top-level arguments are sent as GET parameters in the request. As part of the HTTP specification, a URL must be at most 2,083 characters, so it's best for small API requests. All characters in the URL should be URL encoded.

Example:

https://www.leanplum.com/api?appId=APP_ID&clientKey=CLIENT_KEY&apiVersion=1.0.6&userId=USER_ID&action=setUserAttributes&userAttributes={"Interests":["Technology","Music"]}

Properly encoded this is:

https://www.leanplum.com/api?appId=APP_ID&clientKey=CLIENT_KEY&apiVersion=1.0.6&userId=USER_ID&action=setUserAttributes&userAttributes=%7B%27Interests%27%3A+%5B%27Technology%27%2C+%27Music%27%5D%7D

POST

The top-level arguments can be either in the URL or in the request body. Generally, our docs show the action argument set in the URL for POST requests, but this is not necessary; all arguments can be set in the POST body with the request sent to https://www.leanplum.com/api. Alternatively, more (even all) arguments can be placed in the URL. However, all characters in the URL should be URL encoded.

The Content-Type of the POST request must be JSON or multipart form data.

Example of a POST request with JSON:

POST https://www.leanplum.com/api?action=setUserAttributes

Content-Type: application/json
{
  "appId": "APP_ID",
  "clientKey": "CLIENT_KEY",
  "apiVersion": "1.0.6",
  "userId": "USER_ID",
  "userAttributes": {
    "Interests": [
      "Technology",
      "Music"
    ]
  }
}

Multiple actions can be batched together. It's highly recommended to batch API actions, especially for the same user. Do not make multiple concurrent API requests for the same user. See Batching requests for more.

Suggest Edits

Authentication

 

Client keys

Every Leanplum app you create will have multiple API keys (visible in App Settings > Keys & Settings). Set the clientKey parameter in the API request to the correct key for the associated API methods:

Production

track sessions, states, set user or device attributes, etc.

Development

import CSV data, delete users, set variables, etc.

Data Export

export user data, messaging and a/b test reports, etc.

Content Read-only

get message and a/b test information, etc.

The correct key for each API method is also listed in each method's description.

 

You should retry if and only if you receive an HTTP 5xx (internal server) error, and use exponential backoff, up to a maximum amount of retries. As a simple example, you could:

  1. retry after 2 +/- random(0, 1) seconds, then
  2. retry after 4 +/- random(0, 2) seconds, then
  3. retry after 8 +/- random(0, 4) seconds
  4. etc.
Suggest Edits

Selecting a user

 

For many API methods, you can pass a userId, a deviceId, or both userId and deviceId. Here's how these will affect the action, or execution of the API method:

  • userId only: The API action pertains to the user and not a particular device. In most cases, Leanplum will not associate any device with this action, which may cause device information to be excluded from analytics. In some cases, Leanplum may be able to infer the device. When using the sendMessage method for a push notification, passing a userId only would send a push notification to all devices associated with that user.
  • deviceId only: The API action pertains to a particular device without an associated user ID, for example, a logged out user. The user ID may be inferred by the API.
  • userId and deviceId: The API action pertains to a particular device associated to a particular user ID.

In many cases, you would only pass a userId and not a deviceId, because events coming from the API are not associated with a particular device. Events coming from a device are usually sent via the SDK.

// Example POST requests to 
// https://www.leanplum.com/api?action=sendMessage

// User only - sends message to all devices for that user
{
  "appId": "APP_ID",
  "clientKey": "PROD_KEY",
  "apiVersion": "1.0.6",
  "userId": "hfarnsworth@example.com",
  "messageId": 101001
}

// Device only - sends to a specific device
{
  "appId": "APP_ID",
  "clientKey": "PROD_KEY",
  "apiVersion": "1.0.6",
  "deviceId": "device1",
  "messageId": 101001
}

// User and device - sends to a specific device and user
{
  "appId": "APP_ID",
  "clientKey": "PROD_KEY",
  "apiVersion": "1.0.6",
  "userId": "hfarnsworth@example.com",
  "deviceId": "device1",
  "messageId": 101001
}

Additionally, getVars has an additional mode where neither a userId nor deviceId are provided, which will return the default variables that would be seen by a blank user.

Suggest Edits

Responses

 

All responses except for the downloadFile request are in JSON format, and include warning and error objects to indicate problems with your request, if any. The 200 status and success flag only indicate that the request was received, not that the provided API action was successful.

An API action is successful if all of these are true:

  • the response code is 200.
  • the success flag is true.
  • there is no error.message.
  • there is no warning.message.

A successful call will always result in a 200 status with success=true and no error.message or warning.message.

An HTTP response of 200 and a response of success=true do not indicate that the action was successful. You need to verify there are no error or warning messages.

Types of responses you can get:

HTTP 200

  • success=true (no warning or error objects): The request was received and the action taken successfully.
  • success=true and warning.message=“warning message": The request was received successfully but the action was likely skipped. See warning message for details.
  • success=true and error.message=“error message": The request was received successfully but the action was skipped. See error message for details.

HTTP 4xx or 5xx

  • success=false and error.message=“error message": The request was not received successfully. See error message for details.
{ 
  "response": [
    {
      "success": true
    }
  ]
}
{ 
  "response": [
    {
      "success": true,
      "warning": {
        "message": "User not found; request skipped."
      }
    }
  ]
}
{
  "response": [
    {
      "success": true,
      "error": {
        "message": "Error message provided here."
      }
    }
  ]
}
{
  "response": [
    {
      "success": false,
      "error": {
        "message": "Invalid access key"
      }
    }
  ]
}
 

Due to our system architecture, our costs increase for every user profile we need to retrieve in order to process an HTTP request to our API. As such, we bill server-side API calls based on the number of user lookups per HTTP request to our API, and not the number of HTTP requests or API actions. To be clear, for billing purposes, a server-side API call is one unique user lookup initiated by an HTTP request made to the Leanplum API from any source other than the Leanplum SDK.

One HTTP request can include multiple user lookups. multi allows you to batch multiple actions affecting up to 50 unique users in a single request. Therefore, the maximum number of billable API calls (user lookups) per HTTP request is 50, not 1.

We do, however, exempt all deleteUser actions from billing so you're free to clean up your data.

We also optimize how we handle multi requests to prevent duplicate user lookups (reducing both our and your costs). Because we do this, you can reduce the number of billable calls you make to the Leanplum API (while executing the same number of actions) by batching actions for the same user(s).

See Batching requests for more.

The multi action also allows you to import an external file containing a potentially large number of actions. This is billed by breaking the file into API requests that each contains a batch of 50 actions. Each of these API requests is then billed using the above definition.

Suggest Edits

Batching requests with multi

Use a multi call to batch multiple API requests

 

To improve performance and reduce your billable API calls, you should batch multiple API requests that affect the same users as much as possible (see more on Reducing billable requests).

While Leanplum processes a successful multi call, concurrent requests for these users (via the SDK or API) will be queued and completed after the multi batch completes.

Send the request

To batch API actions, make a post request to https://www.leanplum.com/api?action=multi with the following parameters in the request body:

param
description

appId

required
The application ID. To find yours, select your app in the navigation column, and click Edit Apps. Under Keys, click Show.

clientKey

required
The Production key for your Leanplum App.

apiVersion

required
The version of the Leanplum API to use. The current version is 1.0.6.

time

required
The time at which the request was issued (UNIX time). This is used to resolve the time difference between Leanplum and the API caller when computing the times of events.

data

required
A JSON-encoded list of API methods to execute. All methods must be for the same app referred to by the appId parameter. Each data object must include the required arguments for its API action.

Each nested object in the data array is an individual API action, and must include the required parameters for that method. You'll need to reference each nested API method's documentation for info on required parameters and options.

{
  "appId": "YOUR_APP_ID",
  "clientKey": "YOUR_PROD_KEY",
  "apiVersion": "1.0.6",
  "time": 1375295890,
  "data": [
    {
      "action": "start",
      "time": 1375295825,
      "userAttributes": {
        "Gender": "Male",
        "Age": 25
      },
      "userId": "user1"
    },
    {
      "action": "track",
      "time": 1375295830,
      "event": "Level Complete",
      "params": {
        "Level": 1,
        "Score": 100
      },
      "userId": "user1"
    }
  ]
}

Response

Each individual action will also have its own response; some may be successes, some may have warnings, and some may have errors. The index of the response will match the index of the request in the data array. For the example above, if we pass a bad string as the action in the second batched request, we get the following response:

{
  "response": [
    {
      "success": true
    },
    {
      "success": false,
      "error": {
        "message": "Action not found"
      }
    }
  ]
}

The 'multi' call method is limited to 50 users and/or 500 actions in a single call. All calls in a batch with more than this will be ignored and the server will return a 403 status. Each unique user lookup in a request is a billable API call. See billing and costs for more.

Suggest Edits

Reduce billable requests

 

Batching should first be done on a per-user basis, and then across users, with up to 50 users modified in a single multi request. For example, if you want to track an event and setUserAttributes for two users, the total billable calls is entirely dependent on how you setup your multi requests.

DO

Batch by user first. For example:

multi request 1:

  • track (user1)
  • setUserAttributes (user1)

multi request 2:

  • track (user2)
  • setUserAttributes (user2)

Each of these requests requires one user lookup, so the total billable API calls is two (despite executing four actions). In this case, however, you could combine these into a single multi request without using additional API calls:

multi request 1:

  • track (user1)
  • setUserAttributes (user1)
  • track (user2)
  • setUserAttributes (user2)

This single request still only requires two unique user lookups, so the total billable API calls remains two.

AVOID

Batching requests by action instead of by user.

multi request 1:

  • track (user1)
  • track (user2)

multi request 2:

  • setUserAttributes (user1)
  • setUserAttributes(user2)

In this case, each request requires two user lookups. Therefore, there are four billable API calls. Avoid this, as it is not an efficient use of multi.

Suggest Edits

Debugging

 

To debug an API request, set clientKey to your development key and devMode=true, and most importantly be sure to set the userId and/or deviceId to a test user/device. If you use a real user when debugging, Leanplum will convert that user profile to a developer account.

These requests will be visible in the Dashboard Debugger console.

All session and tracking info from these requests will not be tracked as real user data. The matching user/device will be set to a developer account, and all of their activity will be sent to a separate analytics section, Developer Activity.

Do not set devMode=true for any API request that involves a real device or user. Only use it with test devices or developer accounts.

Suggest Edits

API methods

 

See all of our API methods organized by section below. Make sure to use the best practices outlined under Making requests when working with these methods. You can also download our postman collection here:
Run in Postman

Not sure where to start?

See our API introduction for more on using Leanplum's API, or see our API guides for more specific applications.

Suggest Edits

User Behavior

 

Use these API methods when tracking user behavior like event and session data.

Suggest Edits

advance

Advances a user to the next state. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below). The state is the section of the app the user is currently in. States are like events with duration.

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=advance
curl --request POST \
  --url 'https://www.leanplum.com/api?action=advance'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'advance' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=advance")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=advance");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

state
string
required

The name of the state. Set to an empty string to leave the current state but not enter a new one.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

info
string

Any info attached to the state.

params
object

A flat object of parameters as key-value pairs. Each key must be a string, and up to 50 parameters may be set. Example: {'gender':'F','age':21}.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

pauseState

Pauses the current state, but not the session, for a user. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=pauseState
curl --request POST \
  --url 'https://www.leanplum.com/api?action=pauseState'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'pauseState' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=pauseState")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=pauseState");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

resumeState

Resumes the current state for a user. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=resumeState
curl --request POST \
  --url 'https://www.leanplum.com/api?action=resumeState'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'resumeState' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=resumeState")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=resumeState");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

pauseSession

Pauses the current session and state for a user. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=pauseSession
curl --request POST \
  --url 'https://www.leanplum.com/api?action=pauseSession'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'pauseSession' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=pauseSession")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=pauseSession");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

resumeSession

Resumes the current session and state for a user. Use either after pauseSession, or start if the app started in the background. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=resumeSession
curl --request POST \
  --url 'https://www.leanplum.com/api?action=resumeSession'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'resumeSession' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=resumeSession")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=resumeSession");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

heartbeat

Sends a pulse to indicate that the current session is still in progress, so as not to automatically end it. Sessions are automatically timed out after 2 hours of inactivity — or 30 minutes if the session was paused first. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=heartbeat
curl --request POST \
  --url 'https://www.leanplum.com/api?action=heartbeat'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'heartbeat' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=heartbeat")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=heartbeat");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

start

Starts a new session and returns the variables that have changed for the user. If the user/device does not exist, a new user will be created (see the createDisposition option below). This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=start
curl --request POST \
  --url 'https://www.leanplum.com/api?action=start'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'start' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=start")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=start");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateIfNeeded.

appVersion
string

The version of the app used on this device. E.g. 2.0.1.

systemName
string

The name of the OS the current device is running. E.g. iOS.

systemVersion
string

The version number of the OS the current device is running. E.g. 6.0.

browserName
string

The name of the browser the current device is running. E.g. Chrome.

browserVersion
string

The version number of the browser the current device is running. E.g. 17.0.

deviceName
string

A human-readable name representing the device.

deviceModel
string

The model name of the device. E.g. iPad.

iosPushToken
string

The token used for Apple iOS push notifications on this device.

gcmRegistrationId
string

The registration ID used for Google Cloud Messaging push notifications on this device.

webPushSubscription
string

The JSON-encoded subscription used for web push notifications on this device.

userAttributes
object

A map of user attributes as key-value pairs. Each key must be a string. Attributes are saved across sessions. Only supplied attributes will be updated (i.e., if you omit an existing attribute, it will be preserved). Example: {"gender":"F","age":21}.

locale
string

The current locale the user is in. E.g. en_US.

country
string

The country the user is in, specified by ISO 2-letter code. E.g. US for United States. Set to (detect) to detect the country based on the IP address of the user.

region
string

The region (state) the user is in. E.g. ca for California. Set to (detect) to detect the region based on the IP address of the user.

city
string

The city the user is in. E.g. San Francisco. Set to (detect) to detect the city based on the IP address of the user.

location
string

The location (latitude/longitude) of the user. E.g. 37.775,-122.4183. Set to (detect) to detect the location based on the IP address of the user.

locationAccuracyType
string

The type of location that is provided (IP, CELL, or GPS). Default: IP.

timezone
string

The timezone abbreviation for the user. See list of timezone abbreviations.

timezoneOffsetSeconds
integer

The timezone offset from GMT in seconds.

background
boolean

Whether the app started in the background. In this case, the session won't be counted until resumeSession is executed. Default: false.

includeDefaults
boolean

Whether to include default ("defaults in code") values in output. Default: true.

Response

A successful request will return a response array with an object that has a success value set to true, and no error or warning object. It will also include variables, messages and other details relevant to that user.

responsearray

Response object for the API action.

response[].successboolean

Whether the request was received. Verify that the response has neither warning or error objects to confirm the action was taken. See here for more.

response[].messagesobject

In-app messages targeted at this user.

response[].varsobject

Key/value pairs for variables.

response[].vars.varNamestring

The value of the variable varName.

response[].interfaceRulesarray

Custom visual events and UI settings from UI Editor.

response[].variantsarray

List of variants that the user belongs to.

response[].variants[].idnumber

ID of the variant.

response[].regionsobject
response[].interfaceEventsarray

Interface events information.

response[].tokenstring
Suggest Edits

stop

Ends the current session. If the user/device does not exist, the API request is skipped and a warning will be returned. You can modify this behavior with the createDisposition option (see below). This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=stop
curl --request POST \
  --url 'https://www.leanplum.com/api?action=stop'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'stop' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=stop")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=stop");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateNever.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

track

Tracks one occurrence of an event for a user. If the user/device does not exist, a new user will be created (see the createDisposition option below). This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=track
curl --request POST \
  --url 'https://www.leanplum.com/api?action=track'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'track' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=track")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=track");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateIfNeeded.

event
string
required

The name of the event. Use "Purchase" to identify a monetization event, with the event value being the revenue. You can change the default monetization event name in Analytics by going to the metric chooser and clicking the Monetization metric category.

value
float

The event value. For example, for a purchase event, this would be the purchase price.

currencyCode
string

The ISO 4217 currency code associated with value. Leanplum will automatically convert value into your preferred currency, while retaining the original price and currency code as event parameters localCurrency and localPrice. Currency conversion rates are updated every hour.

info
string

Any info attached to the event.

time
float

Option to provide the UNIX timestamp for when the event occurred, which may be different from the current time.

params
object

A flat object of parameters as key-value pairs. Each key must be a string, and up to 50 parameters may be set. Example: {"gender":"F","age":21}.

messageId
integer

The message ID this event is associated with. Set this to track a user's interaction with a message. To track a message Send or a View, set the event argument to an empty string. For other interactions, set the event argument to the type of action (example values include Open, Cancel, Accept). The Leanplum SDK does this automatically, so this should be used for advanced use cases only.

disposition
string

Determines how tracked events affect sessions and user activity. If present, disposition must have one of the following values:

  • active (default): Used for events reflect user activity. Active events should mark the user as active, and should be tracked within a session. (Replaces the deprecated option allowOffline: false.)
  • passive: Used for events that do not correspond to user activity. These events do not need to occur within a session, and do not mark a user as active. For example, sending a user a message would be tracked passively, since it affects a user, but does not represent user activity. (Replaces the deprecated option allowOffline: true.)
  • requireActive: Used for events that must only be tracked within a session. These events are rejected, and return a warning response with ignored: true if the user does not have an active session. Clients should detect the warning by the ignored field, as warning messages may change.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

User Information

 

Use these API methods to update user and device information. You can also block and delete users via the Leanplum API.

Suggest Edits

setUserAttributes

Sets user attributes for the user given by userId and/or deviceId. If the user has an open session, the attributes for the current session will also be updated. Attributes will then propagate on data going forward. User properties not supplied in this method will not be affected. If the user/device does not exist, a new user will be created (see the createDisposition option below).

This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=setUserAttributes
curl --request POST \
  --url 'https://www.leanplum.com/api?action=setUserAttributes'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'setUserAttributes' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=setUserAttributes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=setUserAttributes");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateIfNeeded.

userAttributes
object

A map of user attributes as key-value pairs. Each key must be a string. Attributes are saved across sessions. Only supplied attributes will be updated (i.e., if you omit an existing attribute, it will be preserved). Example: {"gender":"F","age":21}.

userAttributeValuesToAdd
object

A map of values to add to existing user attribute sets. For example, supply {"Interests":"Sports"} to add Sports to the existing set of Interests.

userAttributeValuesToRemove
object

A map of values to remove from existing user attribute sets. For example, supply {"Interests":"Sports"} to remove Sports from the existing set of interests.

userAttributeValuesToIncrement
object

A map of values to increment onto existing user attributes. The existing attribute value and the increment must both be integers or the operation will be skipped. If the existing attribute is not set, its value will be inferred as 0.

For example, supply {"unreadMessages":1} to add 1 to the number of unread messages.

unsubscribeCategoriesToAdd
array of integers

A list of email categories to unsubscribe a user from.

unsubscribeCategoriesToRemove
array of integers

A list of email categories to re-subscribe a user to.

unsubscribeChannelsToAdd
string

A messaging channel (e.g. Email) to unsubscribe the user from. Use this to unsubscribe a user from all marketing email categories.

unsubscribeChannelsToRemove
string

A messaging channel (e.g. Email) to re-subscribe the user to. Use this to re-subscribe a user to all marketing email categories (except any categories they have unsubscribed from).

newUserId
string

If supplied, updates the user of the current session with newUserId. This can have certain effects:

  • Login: If the current user has no user ID and the user given by newUserId already exists, the current and existing user profiles will be merged, and the current profile will be deleted.
  • Register: If there is no current user ID and the user given by newUserId does not exist, the current user will be simply assigned newUserId as its user ID.
  • Switch user: If the current user has a user ID, the current session will be ended and a new session will be started with the user given by newUserId. A user with newUserId will be created if one does not already exist.
events
object

A map of event data to update for the current user. The keys are the event names, each should have a nested object with at least one of the following attributes:

  • count: New lifetime count of this event for the current user.
  • countIncrement: Amount to increment the lifetime count of this event.
  • value: New lifetime value of this event for the current user.
  • valueIncrement: Amount to increment the lifetime value of this event.
  • firstTime: Time that this event first occurred, in seconds since midnight UTC on January 1, 1970.
  • lastTime: Time that this event last occurred, in seconds since midnight UTC on January 1, 1970.

Example: Here's how to set the lifetime count for an event called "myEvent":

{ "myEvent": { count: 1 } }

states
object

A map of state data to update for the current user. The keys are the state names, and each should have a nested object with at least one of the following attributes:

  • count: New lifetime count of this state for the current user.
  • countIncrement: Amount to increment the lifetime count of this state.
  • firstTime: Time that this state first occurred, in seconds since midnight UTC on January 1, 1970.
  • lastTime: Time that this state last occurred, in seconds since midnight UTC on January 1, 1970.

Example: Here's how to set the lifetime count for a state called "splashPage":

{ "splashPage": { count: 23 } }

created
float

The time at which the user was created, in seconds since midnight UTC on January 1, 1970.

lastActive
float

The time at which the user was last active, in seconds since midnight UTC on January 1, 1970.

totalSessions
integer

The total number of sessions that a user has had in their lifetime.

timeSpentInApp
float

The total number of seconds spent in the app in the user's lifetime.

locale
string

The current locale the user is in. E.g. en_US.

country
string

The country the user is in, specified by ISO 2-letter code. E.g. US for United States. Set to (detect) to detect the country based on the IP address of the user.

region
string

The region (state) the user is in. E.g. ca for California. Set to (detect) to detect the region based on the IP address of the user.

city
string

The city the user is in. E.g. San Francisco. Set to (detect) to detect the city based on the IP address of the user.

location
string

The location (latitude/longitude) of the user. E.g. 37.775,-122.4183. Set to (detect) to detect the location based on the IP address of the user.

locationAccuracyType
string

The type of location that is provided (IP, CELL, or GPS). Default: IP.

timezone
string

The timezone abbreviation for the user. See list of timezone abbreviations.

timezoneOffsetSeconds
integer

The timezone offset from GMT in seconds.

devices
array of objects

A list of device objects associated with this user.

deviceId
appVersion
systemName
systemVersion
browserName
browserVersion
deviceName
deviceModel
iosPushToken
gcmRegistrationId
webPushSubscription
devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

setDeviceAttributes

Sets attributes for the current device. If the device is shared between multiple users, pass a userId with the deviceId to update the device for each user. (Passing just the deviceId will only update it once). If the device already exists, the attributes will be updated. If the device and user do not exist, a new user will be created along with this device (see the createDisposition option below). See selecting a user for more.

This method requires your production API clientKey.

At least one of the following must be set to create/update a device: appVersion, systemName, systemVersion, browserName, browserVersion, deviceName, deviceModel, iosPushToken, gcmRegistrationId, or webPushSubscription.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=setDeviceAttributes
curl --request POST \
  --url 'https://www.leanplum.com/api?action=setDeviceAttributes'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'setDeviceAttributes' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=setDeviceAttributes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=setDeviceAttributes");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

deviceId
string
required

The unique ID for the device.

userId
string

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateIfNeeded.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

appVersion
string

The version of the app used on this device. E.g. 2.0.1.

systemName
string

The name of the OS the current device is running. E.g. iOS.

systemVersion
string

The version number of the OS the current device is running. E.g. 6.0.

browserName
string

The name of the browser the current device is running. E.g. Chrome.

browserVersion
string

The version number of the browser the current device is running. E.g. 17.0.

deviceName
string

A human-readable name representing the device.

deviceModel
string

The model name of the device. E.g. iPad.

iosPushToken
string

The token used for Apple iOS push notifications on this device.

gcmRegistrationId
string

The registration ID used for Google Cloud Messaging push notifications on this device.

webPushSubscription
string

The JSON-encoded subscription used for web push notifications on this device.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

setTrafficSourceInfo

Sets traffic source information for the current session of a user. If the user/device does not exist, a new user will be created (see the createDisposition option below). This method requires your production API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=setTrafficSourceInfo
curl --request POST \
  --url 'https://www.leanplum.com/api?action=setTrafficSourceInfo'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'setTrafficSourceInfo' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=setTrafficSourceInfo")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=setTrafficSourceInfo");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Production key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The current user ID. You can set this to whatever your company uses for user IDs. Leave it blank to use the device ID. For more info, see selecting a user.

deviceId
string

A unique ID for the device targeted by the request. You must provide a deviceId and/or a userId. See selecting a user.

createDisposition
string

The policy that determines whether users are created by the API. Possible values:

  • CreateIfNeeded creates a user with the given IDs if one does not already exist.
  • CreateNever requires that the user already exists, otherwise the API action is skipped and a warning will be returned.

The default value for this method is CreateIfNeeded.

trafficSource
object

An object of traffic source parameters.

 
trafficSource.publisherId
string
required

ID of the publisher used to refer the user. Example: 1001.

trafficSource.publisherName
string
required

Name of the publisher used to refer the user. Example: Big Fish Games.

trafficSource.publisherSubPublisher
string
required

Name of the developer used to refer the user. Example: GameDeveloper1.

trafficSource.publisherSubSite
string
required

Name of the app or website used to refer the user. Example: MyLittleApp.

trafficSource.publisherSubCampaign
string
required

Name of the campaign used to refer the user. Example: US CPI.

trafficSource.publisherSubAdGroup
string
required

Name of the ad group used to refer the user. Example: banners.

trafficSource.publisherSubAd
string
required

Name of the ad used to refer the user. Example: blue1.

time
float

The time at which the session started, in seconds since midnight UTC on January 1, 1970. This should be no more than 2 minutes after the session started. If not provided, uses the current time.

devMode
boolean

Whether the user is in Development Mode, i.e. the user associated with the request is a developer and not a user. This is important for reporting purposes. Default: false.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

registerDevice

Registers the current device for development. This method requires your development API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=registerDevice
curl --request POST \
  --url 'https://www.leanplum.com/api?action=registerDevice'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'registerDevice' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=registerDevice")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=registerDevice");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Development key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

deviceId
string
required

A unique ID for the device to be registered by the request.

email
string
required

The email address corresponding to the Leanplum user account to which the device belongs.

Response

Returns the status of the request and device registration.

response[].successboolean

Whether the request was received. Verify that the response has neither warning or error objects to confirm the action was taken. See here for more.

response[].registeredboolean

Whether the device was just registered. If the device has already been registered, this will be false.

Suggest Edits

deleteUser

Permanently removes all of a user’s attribute information from our database. To erase a user’s data entirely — including attribute, analytics, and sessions data — set the fullErasure flag to true. You can bulk delete users with multi (import mode) or by contacting your CSM. deleteUser calls are exempt from API billing.

This method requires your development API clientKey.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=deleteUser
curl --request POST \
  --url 'https://www.leanplum.com/api?action=deleteUser'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'deleteUser' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=deleteUser")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=deleteUser");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.

clientKey
string
required

The Development key for your Leanplum App.

apiVersion
string
required

The version of the Leanplum API to use. The current version is 1.0.6.

userId
string
required

The user ID to delete. Required unless using deviceId.

deviceId
string

Required if no userId. The deviceId to delete. Only use this if there is no userId set. Note that deviceId will only delete data from devices where a user has never logged-in. If a logged-in user has been on the device, you must call the deleteUser API with the userId.

fullErasure
boolean

Deletes all session and analytics data for the selected user. This may take up to 15 days to process fully. Defaults to false — should be set to true for GDPR-related deletion requests.

Response

The default response for most API actions.

response[]array

The response array.

response[].errorobject

Contains a error message for the API action, if any.

response[].error.messagestring
response[].warningobject

Contains a warning message for the API action, if any.

response[].warning.messagestring
Suggest Edits

block

Stops all data collection for a user going forward. block also erases any data previously associated with that user, including all of their attribute and analytics data. The block will take effect as soon as the “success” response is returned. It may take up to 15 days to delete the user’s data completely.

Note that the block call deletes a user's past data, but does not delete the user entirely. This allows you to use the unblock call to resume data collection.

 

Query Auth

 Authentication is required for this endpoint.
posthttps://www.leanplum.com/api?action=block
curl --request POST \
  --url 'https://www.leanplum.com/api?action=block'
var request = require("request");

var options = { method: 'POST',
  url: 'https://www.leanplum.com/api',
  qs: { action: 'block' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
require 'uri'
require 'net/http'

url = URI("https://www.leanplum.com/api?action=block")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)

response = http.request(request)
puts response.read_body
var data = JSON.stringify(false);

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://www.leanplum.com/api?action=block");

xhr.send(data);
import requests

url = "https://www.leanplum.com/api"

response = requests.request("POST", url)

print(response.text)
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

appId
string
required

The application ID. To find yours, select your app in the navigation column, and click Manage Apps. Then click Keys & Settings.