
## Overview
---
In-app message is a banner that can be displayed when your app is running. It may have various layout variants, because it is fully customizable by HTML. The campaign is triggered and displayed depending on the configuration settings.

Read more about creating in-app messages [here](/docs/campaign/in-app-messages/create-inapp-message).


<div class="admonition admonition-warning"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" /></svg></div><div class="admonition-body"><div class="admonition-content">

Due to operating system differences and web engines, in-app message appearance may differ between systems or not be as expected. You should test your in-app messages.

</div></div></div>



<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

In in-app messages, you can use:
- the **safe area** mode on iOS from the `5.1.0` version, 
- the **display cutouts** mode on Android from the `6.1.0` version.

</div></div></div>


## Requirements
---

- Recommended Mobile SDK version:
    - Android - 5.3.0 or newer
    - iOS - 4.12.0 or newer
    - React Native - 0.12.0 or newer
    - Flutter - 0.5.0 or newer
- If your in-app content (such as JavaScript, CSS, images, or fonts) is being loaded from your own server via HTTP and you have configured **CORS policies**, you need to set the **contentBaseUrl** to your server's address. For example, if you're loading resources from `https://www.synerise.com/example/font.woff`, you should configure **contentBaseUrl** to `https://www.synerise.com` (check this option in the [Settings](/developers/mobile-sdk/settings#content-base-url-for-in-app-message)).
- Enable the `IN_APP_DEFINITIONS_COMMUNICATION_READ` (**Experience Hub**) permission in the Profile (formerly Client) [API key](/docs/settings/tool/api) used by the mobile application so the mobile application can fetch in-app messages.  
    <figure><img src="/api/docs/image/54176ad07f146575310749eba44b7c2f42c1b327/docs/campaign/_gfx/permission-for-in-app.png" class="full" alt="The API key permission matrix with the in-app permission"><figcaption>The API key permission matrix with the in-app permission</figcaption></figure>

## Good practices
---

### Campaign planning recommendations

Using a large number of in-app messages in your application can impact rendering time, message delivery, and battery usage.

To maintain optimal application performance when using in-app campaigns:
- Avoid assigning more than 10 in-app messages to the same trigger event.
- Avoid having more than 20 in-app messages active at the same time in your application.
- Review and archive in-app campaigns that you no longer need.  

### Template construction

When creating or editing in-app message content:

- Place the the `SRInApp.close()` (or `SRInApp.hide()`) method at the beginning of the JS script.
- Use try/catch to handle possible fatal errors in the JS script.
- Handle situations where Jinjava inserts return empty data.
- When adding external links to your message:
    - Only link to sites you trust.
    - Don't link to large images that may negatively affect performance.
    - Don't link to resources whose CSS/HTML may be blocked. If you have resources loaded from your own URLs, set `Synerise.settings.inAppMessaging.contentBaseUrl` and use relative paths in HTML/CSS.

## Configuration
---
In-app message campaigns are served by the Synerise backend.
  
Check possible available configuration options in the [Settings](/developers/mobile-sdk/settings#in-app-messaging).

## JavaScript methods in in-app messages
---

See ["Using in-app template builder" in the User Guide](/docs/campaign/in-app-messages/creating-inapp-templates/creating-inapp-template#javascript-methods-in-in-app-messages).

## Events generated by in-app messaging
---
For information about events generated by in-app messaging, see the [event reference](/docs/assets/events/event-reference/inapp).


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

You can disable sending the `inApp.capping` event in the SDK Settings - [Enable/disable sending in-app capping event](/developers/mobile-sdk/settings#enabledisable-sending-inappcapping-event).

</div></div></div>


## Setting up a global control group for in-app message
---
For information about global control groups in in-app messages, see the [global control group](/docs/settings/configuration/global-control-group) article.

## Handling actions from in-app messages
---
Handling main actions from campaigns depends on the campaign type and operating system and it is described [here](/developers/mobile-sdk/campaigns/action-handling).

## Controlling behavior and actions
---
You may control an incoming in-app message and decide whether to show it (the display of in-app message can be triggered by occurrence of specific events). By default, the SDK allows in-app message display.  

The user interface allows selecting up to 3 trigger events, however, in Android, only for `5.8.1` SDK version (released on 28.08.2023) or higher all triggers are considered altogether. For older SDK versions in Android, only the last event from the trigger list will be considered.  
These limitations don't apply in iOS.

Also, you can be notified (in the form of events) about the campaign actions in the following cases:
- When the in-app message is presented.
- When the in-app message disappeared.
- When additional context is needed to render the campaign.
- When the customer invoked an action.

You can handle the message using:
- [OnInAppListener](/developers/mobile-sdk/listeners-and-delegates/android-listeners#on-in-app-listener) methods for Android. 
- [InjectorInAppMessageDelegate](/developers/mobile-sdk/listeners-and-delegates/ios-delegates#injector-in-app-message-delegate) methods for iOS. 
- [InjectorInAppMessageListener](/developers/mobile-sdk/listeners-and-delegates/react-native-listeners#injector-in-app-message-listener) methods for React Native. 
- [InjectorInAppMessageListener](/developers/mobile-sdk/listeners-and-delegates/flutter-listeners#injector-in-app-message-listener) methods for Flutter. 

See the following code samples:


<div class="content-tabs code-tabs" data-tab-group="tabgrp-25">
<div class="tab-buttons"><button class="tab-button" data-tab-id="tabgrp-25-0" data-tab-group="tabgrp-25" data-tab-active="true">Java</button><button class="tab-button" data-tab-id="tabgrp-25-1" data-tab-group="tabgrp-25">Kotlin</button><button class="tab-button" data-tab-id="tabgrp-25-2" data-tab-group="tabgrp-25">Swift</button><button class="tab-button" data-tab-id="tabgrp-25-3" data-tab-group="tabgrp-25">Objective-C</button><button class="tab-button" data-tab-id="tabgrp-25-4" data-tab-group="tabgrp-25">JavaScript</button><button class="tab-button" data-tab-id="tabgrp-25-5" data-tab-group="tabgrp-25">Dart</button></div>

<div class="tab-panel" data-tab-id="tabgrp-25-0" data-tab-group="tabgrp-25" data-tab-active="true">

```Java
public static OnInAppListener NULL = new OnInAppListener() {
  // This method is called after an in-app message is loaded and Synerise SDK asks for permission to show it.
  @Override
  public boolean shouldShow(InAppMessageData inAppMessageData) {
    return true;
  }

  // This method is called after an in-app message appears.
  @Override
  public void onShown(InAppMessageData inAppMessageData) {
    //...  
  }

  // This method is called after an in-app message disappears.
  @Override
  public void onDismissed(InAppMessageData inAppMessageData) {
    //...
  }

  // This method is called when a individual context for an in-app message is needed.
  @Override
  public HashMap<String, Object> onContextFromAppRequired(InAppMessageData inAppMessageData) {
    return new HashMap<>();
  }

  // This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
  @Override
  public void onHandledOpenUrl(InAppMessageData inAppMessageData) {
    //...
  }

  // This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
  @Override
  public void onHandledOpenDeepLink(InAppMessageData inAppMessageData) {
    //...
  }

  // This method is called when the
  // SRInApp.handleCustomAction(name, params) method is used in an in-app message.
  @Override
  public void onCustomAction(String identifier, HashMap<String, Object> params, InAppMessageData inAppMessageData) {
    //...
  }
};
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-25-1" data-tab-group="tabgrp-25">

```Kotlin
var inAppCallbacks: OnInAppListener = object : OnInAppListener() {
  // This method is called after an in-app message is loaded and Synerise SDK asks for permission to show it.
  override fun shouldShow(inAppMessageData: InAppMessageData): Boolean {
    return true
  }

  // This method is called after an in-app message appears.
  override fun onShown(inAppMessageData: InAppMessageData) {
    //...
  }

  // This method is called after an in-app message disappears.
  override fun onDismissed(inAppMessageData: InAppMessageData) {
    //...
  }

  // This method is called when a individual context for an in-app message is needed.
  override fun onContextFromAppRequired(inAppMessageData: InAppMessageData): HashMap<String, Any> {
    return HashMap()
  }

  // This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
  override fun onHandledOpenUrl(inAppMessageData: InAppMessageData) {
    //...
  }

  // This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
  override fun onHandledOpenDeepLink(inAppMessageData: InAppMessageData) {
    //...
  }

  // This method is called when the
  // SRInApp.handleCustomAction(name, params) method is used in an in-app message.
  override fun onCustomAction(identifier: String?, params: HashMap<String?, Any?>?, inAppMessageData: InAppMessageData?) {
    //...
  }
}
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-25-2" data-tab-group="tabgrp-25">

```Swift
// MARK: - InjectorInAppMessageDelegate

// This method is called after an in-app message is loaded and Synerise SDK asks for permission to show it.
func snr_shouldInAppMessageAppear(data: InAppMessageData) -> Bool {
  return true
}

// This method is called after an in-app message appears.
func snr_inAppMessageDidAppear(data: InAppMessageData) {
  //...
}

// This method is called after an in-app message disappears.
func snr_inAppMessageDidDisappear(data: InAppMessageData) {
  //...
}

// This method is called when an in-app message changes size.
func snr_inAppMessageDidChangeSize(rect: CGRect) {
  //...
}

// This method is called when a individual context for an in-app message is needed.
func snr_inAppMessageContextIsNeeded(data: InAppMessageData) -> [AnyHashable: Any]? {
  return []
}

// This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
func snr_inAppMessageHandledAction(data: InAppMessageData, url: URL) {
  //...
}

// This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
func snr_inAppMessageHandledAction(data: InAppMessageData, deeplink: String) {
  //...
}

// This method is called when the
  // SRInApp.handleCustomAction(name, params) method is used in an in-app message.
func snr_inAppMessageHandledCustomAction(data: InAppMessageData, name: String, parameters: [AnyHashable: Any]) {
  //...
}
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-25-3" data-tab-group="tabgrp-25">

```Objective-C
#pragma mark - SNRInjectorInAppMessageDelegate

// This method is called after an in-app message is loaded and Synerise SDK asks for permission to show it.
- (BOOL)SNR_shouldInAppMessageAppear:(SNRInAppMessageData *)data {
  //...
}

// This method is called after an in-app message appears.
- (void)SNR_inAppMessageDidAppear:(SNRInAppMessageData *)data {
  //...
}

// This method is called after an in-app message disappears.
- (void)SNR_inAppMessageDidDisappear:(SNRInAppMessageData *)data {
  //...
}

// This method is called when an in-app message changes size.
- (void)SNR_inAppMessageDidChangeSize:(CGRect)rect {
  //...
}

// This method is called when a individual context for an in-app message is needed.
- (nullable NSDictionary *)SNR_inAppMessageContextIsNeeded:(SNRInAppMessageData *)data {
  //...
}

// This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
- (void)SNR_inAppMessageHandledURLAction:(SNRInAppMessageData *)data url:(NSURL *)url {
  //...
}

// This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
- (void)SNR_inAppMessageHandledDeeplinkAction:(SNRInAppMessageData *)data deeplink:(NSString *)deeplink {
  //...
}

// This method is called when the
  // SRInApp.handleCustomAction(name, params) method is used in an in-app message.
- (void)SNR_inAppMessageHandledCustomAction:(SNRInAppMessageData *)data name:(NSString *)name parameters:(NSDictionary *)parameters {
  //...
}
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-25-4" data-tab-group="tabgrp-25">

```JavaScript
Synerise.onReady(function() {
  Synerise.Injector.setInAppMessageListener({
    // This method is called after an in-app message is loaded and Synerise SDK asks for permission to show it.
    shouldPresent: function(data) {
      return true;
    },
    // This method is called after an in-app message appears.
    onPresent: function(data) {
      //...
    },
    // This method is called after an in-app message disappears.
    onHide: function(data) {
      //...
    },
    // This method is called when a individual context for an in-app message is needed.
    contextIsNeeded: function(data) {
      return {}
    },
    // This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
    onOpenUrl: function(data, url) {
      //...
    },
    // This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
    onDeepLink: function(data, deepLink) {
      //...
    },
    // This method is called when Synerise handles custom action from in-app messages.
    onCustomAction: function(data, name, parameters) {
      //...
    }
  });
})
```

</div>

<div class="tab-panel" data-tab-id="tabgrp-25-5" data-tab-group="tabgrp-25">

```Dart
Synerise.injector.inAppMessageListener((listener) {
  // This method is called after an in-app message appears.
  listener.onPresent = (data) {
    //...
  };
  // This method is called after an in-app message disappears.
  listener.onHide = (data) {
    //...
  };
  // This method is called when the SRInApp.openUrl(url) method is used in an in-app message.
  listener.onOpenUrl = (data, url) {
    //...
  };
  // This method is called when the SRInApp.openDeeplink(url) method is used in an in-app message.
  listener.onDeepLink = (data, deepLink) {
    //...
  };
  // This method is called when Synerise handles custom action from in-app messages.
  listener.onCustomAction(data, name, parameters) {
    //...
  };
});
```

</div>
</div>


## Closing a message  

In-app messages can be closed with a [JS method included in their content](/docs/campaign/in-app-messages/creating-inapp-templates/creating-inapp-template#close-a-message), but you can also use a mobile SDK method. This can be used to close top or bottom bar in-app from somewhere else on the screen.  
Using this method generates an `inApp.discard` event.  
See the method reference:
- [Android](/developers/mobile-sdk/method-reference/android/campaigns#close-in-app-message)
- [Flutter](/developers/mobile-sdk/method-reference/flutter/campaigns#close-in-app-message)
- [iOS](/developers/mobile-sdk/method-reference/ios/campaigns#close-in-app-message)
- [React Native](/developers/mobile-sdk/method-reference/react-native/campaigns#close-in-app-message)

## Example
---
This is an in-app message campaign example with full screen presentation.

<figure><img src="/api/docs/image/54176ad07f146575310749eba44b7c2f42c1b327/developers/mobile-sdk/_gfx/android-in-app-campaign-1.png" alt="In-app message campaign example" class="small"><figcaption>In-app message campaign (Android)</figcaption></figure>
<figure><img src="/api/docs/image/54176ad07f146575310749eba44b7c2f42c1b327/developers/mobile-sdk/_gfx/ios-in-app-campaign-1.png" alt="In-app message campaign example" class="small"><figcaption>In-app message campaign (iOS)</figcaption></figure>
