# Inline in-app messages

Inline in-app messages help you send dynamic content into your app. The messages can look and feel like a part of your app, but provide fresh and timely content without requiring app updates.

## How it works[](#how-it-works)

An inline message targets a specific view in your app. Basically, you’ll create an empty placeholder view in your app’s UI, and we’ll fill it with the content of your message.

This makes it easy to show dynamic content in your app without development effort. You don’t need to force an update every time you want to talk to your audience. *And*, unlike push notifications, banners, toasts, and so on, in-line messages can look like natural parts of your app.

## Install dependencies[](#install-dependencies)

Add the appropriate dependency to your `build.gradle` file based on your UI framework:

```gradle
dependencies {
  // For Android XML views
  implementation "io.customer.android:messaging-in-app:4.17.0"
  
  // For Jetpack Compose (includes messaging-in-app internally)
  implementation "io.customer.android:messaging-in-app-compose:4.17.0"
}
```

 If you’re using **Jetpack Compose**, you only need the `messaging-in-app-compose` dependency. It includes the standard in-app messaging functionality internally.

 For more information about installing and configuring the Customer.io SDK, see our [Quick Start Guide](../../quick-start-guide/#install).

## 1\. Add View to your app UI to support inline messages[](#1-add-view-to-your-app-ui-to-support-inline-messages)

You’ll need to include a UI element in your app UI to render inline messages. Avoid setting a fixed height on this view as its height will automatically adjust when messages are loaded or interacted with.

 We’ve set up examples in [our sample apps](https://github.com/customerio/customerio-android/tree/main/samples/) that might help if you want to see a real-world implementation of this feature.

 Android XML

#### Android XML[](#Android XML)

1.  Open your layout XML file and add `InlineInAppMessageView` to your layout as shown in the example below.
    
2.  Set up layout constraints: you’re responsible for setting the width and the leading, top, trailing, and bottom constraints for the view. See [view layout](#view-layout) for more information.
    
3.  Set the `elementId` in your XML or programmatically in your activity/fragment. This ID is used in Customer.io UI to target this view when sending an in-app message.
    
    ```xml
     <io.customer.messaginginapp.ui.InlineInAppMessageView
         android:id="@+id/example_in_app_message"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         app:elementId=<example-element-id> />
    ```
    
4.  Or you can set the `elementId` directly in code as shown below:
    
    ```kotlin
    val inlineView = findViewById<InlineInAppMessageView>(R.id.example_in_app_message)
    inlineView.elementId = <example-element-id>
    ```
    

 Jetpack Compose

#### Jetpack Compose[](#Jetpack Compose)

1.  Add the `InlineInAppMessage` to your UI as shown in the example below.
    
2.  Set layout modifiers to position the view. Avoid setting a fixed height, `InlineInAppMessage` will adjust its height automatically when messages load or are interacted with. See [view layout](#view-layout) for more information.
    
3.  Set the `elementId` in your composable. This ID is used in Customer.io UI to target this view when sending an in-app message.
    
    ```kotlin
    import io.customer.messaginginapp.compose.InlineInAppMessage
    
    InlineInAppMessage(
        elementId = <example-element-id>,
        modifier = Modifier.fillMaxWidth()
    )
    ```
    

### Set up layout constraints for your message[](#view-layout)

Inline message views automatically adjust their height at runtime when messages load or users interact with them. Use `wrap_content` for the view’s height. This lets the view resize itself dynamically.

You’re responsible for setting layout constraints or modifiers to position your view correctly (like start, top, or end). You shouldn’t use a fixed height, as it might interfere with message rendering. If you’re using XML, Android Studio might show warnings if you don’t set a height. The `wrap_content` setting satisfies these warnings without breaking functionality.

## 2\. Build and send your message[](#2-build-and-send-your-message)

When you add an in-app message to a broadcast or campaign in Customer.io:

1.  Set the **Display** to **Inline** and set the **Element ID** to the ID you set in your app. If the editor says that the inline display feature is *Web/iOS only*, don’t worry about that. We’re working on updating this UI.
2.  (Optional) If you send multiple messages to the same Element ID, you’ll also want to set the **Priority**. This determines which message we’ll show to your audience first, if there are multiple messages in the queue.

Then craft and send your message!

[![in-app message settings with the To field set to ID and the display setting set to inline](https://docs.customer.io/images/in-app-inline.png)](#74810b23329cd479a11edfdda9f818e0-lightbox)

## Handling custom actions[](#handling-custom-actions)

When you set up an in-app message, you can determine the “action” to take when someone taps a button, taps your message, etc. In most cases, you’ll want to deep link to a screen, etc. But, in some cases, you might want to execute some custom action or code—like requesting that a user opts into push notifications or enables a particular setting.

While you’ll have to write custom code to handle custom actions, the SDK helps you listen for in-app message events including your custom action, so you know when to execute your custom code.

Follow these steps to implement custom action buttons for inline messages:

### 1\. Compose an in-app message with a custom action[](#1-compose-an-in-app-message-with-a-custom-action)

When you [add an action to an in-app message](/journeys/in-app-messages/) in Customer.io, select *Custom Action* and set your Action’s *Name* and value. The *Name* corresponds to the `actionName`, and the value represents the `actionValue` in your event listener.

[![Set up a custom in-app action](https://docs.customer.io/images/in-app-custom-action.png)](#1005ee0b179f3999e81398a57e369557-lightbox)

### 2\. Listen for events[](#2-listen-for-events)

There are two ways to listen for these click events in inline in-app messages.

1.  Register a delegate with your inline view:
    
     Android XML
    
    #### Android XML[](#Android XML)
    
    ```kotlin
    import io.customer.messaginginapp.type.InAppMessage
    import io.customer.messaginginapp.type.InlineMessageActionListener
    import io.customer.messaginginapp.ui.InlineInAppMessageView
    
    class InlineExamplesActivity: AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            
            val inlineView = findViewById<InlineInAppMessageView>(R.id.example_in_app_message)
            inlineView.setActionListener(MyInlineMessageActionListener())
        }
    }
    
    class MyInlineMessageActionListener : InlineMessageActionListener {
        override fun onActionClick(message: InAppMessage, actionValue: String, actionName: String) {
            // Perform some logic when people tap an action button.
    
            // Example code handling button tap:
            when (actionValue) { // use actionValue or actionName, depending on how you composed the in-app message.
                "enable-auto-renew" -> {
                    // Perform the action to enable auto-renew
                    enableAutoRenew(actionName)
                }
    
                // You can add more cases here for other actions
                else -> {
                    // Handle unknown actions or do nothing
                    print("Unknown action: $actionValue")
                }
            }
        }
    }
    ```
    
     Jetpack Compose
    
    #### Jetpack Compose[](#Jetpack Compose)
    
    ```kotlin
    import io.customer.messaginginapp.compose.InlineInAppMessage
    import io.customer.messaginginapp.type.InAppMessage
    import io.customer.messaginginapp.type.InlineMessageActionListener
    
    @Composable
    fun InlineInAppMessageExample() {
        InlineInAppMessage(
            elementId = <example-element-id>,
            modifier = Modifier
                .fillMaxWidth(),
            progressTint = Color(0xFF03DAC5), // Optional: set custom progress color if needed
            onAction = { message: InAppMessage, actionValue: String, actionName: String ->
                // Perform some logic when people tap an action button.
    
                // Example code handling button tap:
                when (actionValue) { // use actionValue or actionName, depending on how you composed the in-app message.
                    "enable-auto-renew" -> {
                        // Perform the action to enable auto-renew
                        enableAutoRenew(actionName)
                    }
    
                    // You can add more cases here for other actions
                    else -> {
                        // Handle unknown actions or do nothing
                        print("Unknown action: $actionValue")
                    }
                }
            }
        )
    }
    ```
    
2.  Register a global SDK event listener.
    
    When you register an [event listener](../in-app-event-listeners/#event-listeners) with the SDK, we’ll call the `messageActionTaken` event listener. We call this event listener for both modal and inline in-app message types, so you can reuse logic if you want.
    

## Handle responses to messages (event listeners)[](#event-listeners)

Similar to [modal in-app messages](../in-app-event-listeners/#event-listeners), you can set up event listeners to handle your audience’s response to your messages.

For inline messages, you can listen for three different events:

*   `messageShown`: a message is “sent” and appears to a user.
*   `errorWithMessage`: the message itself produces an error—this probably prevents the message from appearing to the user.
*   `messageActionTaken`: the user performs an action in the message. As [shown above](#2-listen-for-events), this is only called if the View instance doesn’t have an `onActionDelegate` set.

Unlike modal in-app messages, you’ll notice that there’s no `messageDismissed` event. This is because inline messages don’t really have a concept of dismissal like modal messages do. They’re meant to be a part of your app!