App inbox

Instructions for setting up a platform-agnostic messaging channel

App Inbox is a standalone messaging channel allowing you to send messages to users in your app, similar to an email inbox. This doesn't require push certificates and you can store messages for long periods of time.

With the Leanplum App Inbox, there is no default UI. This means with a few lines of code, you can connect Leanplum with your inbox and fit your app's branding and goals. Many Leanplum users have their inbox messages lead to a full-screen message when tapped, with a Back button that leads users back to the inbox.

👍

SDK Version

For best performance, we always recommend using the latest version of our SDKs. To find those visit our page at SDK Versions

App Inbox SDK Calls

The below examples are the calls you can implement in the Leanplum SDK to leverage the App Inbox channel.

Leanplum Inbox

To get an instance to the App Inbox object, you will need to use the Leanplum.inbox() call which you can see below:

Leanplum.inbox()
[Leanplum inbox]
Leanplum.getInbox();
var inbox = Leanplum.inbox()
LeanplumInbox.inbox().then(inbox=>{
      //...
}).catch(error=>{
      //...
})
Leanplum.Inbox

Get data from Leanplum

Messages and Inbox data are retrieved initially from Leanplum on the Leanplum.start() call. The start method returns data asynchronously, so you will need to use the provided callback (onChanged for iOS and React Native, 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().onInboxChanged {
    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()));
  }
});
Leanplum.inbox().onChanged(function() {
  var unreadCount = String(Leanplum.inbox().unreadCount());
  document.getElementById('unreadCountLabel').innerText = unreadCount;
});
LeanplumInbox.inbox().onChanged(CALLBACK_FUNCTION)
Leanplum.Inbox.InboxChanged

Downloading new messages mid-session

Starting in Android SDK 5.5.0, iOS SDK 3.1.1, and Unity 3.1.0 versions +, you can now download new messages without the need to call forceContentUpdate method. The forceContentUpdate is typically is required to sync a client mid-session with Leanplum. Learn about mid-session syncing here.

Use the below source code in your App Inbox to sync and download those messages.

Leanplum.inbox().downloadMessages()

//Download messages.
//All registered InboxSyncedCallback will be invoked including the parameter callback.
Leanplum.inbox().downloadMessages({ success in
    //
})
[[Leanplum inbox] downloadMessages];

//Download messages.
//All registered InboxSyncedCallback will be invoked including the parameter callback.
[[Leanplum inbox] downloadMessages:^(BOOL success) {
        //
}];
//Download messages. All registered InboxSyncedCallback will be invoked.
Leanplum.getInbox().downloadMessages();

//Download messages.
//All registered InboxSyncedCallback will be invoked including the parameter callback.
Leanplum.getInbox().downloadMessages(callback);
Leanplum.Inbox.DownloadMessages((success) =>
{
   Debug.Log($"Download Inbox Messages Finished with Status: {success}");
});

Get Inbox message counts

After data is finished loading from Leanplum in your App Inbox, you can fetch the total and unread counts of messages. You can do this by using the LPInbox method (iOS) or the 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();
var inbox = Leanplum.inbox()
var count = inbox.count()
var unreadCount = inbox.unreadCount()
let inbox: LPInbox = Leanplum.inbox()
let count: UInt  = inbox.count()
let unreadCount: UInt = inbox.unreadCount()
var messages = Leanplum.Inbox.Messages;
int unread = Leanplum.Inbox.UnreadCount;
int msgCount = Leanplum.Inbox.Count;

Get a list of Inbox messages

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

// Use the LeanplumInbox instance to get messages (LeanplumInbox.Message). You'll get an NSArray of message objects - either all or just the user's unread messages.
let allMessages: [LeanplumInbox.Message] = inbox.allMessages
let unreadMessages: [LeanplumInbox.Message] = inbox.unreadMessages
// 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.
var allMessages = inbox.allMessages();
var unreadMessages = inbox.unreadMessages();
const message = await LeanplumInbox.message(MESSAGE_ID);
const title = message.title;
const subtitle = message.subtitle;
const timestamp = message.timestamp;

if (message.isRead) {
  // Do something if the message has been read.
}
var messages = Leanplum.Inbox.Messages;
var unread = Leanplum.Inbox.UnreadMessages;

Alternatively, you could use messagesIds to get an Array or List of all the message IDs of your messages. Once you have fetch those (as below), you can loop through the returned items and call messageForId with each messageId to fetch each message:

// Use the LeanplumInbox instance to get message Ids.
let messageIds = inbox.messagesIds
for messageId in messageIds {
    let message: LeanplumInbox.Message = inbox.message(id: messageId)
    // 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.
}
var messageIds = inbox.messagesIds()
messageIds.forEach(function(messageId) {
    var message = inbox.message(messageId)
    // Do stuff with message.
})
message.Id

Accessing Message attributes

Once you have the Message object, you can access its title, subtitle, and deliveryTimestamp for display as shown in the example below.

let message: LeanplumInbox.Message = Leanplum.inbox().message(id: 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();
var message = Leanplum.inbox().message(messageId)
var title = message.title()
var subtitle = message.subtitle()
var timestamp = message.timestamp()
var messages = Leanplum.Inbox.Messages;
foreach (var message in messages)
{
   var title = message.Title;
   var subtitle = message.Subtitle;
}

You can also easily access and check if an inbox message was read using the below:

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.
}
if (message.isRead()) {
  // Do something if the message has been read.
}
message.IsRead

Use Message image

Inbox messages can be customized with an image.

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

let image = UIImage(contentsOfFile: message.imageFilePath ?? "")
UIImage *image = [UIImage imageWithContentsOfFile:[message imageFilePath]];
String imageFilePath = message.getImageFilePath();
Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
var message = Leanplum.inbox().message(MESSAGE_ID);

var url = message.imageUrl();
const message = await LeanplumInbox.message(MESSAGE_ID);
const imageFilePath = message.imageFilePath;

const url = message.imageURL;

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 (imageURL value for Swift). 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.
var url = message.imageUrl()

Handling user interactions

After a user reads the message, you need to explicitly set the inbox message as read. You need to make sure the message is marked as read every time the user interacts with it, since this also triggers the Open Action for that message. You'll also need to remove the message if the user deletes it.
You can also only read the message without triggering the Open Action, using markAsRead method of the inbox message. Note that this method is available in Android 5.4.2 and iOS 3.1.0.

//Mark message as read and triggers the Open Action.
message.read()

//Mark message as read (without invoking its Open Action).
message.markAsRead()

//Delete inbox message.
message.remove()
//Mark message as read and triggers the Open Action.
[message read];

//Mark message as read (without invoking its Open Action).
[message markAsRead];
  
//Delete inbox message.
[message remove];
//Mark message as read and triggers the Open Action.
message.read();

//Mark message as read (without invoking its Open Action).
message.markAsRead();

//Delete inbox message.
message.remove();
var inbox = Leanplum.inbox();

// Mark message as read and trigger Open Action
inbox.read(MESSAGE_ID);

// Mark message as read without triggering Open Action
inbox.markAsRead(MESSAGE_ID);

// Delete inbox message
LeanplumInbox.remove(MESSAGE_ID)
const message = await LeanplumInbox.message(MESSAGE_ID);

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

//Delete inbox message.
LeanplumInbox.remove(MESSAGE_ID)

Example App Inbox implementation in iOS

When implementing an App Inbox experience, a natural UIView for App Inbox is UITableView because table cells have title, subtitle and image properties.

For an example implementation of App Inbox with a TableView in Objective C and in Swift.

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