# Legacy in-app editor

 The legacy in-app editor is deprecated

You will not be able to create new messages in the legacy editor after **October 1, 2025**. We’re sunsetting the legacy in-app editor **January 31, 2026**. If you haven’t made the switch yet, now’s the perfect time to start using [the new in-app editor](/journeys/html-in-app), designed to help you build better in-app experiences.

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

In-app message templates built in our older template editor include all of your message content, including the text areas you can customize when you create a message in Customer.io.

Any of the messages that you set up with this editor contain basic components like text and images, wrapped in **actions** that make them tappable. These items are then contained in blocks, lists, and grids that organize the layout of your message. For example, a button in your message that takes a person to a deep link is an action (deep link), containing a block (defining the shape of the button), containing a text component (button text).

Unlike messages you create with our new editor, messages built in this older editor also rely on [in-app branding settings](#in-app-branding) (fonts, colors, etc) that are *only* used in this editor.

Create a message...

and use it in a campaign

[![Set up an in-app message](https://docs.customer.io/images/in-app-designer.png)](#3c4d05eb2865e1043720a5f63c7e5060-lightbox)

[![use the message in a campaign](https://docs.customer.io/images/in-app-campaign-message.png)](#b6d4ee4a5ac2f77344969fbe48bbc216-lightbox)

### In-app branding[](#in-app-branding)

*Branding* rules determine the colors, fonts, and padding options used in the old template editor. They *do not* apply to messages you create in the block-based editor, which supports custom CSS classes and reusable styles.

Go to the **Branding** tab under [**Content** > **In-App Messages**](https://fly.customer.io/env/last/in-app-messages) to set or change your in-app branding rules.

[![Set up branding rules for your messages](https://docs.customer.io/images/in-app-branding.png)](#af628618659fb3cfdf99ba0a0c647ae1-lightbox)

 Branding changes take effect immediately

Changes to your branding settings affect all of your messages, even messages that are in-flight!

### In-App message JSON[](#show-code)

You can use the **Show Code** option to expose the JSON representation of your message.

Messages created in this editor are an array of objects, where each object represents a part of your message. Some items, like actions and blocks, contain nested `components`. You might use the code editor to rearrange your message by moving components in and out of blocks, or moving them up or down in the array.

Each component has a `type` and a `gist` object, both are required and set automatically by the editor.

*   `type` determines the type of widget you’re using in the editor—`textWidget`, `imageWidget`, `actionWidget`, etc.
*   `gist` is an object containing a unique `id` for the widget.

[![See the JSON representation of your message in the code editor](https://docs.customer.io/images/in-app-code-editor.png)](#32979f8baaecb922065cf2cd4d728178-lightbox)

## Edit an in-app message[](#set-up-a-template)

While we have a newer, easier to use editor, you might still want to edit messages that you created in our older in-app message editor. You can create new messages in this editor, but we strongly recommend that you [use our new editor](/journeys/html-in-app) for new messages.

1.  Go to the **Messages** tab under [**Content** > **In-App Messages**](https://fly.customer.io/env/last/in-app-messages) and select the message you want to edit.
2.  Add or move around components in your message. By default, a component only shows required fields.
    *   Use `$properties.<var>` to [add variables to your message](#template-variables) that you can supply in Customer.io. For example, `$properties.name` creates a field called *Name* in Customer.io
    *   Click to reveal additional properties for the component.
    *   Click **Actions** in the upper-right of any component to change the order of components, wrap them in blocks, actions, etc.

As you create and update your message, we’ll show how it will appear in your app or on your website.

[![the message designer](https://docs.customer.io/images/in-app-basic-instructions.png)](#fd921ccf18dc705e0a09ae4b0211a634-lightbox)

## Customizing messages with variables[](#template-variables)

You can customize text in your message by adding `$properties.<variableName>` to **text** field. You can include as many variables as you like, and even simply set a variable name for an entire block if you want to give message creators control over the text that they send in messages. You can use the same variable multiple times if you want to duplicate variable text in your message.

When you create and populate your messages, you can use [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/using-liquid) to use your audience’s attributes or event data—like a person’s name or the items they left in their cart. In the example below, we use a variable in an in-app message called `$properties.name` to add a field called `name` when you use the message in a campaign or broadcast.

[![add variables to your messages so that you can personalize them in your campaigns](https://docs.customer.io/images/in-app-message-var.png)](#2155eb0dd19702e5d7f905c9bf1a11d3-lightbox)

## Organizing your message[](#organizing-your-message)

When you add a component or container, we show required settings by default. Click to show additional options.

We organize message items into **blocks**, **content**, and **layout**. In general, *blocks* make it easy to build your message with premade components, and the *content* and *layout* components give you more granular control to customize your message.

*   **blocks** are premade groups of components that you can use to build your message.
*   **content** are content components for your message, like text, images, etc.
*   **layout** components help you organize the visible parts of your message horizontally, vertically, blocks that let you set padding, etc.

in-app messages are flexible: you can nest some containers inside each other. In this section, we’ll show a few common arrangements that you’ll use to create buttons, carousels, and so on.

### Blocks[](#blocks)

#### Message Frame[](#message-frame)

A **message frame** is a group of components you can use to establish an area with rounded corners. Nest content components within the frame as you see fit.

[![A message frame has a vertical list nested within a block for the frame and a block for the message padding.](https://docs.customer.io/images/in-app-message-frame.png)](#c2d93d8dc94516f25a0d222a79f51688-lightbox)

#### Close Button[](#close-button)

A **close button** is a group of components you can use to do just that - close an in-app message. The action is automatically set to close the message, but you can also adjust the action and styling as you see fit.

[![in-app-close-button.png](https://docs.customer.io/images/in-app-close-button.png)](#2d76047c56a861a87524144abfa2727b-lightbox)

#### Button[](#button)

A **button** is a group of components you can use to add an actionable area to your message. The action is automatically set to close the message, but you can also adjust the action and styling as you see fit.

[![in-app-button.png](https://docs.customer.io/images/in-app-button.png)](#1ef8653f03c11730b1b253d9ca585d6e-lightbox)

A button consists of four items, nested in this order:

1.  *Button padding*: a block that determines the padding around the outside of the tappable area.
2.  *Button action*: this determines what happens when someone taps the button.
3.  *Button style*: a block that defines the tappable area and controls the border color, the border radius/roundness of the button, and the color of the button.
4.  *Text*: the text for the button. You could substitute this for a different content component: icon, image or markdown for button text.

Click to style your blocks and content. You can modify the background color or center your button text, for instance.

Remember, [if you want to personalize the text for your buttons](#template-variables) when you create your message, use the syntax `$properties.fieldname`. When you create your message in Customer.io, you’ll see a `fieldname` that you can personalize with [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/using-liquid) or otherwise change so that it’s relevant to your message!

#### Two Button Row[](#two-button-row)

A **two button row** is a group of components that places two buttons, side-by-side in the same row. Set the action, styling, and text as you see fit. You might use this to create an action button and a button that dismisses your message.

[![in-app-two-button-row.png](https://docs.customer.io/images/in-app-two-button-row.png)](#120e7d3832052baccec6ad85a4a7450f-lightbox)

#### Rounded Image[](#rounded-image)

A **rounded image** is a group of components that displays an image within a circular viewport. You can adjust the rounding through **Corner Radius** within the [image component](#image).

[![in-app-rounded-image.png](https://docs.customer.io/images/in-app-rounded-image.png)](#53b2ed492fd5ea532387786f2c7283d7-lightbox)

#### Surveys[](#surveys)

The *Survey* components make it easy to set up surveys for your recipients and automatically track responses in Customer.io. You can use these components to ask for feedback, ratings, or other information from your audience.

With these components, it’s easy to set up the options or ratings available to your audience. See [microsurveys](/journeys/microsurveys/) for more information about setting up surveys and tracking responses in Customer.io.

[![set up a survey to get feedback from recipients](https://docs.customer.io/images/microsurvey-emoji-actions.png)](#2a2c1ef9e204fdac24eedfa5706b3815-lightbox)

#### Links[](#links)

You can set up a link by adding an **action** component and then adding a **text** component inside the action. The action determines what happens when someone taps the text—whether the link goes to a website, somewhere in your app, a mail application, etc.

[![set up a link in your message](https://docs.customer.io/images/gist-link.png)](#6df2da9572a52fad5e325d6dfca0d6c1-lightbox)

### Content[](#content)

#### Text[](#text)

A text component represents any text in your message—headings, body, footers, etc. Use `$properties.<variableName>` to add a customizable variable to your message. When someone uses your message in a campaign or broadcast workflow, they’ll see a field called `<variableName>` that they can personalize for your audience.

Press to expose options to style your text.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "textWidget",
	"text": "$properties.name",
	"style": "bodyText",
	"color": "black",
	"textAlign": "left",
	"maxLines": 1,
	"overflow": "ellipsis"
}
```

 Schema

#### Schema[](#Schema)

*   maxLines integer
    
    The maximum lines of text you want to display. Text over this limit is controlled by the `overflow` property. If unset, the message displays an unlimited number of lines.
    
*   overflow string
    
    Determines how to handle text that overflows the `maxLines` limit (if set). By default, we cut off overflowing text with ellipsis (`...`).
    
    Accepted values:`ellipsis`,`fade`,`clip`
    
*   style string
    
    The style of text you want to display. You can only set values here that are defined under [**Content** > **In-App Messages**](https://fly.customer.io/env/last/in-app-messages).
    
*   text string
    
    Required The text you want to display.
    
*   textAlign string
    
    How you want to align this text.
    
    Accepted values:`center`,`right`,`left`,`start`,`end`,`justify`
    
*   type string
    
    Required Defines the widget type.
    
    Accepted values:`textWidget`
    

#### Markdown[](#markdown)

You can use the **markdown** component to style text using [markdown syntax](https://www.markdownguide.org/basic-syntax/).

Markdown

\# Heading 1

\## Heading 2

\### Heading 3

\*\*bold\*\*

\_\_bold\_\_

\`code\`

\[text\](link)

1\. go to concert  
2\. scream-sing your favorite song  
3\. return home overjoyed and exhausted

\- carrots  
\- broccoli  
\- raspberries

To render markdown using your branding settings, select the styles for headings, text and links below the markdown field. Begin by specifying the color so that they appear on the canvas.

[![in-app-markdown.png](https://docs.customer.io/images/in-app-markdown.png)](#26f7809a2f7cb4a135862d7ef4d6effd-lightbox)

Check the preview on the right to see if you’ve chosen your desired fonts and colors.

#### Image[](#image)

Upload an image for your message. Click the downarrow to reveal additional properties determining the width of your image, how it should fit the bounds of the message, whether it should fade in, etc.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "imageWidget",
	"image": "$properties.imageUrl",
	"fit": "cover",
	"height": 50,
	"width": 50,
	"cornerRadius": 25,
	"fadeInDuration": 200
}
```

 schema

#### schema[](#schema)

*   fadeInDuration integer
    
    The durration for the image to fade in, in milliseconds, similar to the `fadeIn` CSS transition property.
    
*   fit string
    
    Determines how the image fits your message. Defaults to `cover`.
    
    Accepted values:`none`,`fitWidth`,`cover`,`contain`,`scaleDown`,`fill`,`fitHeight`
    
*   type string
    
    Required Defines the widget type.
    
    Accepted values:`imageWidget`
    

#### Icon[](#icon)

The *Icon* widget displays an icon from an icon font. You must load fonts in the `assets` section of your app configuration to show icon fonts.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "IconWidget",
	"color": "black",
	"font": "IconFont-One",
	"size": 18,
	"value": "\e012"
}
```

 schema

#### schema[](#schema)

*   size integer
    
    The pixel size of the icon.
    
*   type string
    
    Required Defines the widget type.
    
    Accepted values:`iconWidget`
    
*   value string
    
    Required The value of the icon that you want to use. For example, for font-awesome, you’d use the name of the icon.
    

#### Action[](#action)

An **Action** determines what happens when someone taps one or more components in your message. You might use an action to send someone to a link in your app, an external link, etc. When you add an action, you’ll determine the action and then add components inside the action.

[![example of a link action](https://docs.customer.io/images/gist-action-link.png)](#7dcf07f870a11cf08f0dba500ac3b330-lightbox)

We support the following actions:

*   **Close message**: Dismisses the in-app message.
*   **Link to web page**: Sends the message recipient to a web page in their default browser.
*   **Link to web page (new tab) or mobile app (deep link)**: Sends a person to a deep link in your app or a webpage (if you use Universal Links). You’ll need to know the deep link format and screen you want to send a person to.
*   **Show another message**: Change the content of your message when someone interacts with it.
*   **Custom action**: Set up an action handled directly by your app. See the [section below](#custom-actions) for more information.

If you use the *Show Code* option, the `action` is the link. You can set a `behavior` key determining how to handle the action. See the schema below for available values.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "actionWidget",
	"action": "myApp://homepage",
	"behaviour": "push",
	"component": {}
}
```

 schema

#### schema[](#schema)

*   action string
    
    Required The link or place you want to send a person. This is either a deep link in your app, a web address, a `mailto` link, or a way to close the message (`gist://close`).
    
*   behaviour string
    
    *   `push`: pushes a new route into the navigation stack.
    *   `system`: offloads the action onto the operating system. Actions like `mailto:support@bourbon.sh` will open the default email client.
    *   `back`: pops the navigation stack one step back.
    *   `retain`: retain replaces the current view with a new route.
    
    Accepted values:`push`,`system`,`back`,`retain`
    
*   component object
    
    Required The component a person taps to perform the action defined in this widget.
    
*   type string
    
    Required Defines the widget type.
    
    Accepted values:`actionWidget`
    

#### Track Clicks[](#track-clicks)

The *Track Clicks* box tells Customer.io to track when someone taps the action—similar to the way [tracked links](/journeys/link-tracking/) work in emails. This setting is enabled by default. If you disable this setting, we won’t track when someone taps the action.

Tracked responses are based on the action name, so make sure that you give your actions names that will make sense to you when you look at metrics later.

#### Custom actions[](#custom-actions)

Unlike other actions, which do something predefined by our SDKs, you can also set up “Custom Actions”—this is custom code that you want to execute when someone interacts with your message. For example, if you send an in-app message requesting that your audience opts-into push notifications, you might execute custom code to trigger the operating system’s native opt-in prompt. Custom actions give you the flexibility to handle your audience’s responses to messages in ways that fit your app uniquely.

Our SDKs expose an in-app event listener called `messageActionTaken`. You’ll set up your app to listen for this event and the custom `actionName` or `actionValue` that you set. When it occurs, you’ll execute custom code in your app. See the in-app pages for [our SDKs](/integrations/sdk/) to learn more about in-app event listeners and set up your first custom action.

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

##### Dismissing messages with custom actions[](#dismiss-in-app-message)

All of our SDKs expose methods to listen for the actions people take when they interact with your messages *and* methods to dismiss the message. If you use custom actions, you’ll need to make sure that your app or website does the following things to execute custom actions and dismiss messages appropriately:

1.  Listen for the custom action (either by `event.actionName` or `event.actionValue`).
2.  Perform your custom action—this is your own code.
3.  Use the `dismissMessage` method to stop showing the message to your audience. See relevant documentation for our SDKs for more information about event listeners and dismissing messages.

#### Carousel[](#carousel)

A carousel is content that users can swipe without dismissing your message. You might use a carousel to showcase new features, provide a tutorial, etc.

You’ll use a *Fixed horizontal scroll* widget containing at least two components. You can even wrap items in the carousel in actions, so that each item in your carousel performs a different action.

### Layout[](#layout)

 Click *Show Code* to move components in and out of lists or grids

You might want to try different list and grid layouts as you create your message. Rather than re-creating components in different list and grid containers, you can use the *Show Code* option and copy the `components` array into different containers to play with different layouts!

#### Block[](#block)

A **block** is a group of components that you apply a design to. You might group components to set a background image, apply rounded corners, etc. The only required property is the list of components you want to nest inside the block.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "blockWidget",
	"safeInsets": false,
	"padding": ["m","m","m",""],
	"backgroundColor": "white",
	"borderColor": "black",
	"borderWidth": 1,
	"borderRadius": 10,
	"height": 150,
	"backgroundImage": "$properties.backgroundImage",
	"flex": 1,
	"components": []
}
```

 schema

#### schema[](#schema)

*   backgroundColor string
    
    The background color for your block. You must set a value defined under *Branding* > *Colors*.
    
*   backgroundImage string
    
    Set a background image for the block
    
*   borderColor string
    
    The border color for your block, if you set a border width greater than 0. You must set a value defined under *Branding* > *Colors*.
    
*   borderWidth integer
    
    The width of the border for this block in pixels.
    
*   flex integer
    
    The single digit syntax for the CSS `flex` property. The value you use here determines the propotional amount of space the block consumes in a parent container.
    
*   padding array of \[ strings \]
    
    Defines padding for the block, based on the values set under *Branding* > *Padding*. As with the CSS `padding` property, values in the array represent top, right, bottom, and left padding.
    
*   safeInsets boolean
    
    Based on the env `safe-area-inset-*` CSS properties. Set to true to ensure that the block can’t overflow the defined screen or the defined area of your message. Defaults to `false`.
    
*   type string
    
    Defines the widget type.
    
    Accepted values:`blockWidget`
    

##### The Flex property[](#the-flex-property)

The **flex** property is an integer that defines the proportion of two or more blocks in a horizontal list. Using a banner example, we can show the same banner with three different pairs of flex values.

**1:1**

[![Banner with 1-1 flex ratio](https://docs.customer.io/images/in-app-advanced-banner-example-flex-1-1.png)](#a52279f3dad8c3b57c8cf490f8cc10bb-lightbox)

**3:1**

[![Banner with 3-1 flex ratio](https://docs.customer.io/images/in-app-advanced-banner-example-flex-3-1.png)](#0cfd0bd8113929e7b366b0db73155326-lightbox)

**9:1**

[![Banner with 9-1 flex ratio](https://docs.customer.io/images/in-app-advanced-banner-example-flex-9-1.png)](#4ed8d0fb0316ed5d3a7669974f35f7ee-lightbox)

#### Horizontal List[](#horizontal-list)

A **horizontal list** lays out components horizontally, letting you set the alignment of the items in the list. Nest content components within this layout to horizontally align them. Wrap these components in blocks for additional styling. The [flex property](#the-flex-property) of blocks can help you establish the ratio of space between each block in a horizontal list.

[![in-app-horizontal-list.png](https://docs.customer.io/images/in-app-horizontal-list.png)](#5c71fe28ff750ec8058a873fb1b2446d-lightbox)

 JSON

#### JSON[](#JSON)

```json
{
	"type": "fixedHorizontalListWidget",
	"mainAxisAlignment": "start",
	"crossAxisAlignment": "center",
	"components": [{},{}]
}
```

 schema

#### schema[](#schema)

*   type string
    
    Defines the widget type.
    
    Accepted values:`fixedHorizontalListWidget`
    

#### Vertical List[](#vertical-list)

While components in your message are typically displayed top-to-bottom, a **vertical list** helps you align these items. You can set up vertical lists to control the vertical layout of your message.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "fixedListWidget",
	"mainAxisAlignment": "start",
	"crossAxisAlignment": "center",
	"components": [{},{}]
}
```

 schema

#### schema[](#schema)

#### Carousel[](#horizontal-scroll-list)

A **carousel** is a list of items you can scroll hortizontally. One component displays at a time, and users can swipe left to right to see different components. A carousel takes up the entire width of the parent list, block, or grid.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "fixedHorizontalListScrollWidget",
	"height": 150,
	"components": [{},{}]
}
```

 schema

#### schema[](#schema)

*   height integer
    
    The height of the widget in pixels.
    
*   type string
    
    Defines the widget type
    
    Accepted values:`fixedHorizontalListScrollWidget`
    

#### Grid[](#horizontal-grid)

A **grid** is like a horizontal list, except that you can control the padding between elements and the aspect ratio of items in the grid. This allows you to customize your layout with tall, skinny grids or short, long grids. By default, a grid’s aspect ratio is `1.0`.

 JSON

#### JSON[](#JSON)

```json
{
	"type": "fixedGridWidget",
	"itemPadding": "xs",
	"columns": 2,
	"childAspectRatio": 1.5,
	"components": [{},{}]
}
```

 schema

#### schema[](#schema)

*   childAspectRatio number
    
    The aspect ratio for items in the grid. Defaults to 1.0
    
*   columns integer
    
    Required The number of columns in your grid.
    
*   itemPadding string
    
    The padding between items in your grid.
    
*   type string
    
    Required Defines the widget type.
    
    Accepted values:`fixedGridWidget`
    

#### Conditional[](#conditional)

Use a **conditional** to show or hide parts of your message based on a true/false condition.

There are three fields to complete when using a conditional component:

*   **Condition**: The function that you want to evaluate as “true” or “false”. The condition field supports: >, <, == & in. If you don’t specify an operator, the condition will check if the property is null.
*   **If True**: The components that you want to display when the condition is true.
*   **If False**: The the components that you want to display when the condition is false.

When building your message, entering `1 == 1` is an easy way to force the condition to true and `1 == 0` will force it to false. When you’re set with the design, replace the condition with `$properties.condition_field == MATCH-VALUE`. This adds a field called `Condition Field` to your in-app messages which you can then configure with static or dynamic values from the campaign or broadcast. If the value matches, the *True* section will show to the recipient. Otherwise, the *False* section will show.

[![Example in-app conditional](https://docs.customer.io/images/in-app-conditional.png)](#3873a3b1d293f01334c99aceaec764f0-lightbox)