In-App Messaging

In-App Messages are great for creating unobtrusive calls to action, notifying people of new content in the News Feed and driving them toward it or communicating with users who have push turned off. They are also effective for other content that isn’t time-sensitive enough to warrant a push notification, or permanent enough to warrant a News Feed item. You can find a detailed explanation of in-app message behavior in Braze Academy.

Integration

Step 1: Braze In-App Message Manager Registration

In-App Message display is managed by the AppboyInAppMessageManager class. Every activity in your app must be registered with the AppboyInAppMessageManager to allow it to add in-app message views to the view hierarchy. There are two ways to accomplish this:

The Activity Lifecycle Callback Integration handles in-app message registration automatically, no extra integration is required. This is the recommended integration for handling in-app message registration.

Manual In-App Message Registration

A manual in-app message registration requires 3 steps.

If you did the activity lifecycle integration, then you should not do a manual in-app message integration.

1
AppboyInAppMessageManager.getInstance().ensureSubscribedToInAppMessageEvents(context);
1
2
3
4
5
6
7
@Override
public void onResume() {
  super.onResume();
  // Registers the AppboyInAppMessageManager for the current Activity. This Activity will now listen for
  // in-app messages from Braze.
  AppboyInAppMessageManager.getInstance().registerInAppMessageManager(activity);
}
1
2
3
4
5
6
@Override
public void onPause() {
  super.onPause();
  // Unregisters the AppboyInAppMessageManager for the current Activity.
  AppboyInAppMessageManager.getInstance().unregisterInAppMessageManager(activity);
}

In-App Message Types

Braze offers several default in-app message types, each customizable with messages, images, Font Awesome icons, click actions, analytics, editable styling and color schemes. The currently available types are Slideup, Modal, Full, and HTML Full. It is also possible to define your own custom in-app message view.

All in-app messages implement the IInAppMessage interface, which defines basic behavior and traits for all in-app messages. InAppMessageBase is an abstract class that implements IInAppMessage and provides the foundational in-app message implementation. All in-app message classes are subclasses of InAppMessageBase.

In addition, there is a subinterface of IInAppMessage called IInAppMessageImmersive, which adds click action and analytics enabled buttons, as well as header text and a close button. InAppMessageImmersiveBase is an abstract class that implements IInAppMessageImmersive and provides the foundational immersive in-app message implementation. Modal and Full in-app messages are subclasses of InAppMessageImmersiveBase.

HTML Full in-app messages are InAppMessageHtmlFull instances, which implement IInAppMessageHtml, another subclass of IInAppMessage.

Slideup In-App Messages

Slideup in-app messages are so-named because they “slide up” or “slide down” from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability.

Slideup Example

Modal in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two click action and analytics enabled buttons.

Modal Example

Full In-App Messages

Full in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a full in-app message contains an image and the lower half displays text as well as up to two click action and analytics enabled buttons.

Full Example

HTML Full In-App Messages

HTML Full in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a WebView and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

The following example shows a survey HTML Full in-app message created by Soundcloud.

HTML5 Example

Full in-app message content is displayed in a UIWebView and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. Please note that we currently do not support display of custom HTML in-app messages in an iFrame on the iOS and Android platforms.

In-App Message Delivery

In-App Messages (Triggered)

The following documentation refers to Braze’s In-App Messaging product, aka “triggered in-app messages,” which are branded as highlighted below in the “Create Campaign” drop-down:

In-App Messaging Composer

You may also refer to the documentation for our deprecated Original In-App Messaging product.

Trigger Types

Our in-app message product allows you to trigger in-app message display as a result of several different event types: Any Purchase, Specific Purchase, Session Start, Custom Event, Push Click. Furthermore, Specific Purchase and Custom Event triggers can contain robust property filters.

-Note: Triggered in-app messages only work with custom events logged through the SDK and not through the Rest APIs. If you’re working with Android, please check out how to log custom events here. If you’re working with iOS, check out how to log custom events here.

Delivery Semantics

All in-app messages that a user is eligible for are delivered to the user’s device on session start. For more information about the SDK’s session start semantics, see our session lifecycle documentation. Upon delivery, the SDK will pre-fetch assets so that they are available immediately at trigger time, minimizing display latency.

When a trigger event has more than one eligible in-app message associated with it, only the in-app message with the highest priority will be delivered.

For in-app messages that display immediately on deliver (i.e., session start, push click) there can be some latency due to assets not being prefetched.

Minimum Time Interval Between Triggers

By default, we rate limit in-app messages to once every 30 seconds to ensure a quality user experience.

To override this value, set com_appboy_trigger_action_minimum_time_interval_seconds in your appboy.xml. An example can be found in our sample application’s appboy.xml.

Local In-App Messages

In-app messages can be created within the app and displayed locally in real-time. All customization options available on the dashboard are also available locally. This is particularly useful for displaying messages that you wish to trigger within the app in real-time.

1
2
3
  // Initializes a new slideup type in-app message and specifies its message.
  InAppMessageSlideup inAppMessage = new InAppMessageSlideup();
  inAppMessage.setMessage("Welcome to Braze! This is a slideup in-app message.");

Do not display in-app messages when the soft keyboard is displayed on screen as rendering is undefined in this circumstance.

Manually Triggering In-App Message Display

The following method will manually display your in-app message.

1
  AppboyInAppMessageManager.getInstance().addInAppMessage(inAppMessage);

See InAppMessageTesterFragment.java in the DroidBoy sample app for example usage.

In-Depth: Defining Custom In-App Message Types

Braze’s slideup in-app message object extends InAppMessageBase. Braze’s full and modal type messages extend InAppMessageImmersiveBase. Extending one of these classes gives you the option of adding custom functionality to your locally generated in-app messages.

See CustomInAppMessage.java in the DroidBoy sample app for an example implementation.

Customization

Key-Value Pair Extras

In-app message objects may carry key-value pairs as extras. They are specified on the dashboard under “Advanced Settings” when creating an in-app message campaign. These can be used to send data down along with an in-app message for further handling by the application.

Call the following when you get an in-app message object to retrieve its extras:

1
Map<String, String> getExtras()

See the Javadoc for more information.

Custom Styling

Braze UI elements come with a default look and feel that matches the Android standard UI guidelines and provides a seamless experience. You can see these default styles in the Braze SDK’s styles.xml file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  <style name="Appboy"/>
    <!-- In-app Message -->
  <style name="Appboy.InAppMessage">
  </style>
  <style name="Appboy.InAppMessage.Header">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:padding">0.0dp</item>
    <item name="android:background">@android:color/transparent</item>
    <item name="android:textColor">@color/com_appboy_inappmessage_header_text_light</item>
    <item name="android:textSize">19.0sp</item>
    <item name="android:layout_gravity">center</item>
    <item name="android:singleLine">true</item>
    <item name="android:textStyle">bold</item>
  </style>

If you would prefer, you can override these styles to create a look and feel that better suits your app.

To override a style, copy it in its entirety to the styles.xml file in your own project and make modifications. The whole style must be copied over to your local styles.xml file in order for all attributes to be correctly set. Please note that these custom styles are for changes to individual UI elements, not wholesale changes to layouts. Layout-level changes need to be handled with custom views.

Using Custom Styling to Set a Custom Font

Braze allows for setting a custom font using the font family guide. To use it, override the style for message text, headers, and/or button text and use the fontFamily attribute to instruct Braze to use your custom font family.

For example, to update the font on your in-app message button text, override the Appboy.InAppMessage.Button style and reference your custom font family. The attribute value should point to a font family in your res/font directory.

Here is a truncated example with a custom font family, my_custom_font_family, referenced on the last line:

1
2
3
4
5
6
7
  <style name="Appboy.InAppMessage.Button">
    <item name="android:layout_height">wrap_content</item>
    ...
    <item name="android:paddingBottom">15.0dp</item>
    <item name="android:fontFamily">@font/my_custom_font_family</item>
    <item name="fontFamily">@font/my_custom_font_family</item>
  </style>

Aside from the Appboy.InAppMessage.Button style for button text, the style for message text is Appboy.InAppMessage.Message and the style for message headers is Appboy.InAppMessage.Header. If you want to use your custom font family across all possible in-app message text, you can set your font family on the Appboy.InAppMessage style, which is the parent style for all in-app messages.

As with other custom styles, the entire style must be copied over to your local styles.xml file for all attributes to be correctly set.

Setting Custom Listeners

Before customizing in-app messages with custom listeners, it’s important to understand the AppboyInAppMessageManager, which handles the majority of in-app message handling. As described in Step 1, it must be registered for in-app messages to function appropriately.

AppboyInAppMessageManager manages in-app message display on Android. It contains helper class instances that help it manage the lifecycle and display of in-app messages. All of these classes have standard implementations and defining custom classes is completely optional. However, doing so can add another level of control over the display and behavior of in-app messages. These customizable classes include:

Setting a Custom Manager Listener

The AppboyInAppMessageManager automatically handles the display and lifecycle of in-app messages. If you require more control over the lifecycle of a message, setting a custom manager listener will enable you to recieve the in-app message object at various points in the in-app message lifecycle, allowing you to handle its display yourself, perform further processing, react to user behavior, process the object’s Extras, and much more.

Step 1: Implement an In-App Message Manager Listener

Create a class that implements IInAppMessageManagerListener

The callbacks in your IInAppMessageManagerListener will be called at various points in the in-app message lifecycle.

For example, if you set a custom manager listener, when an in-app message is received from Braze, the beforeInAppMessageDisplayed() method will be called. If this method returns true, that signals to AppboyInAppMessageManager that the in-app message will be handled by the host app and that it should not be displayed by Braze. If false is returned, the AppboyInAppMessageManager attempts to display the in-app message. This method should be used if you choose to display the in-app message in a customized manner.

IInAppMessageManagerListener also includes delegate methods for clicks on the message itself or one of the buttons. A common use case would be intercepting a message when a button or message is clicked for further processing.

Step 2: Instruct Braze to use your In-App Message Manager Listener

Once your IInAppMessageManagerListener is created, call AppboyInAppMessageManager.setCustomInAppMessageManagerListener() to instruct AppboyInAppMessageManager to use your custom IInAppMessageManagerListener instead of the default listener.

We recommend setting your IInAppMessageManagerListener in your Application.onCreate() before any other calls to Braze. This will ensure that the custom listener is set before any in-app message is displayed.

See InAppMessageTesterFragment.java in the DroidBoy sample app for an example implementation.

In-Depth: Altering In-App Messages Before Display

When a new in-app message is received, and there is already an in-app message being displayed, the new message will be put onto the top of the stack and can be displayed at a later time.

However, if there is no in-app message being displayed, the following delegate method in IInAppMessageManagerListener will be called:

1
2
3
4
  @Override
  public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessageBase) {
    return InAppMessageOperation.DISPLAY_NOW;
  }

The InAppMessageOperation() return value can be used to control when the message should be displayed. A suggested usage of this method would be to delay messages in certain parts of the app by returning DISPLAY_LATER when in-app messages would be distracting to the user’s app experience.

InAppMessageOperation return value Behavior
DISPLAY_NOW The message will be displayed
DISPLAY_LATER The message will be returned to the stack and displayed at the next available opportunity
DISCARD The message will be discarded
null The message will be ignored. This method should NOT return null

See InAppMessageOperation.java for more details.

If you choose to DISCARD the in-app message and replace it with your own in-app message view, you will need to manually log in-app message clicks and impressions.

On Android, this is done by calling logClick and logImpression on in-app messages, and logButtonClick on immersive in-app messages.

Once an in-app message has been placed on the stack, you can request for it to be retrieved and displayed at any time by calling AppboyInAppMessageManager.requestDisplayInAppMessage(). Calling this method requests Braze to display the next available in-app message from the stack.

Setting a Custom View Factory

Braze’s suite of in-app messages types are versatile enough to cover the vast majority of custom use cases. However, if you would like to fully define the visual appearance of your in-app messages instead of using a default type, Braze makes this possible via setting a custom view factory.

Step 1: Implement an In-App Message View Factory

Create a class that implements IInAppMessageViewFactory

Step 2: Instruct Braze to use your In-App Message View Factory

Once your IInAppMessageViewFactory is created, call AppboyInAppMessageManager.setCustomInAppMessageViewFactory() to instruct AppboyInAppMessageManager to use your custom IInAppMessageViewFactory instead of the default view factory.

We recommend setting your IInAppMessageViewFactory in your Application.onCreate() before any other calls to Braze. This will ensure that the custom view factory is set before any in-app message is displayed.

See InAppMessageTesterFragment.java in the DroidBoy sample app for an example implementation.

In-Depth: Implementing a Braze View Interface

Braze’s slideup in-app message view implements IInAppMessageView. Braze’s full and modal type message views implement IInAppMessageImmersiveView. Implementing one of these classes will allow Braze to add click listeners to your custom view where appropriate. All Braze view classes extend Android’s View class.

Implementing IInAppMessageView allows you to define a certain portion of your custom view as clickable. Implementing IInAppMessageImmersiveView allows you to define message button views and a close button view.

Client Example

The following image is an example custom In-App Message view from a Braze client:

Foodo In-App Message Customization Example

Setting a Custom Animation Factory

In-app messages have preset animation behavior. Slideup type messages slide into the screen; full and modal messages fade in and out. If you would like to define custom animation behaviors for your in-app messages, Braze makes this possible via setting a custom animation factory.

Step 1: Implement an In-App Message Animation Factory

Create a class that implements IInAppMessageAnimationFactory

Step 2: Instruct Braze to use your In-App Message View Factory

Once your IInAppMessageAnimationFactory is created, call AppboyInAppMessageManager.setCustomInAppMessageAnimationFactory() to instruct AppboyInAppMessageManager to use your custom IInAppMessageAnimationFactory instead of the default animation factory.

We recommend setting your IInAppMessageAnimationFactory in your Application.onCreate() before any other calls to Braze. This will ensure that the custom animation factory is set before any in-app message is displayed.

See InAppMessageTesterFragment.java in the DroidBoy sample app for an example implementation.

Setting Fixed Orientation

To set a fixed orientation for an in-app message, first set a custom in-app message manager listener. Then, call setOrientation() on the IInAppMessage object in the beforeInAppMessageDisplayed() delegate method.

1
2
3
4
5
public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) {
  // Set the orientation to portrait
 inAppMessage.setOrientation(Orientation.PORTRAIT);
 return InAppMessageOperation.DISPLAY_NOW;
}

Server-side Event Triggering

By default in-app messages are triggered by custom events logged by the SDK. If you would like to trigger in-app messages by server sent events you are also able to achieve this.

To enable this feature, a silent push is sent to the device which allows a custom push receiver to log an SDK based event. This SDK event will subsequently trigger the user-facing in-app message.

Step 1: Register a Custom Broadcast Receiver to Log Custom Event

Register your custom BroadcastReceiver to listen for a specific silent push within your AndroidManifest.xml. For more information on how to register a custom BroadcastReceiver please review Braze’s push documentation.

Step 2: Create your BroadcastReceiver

Your receiver will handle the intent broadcast by the silent push and log an SDK event. Starting in SDK 2.0.0, events can be logged in the background without issue. All clients implementing this solution must be on SDK v2.0.0+.

It will subclass BroadcastReceiver and override onReceive(). For a detailed example, please see our EventBroadcastReceiver.java in the linked gist.

Two events will be logged for the in-app message to be delivered, one by the server and one from within your custom BroadcastReceiver. To ensure the same event is not duplicated, the event logged from within your BroadcastReceiver should be given a generic naming convention, for example “in-app message trigger event,” and not the same name as the server sent event. If this is not done segmentation and user data may be affected by duplicate events being logged for a single user action.

For further details on custom handling push receipts, opens, and key-value pairs please visit this section of our Documentation.

Step 3: Create a Push Campaign

Create a silent push campaign which is triggered via the server sent event. For details on how to create a silent push campaign please review this section of our Academy.

serverEventTrigger

The push campaign must include key value pair extras which indicate that this push campaign is sent with the intention to log an SDK custom event. This event will be used to trigger the in-app message

kvpConfiguration

The EventBroadcastReceiver.java recognizes the key value pairs and logs the appropriate SDK custom event.

Should you want to include any event properties to attach to your ‘In-App Message Trigger’ event, you can achieve this by passing these in the key value pairs of the push payload. In the example above the campaign name of the subsequent in-app message has been included. Your custom BroadcastReceiver can then pass the value as the parameter of the event property when logging the custom event.

Step 4: Create an In-App Message Campaign

Create your user visible in-app message campaign from within Braze’s dashboard. This campaign should have an Action Based delivery, and be triggered from the custom event logged from within the custom EventBroadcastReceiver.java.

In the example below the specific in-app message to be triggered has been configured by sending the event property as part of the initial silent push.

serverEventTrigger

If a server sent event is logged whilst the app is not in the foreground, the event will log but the in-app message will not be displayed. Should you want the event to be delayed until the application is in the foreground, a check must be included in your custom push receiver to dismiss or delay the event until the app has entered the foreground.

GIFs

Braze requires an external image library to display animated GIFs with in-app messages.

Custom Image Library Integration

Braze offers the ability to use a custom image library to display animated GIFs with in-app messages.

Note: Although the example below uses Glide, any image library that supports GIFs is compatible.

Step 1: Creating the Image Loader Delegate

The Image Loader delegate must implement the following methods:

The integration example below is taken from the Glide Integration Sample App included with the Braze Android SDK.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class GlideAppboyImageLoader implements IAppboyImageLoader {
  private static final String TAG = GlideAppboyImageLoader.class.getName();
  private RequestOptions mRequestOptions = new RequestOptions();

  @Override
  public void renderUrlIntoView(Context context, String imageUrl, ImageView imageView, AppboyViewBounds viewBounds) {
    Glide.with(context)
        .load(imageUrl)
        .apply(mRequestOptions)
        .into(imageView);
  }

  @Override
  public Bitmap getBitmapFromUrl(Context context, String imageUrl, AppboyViewBounds viewBounds) {
    try {
      return Glide.with(context)
          .asBitmap()
          .apply(mRequestOptions)
          .load(imageUrl).submit().get();
    } catch (Exception e) {
      AppboyLogger.e(TAG, "Failed to retrieve bitmap at url: " + imageUrl, e);
    }
    return null;
  }

  @Override
  public void setOffline(boolean isOffline) {
    // If the loader is offline, then we should only be retrieving from the cache
    mRequestOptions = mRequestOptions.onlyRetrieveFromCache(isOffline);
  }
}

Step 2: Setting the Image Loader Delegate

The Braze SDK will use any custom image loader set with setAppboyImageLoader. Note that we recommend setting the custom image loader in a custom application subclass.

1
2
3
4
5
6
7
public class GlideIntegrationApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    Appboy.getInstance(this).setAppboyImageLoader(new GlideAppboyImageLoader());
  }
}

Fresco Migration

Fresco is no longer supported as a GIF loading library in version 3.0.0 of the Braze Android SDK. A custom image loader, such as Glide, must be used in order to display GIFs.

The usage of Fresco with IAppboyImageLoader is not supported since Fresco requires Drawee views to work.

Advanced Notes

Android Dialogs

Braze doesn’t support displaying in-app messages in Android Dialogs at this time.

Button Text Capitalization

Android Material Design specifies that Button text should be upper case by default. Braze’s in-app message buttons follow this convention as well.

Youtube in HTML in-app messages

Starting in Braze Android SDK version 2.0.1, Youtube and other HTML5 content can play in HTML in-app messages. This requires hardware acceleration to be enabled in the Activity where the in-app message is being displayed, please see the Android developer guide for more details. Also that hardware acceleration is only available on API versions 11 and above.

Troubleshooting

Troubleshooting Scenarios

Expected In-App Message Did Not Display

Most in-app message issues can be broken down into two main categories: delivery and display. To troubleshoot why an expected in-app message did not display on your device, you should first ensure that the in-app message was delivered to the device, then troubleshoot message display.

Impressions Are Lower Than Expected

Triggers take time to sync to the device on session start, so there can be a race condition if users log an event or purchase right after they start a session. One potential workaround could be changing the campaign to trigger off of session start, then segmenting off of the intended event or purchase. Note that this would deliver the in-app message on the next session start after the event has occurred.

In-App Message Delivery

The SDK requests in-app messages from Braze’s servers on session start. To check if in-app messages are being delivered to your device, you’ll need to ensure that in-app messages are being both requested by the SDK and returned by Braze’s servers.

Check If Messages Are Requested and Returned

  1. Add yourself as a test user on the Dashboard.
  2. Set up an in-app message campaign targeted at your user.
  3. Ensure that a new session occurs in your application.
  4. Use the Event User Logs to check that your device is requesting in-app messages on session start. Find the SDK Request associated with your test user’s session start event.
    • If your app was meant to request triggered In-App Messages, you should see trigger in the Requested Responses field under Response Data.
    • If your app was meant to request Original In-App Messages, you should see in_app in the Requested Responses field under Response Data.
  5. Use the Event User Logs to check if the correct in-app messages are being returned in the Response Data.

In-App Message

Troubleshoot Messages Not Being Requested

If your in-app messages are not being requested, your app might not be tracking sessions correctly, as in-app messages are refreshed upon session start. Also be sure that your app is actually starting a session based on your app’s session timeout semantics:

Session Start

Troubleshoot Messages Not Being Returned

If your in-app messages are not being returned, you’re likely experiencing a campaign targeting issue:

  • Your segment does not contain your user.
    • Check your user’s Engagement tab to see if the correct segment appears under Segments.
  • Your user has previously received the in-app message and was not re-eligible to receive it again.
    • Check the campaign re-eligibility settings under the Delivery tab of the Campaign Composer and make sure the re-eligibility settings align with your testing setup.
  • Your user hit the frequency cap for the campaign.
  • If there was a control group on the campaign, your user may have fallen into the control group.
    • You can check if this has happened by creating a segment with a “Received Campaign Variant” filter, where the campaign variant is set to “Control”, and checking if your user fell into that segment.
    • When creating campaigns for integration testing purposes, make sure to opt-out of adding a control group.

In-App Message Display

If your app is successfully requesting and receiving in-app messages but they are not being shown, some device-side logic may be preventing display:

  • Triggered in-app messages are rate-limited based on the minimum time interval between triggers, which defaults to 30 seconds.
  • If you have set a delegate to customize in-app message handling, check your delegate to ensure it is not affecting in-app message display.
  • Failed image downloads will prevent in-app messages with images from displaying. Image downloads will always fail if . Check your device logs to ensure that image downloads are not failing.
  • If the device orientation did not match the orientation specified by the in-app message, the in-app message will not display. Make sure that your device is in the correct orientation.
WAS THIS PAGE HELPFUL?