Send in-app messages
How it works
Before you begin, make sure that you’ve incorporated our SDKs in your app or website depending on the platforms you want to support. People can’t receive in-app messages unless they visit your website or use a version of your app that incorporates our SDK.
You can send in-app messages as a part of any campaign or broadcast workflow. When you set up a message, you’ll select and populate a message. The message provides the general design of your message—colors, static text, etc. When you populate the message as a part of your workflow, you’ll customize:
- Text fields: 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}}
. to personalize the message for your audience - Expiry: this determines how long a message will wait for a person to open your app or visit your website (and visit the right page)
- Page rule: the page that a person has to look at to see your message
- Display and Position: where your message will appear on your audience’s screen


Once the message is sent, people will receive your in-app message as soon as they’re identified in your app or website, as long as the message hasn’t expired. By default, messages expire after 30 days, but you can change the expiration period to make sure that people don’t receive messages that are no longer relevant. You can also set page rules to determine the pages people must visit before they’ll see your message. Page rules can help you send targeted, relevant messages.
If a person has multiple devices, they’ll receive your message on their first eligible device.
in-app message]-->d{is the app open?} d-->|yes|f[user gets message] d-->|no|e[hold message
until app opens] e-->g{did the message
expire?} g-->|no, wait for user
to open the app|d g-->|yes|h[user doesn't
get the message]
Send an in-app message
Before you can use an in-app message in a workflowA series of actions (messages, attribute updates, etc) that people progress through as a part of a campaign or broadcast., you need to create it under Content > In-App Messages. If you haven’t already created a message, you’ll need to do that first.
- Drag In-App Message into your workflow.
- Select your message, give it a Name, and then click Add Content.
- Set your message settings:
- To: the value you use to identify people who use your app or your website. Contact your app or web developer if you’re not sure.
- Priority: negotiates between multiple messages with the same Page Rule.
- Position: determine where the message appears on the screen.
- Page Rule: determine the page(s) a person must be on to see your message.
- Display and Position: Select where you want your message to appear in your app or on your website. See Display and Position for more information about positioning your message.
- Pick the Message you want to send. Learn more about crafting in-app messages.
- Fill in your message Content, customizing your message for recipients. These fields are represented by
$<fieldTitle>
in your preview, and will update as you fill them in. Remember, 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}}
. in these fields! - Click Save Changes.
Targeting your audience: the “To” field
When you set up a message, the To field is the identifierThe attributes you use to add, modify, and target people. Each unique identifier value represents an individual person in your workspace.—email or ID—that your app uses to identify people in Customer.io. When a person in your campaign or broadcast is identified by the value in the To field, they’ll receive your message. If your app doesn’t identify people using the value you select, we won’t deliver your message to the person. Your messages will appear as Sent, but never Opened or Clicked.
Message Expiration
By default, in-app messages expire 30 days after they’re sent. If someone doesn’t open your app within the expiration period after the message is sent, they won’t get your message.
However, many messages are more time-sensitive. For example, you wouldn’t want to send someone an expired coupon code. To prevent people from receiving old messages, make sure that you change the Expiration for your message. You can set a static expiration window or 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}}
. to configure the expiration date based on an event property, profile attribute, trigger variable, or snippet.
For longer-living messages, the maximum expiration window is 60 days.
Message Priority
Priority determines the order of messages sent to a person. If you send multiple messages before the next time a person opens their app, we’ll display messages in the priority order—highest to lowest.
You can avoid competing messages using Page Rule triggers. Page rules cause messages to appear when a person visits specific pages in your app or website, helping you deliver messages that are relevant to the pages your audience visits.
Page Rule
Page rules determine the platform a person must be on and the page(s) or screen(s) a person must visit on your website or app to see a message. They help you send messages that are relevant to the places your audience visits and the things they do.
By default, your audience will see your message on the first page or screen they visit. Check a platform to enable it and exclude un-checked platforms. Then you can set the page(s) or screen(s) a person must visit to see your message or 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}}
. to configure the page value based on an event property, profile attribute, trigger variable, or snippet.


A “page” is means something different for your mobile apps and website. In both cases, you can pass *
as a wildcard to show your message on multiple pages!
- Mobile Apps (iOS and Android): the page is the same as the
name
value that you send inscreen
events. For example,billing*
would cover all screens in your app that begin with “billing”. - Websites: the page is the URL (
window.location.href
) unless you passpage
calls with a different name parameter. For example,https://example.com/*/billing
would cover paths on your website like your in-app billing pagehttps://example.com/ui/billing
or documents about billing underhttps://example.com/docs/billing
.
Use *
to represent all pages
When you select a channel, you have to enter a page rule. But, if you want to show a message on every page on your website or app, you can simply enter *
.
If your website is a single page application you must send page
calls to tell Customer.io what “page” a person is on.
You might use page rules to point out new features within specific areas of your app or new products on your website and you can even 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}}
. to set a dynamic value (like {{event.product_url}}
). Page rules also help avoid conflicting messages. If you send two messages of the same priority without page rules, they’ll appear one after the other; if you set a page rule for at least one message, it’ll distribute the messages across your app, and only show when your audience is on a page matching the rule.
Positioning your message
The Display and Position settings help you determine where your message appears to users. Pick your Display option and then pick the position for your message.
Some options are exclusive to web in-app messages and won’t work on mobile devices. For example, using an Overlay option effectively limits your message to your website visitors because mobile apps won’t display the message.
Display setting | iOS | Android | Web |
---|---|---|---|
Modal | |||
Overlay | |||
Inline |


Modal positioning works for both mobile and web apps. You can position your message on at the top, in the center, or at the bottom of your audience’s screen.
Overlay positioning is specific to web in-app messages. Your message appears in the location you select, relative to your audience’s browser. For example, on a wide-screen monitor, a bottom-right positioned message will appear in the bottom right.
Inline positioning is only for web in-app messages. With inline positioning, you provide the id
of an element that you want to replace with your message. For example, if you wanted to highlight a new button on your website, you could place an empty placeholder element with an ID directly below the new button and use your message to replace to the empty element and highlight to your button.
For mobile apps, you have to handle inline positioning with your own code, or your message won’t be displayed.
We don’t retry messages that can’t be displayed on apps
Apps don’t handle website-only display methods. If you set up your message with a website-only display setting, and don’t use page rules to limit your message to your website, anybody who logs into your app before your website won’t see your message; Customer.io will not retry your message either.
We’re working to change this behavior. In the meantime, you can limit your message to web or mobile only using page rules.
Limit your message to web or mobile audiences
By default, when you set up an in-app message, your audience can see your message in your app or on your website—anywhere you’ve integrated in-app notifications. You can limit your message to specific message channels using page rules.
By default, all the page rule boxes are unchecked, and your audience will see your message on the first page or screen they visit on your website or app.


When you check a box, you automatically exclude un-checked channels. For example, if you want to send a message to your web visitors but not iOS or Android devices, you can check the Web box.
When you select a channel, you must enter a page rule; an empty rule is invalid. You can, however, use a wildcard (*
) to show your message on the first page or screen people. You can set a specific page URL or use a path with a wildcard to limit the pages or screens people must visit to see your message.


Segmenting an audience of app users
When you set up your campaign, you may also want to make sure your segment includes, or filters for, people who have a version of the SDKs supporting in-app messages. If someone in your audience doesn’t have a version of your app that supports in-app messages, they’ll never receive your in-app messages. Messages intended for them will be sent
, but never opened
, which can produce inaccurate metrics.
Our SDKs have implemented in-app messages in different versions. So, if you create segments or filters for this purpose, you should group platform AND cio_sdk_version
conditions:


Use filters for event triggered campaigns
If you send an in-app message as a part of an event-triggered campaign, you might want to use a segment to exclude people who don’t have versions of your app supporting in-app messages.
Test your in-app message
When you set up a message as a part of a campaign, you can send a test to make sure that your message looks and behaves the way you expect it to.
Click Send test… and enter the email or ID—corresponding to your message’s To field—of the person you want to send a test to.
If your test looks good, then you’re all set to send! If not, you can edit your message and send more tests to check your work.
In-App FAQs
Can I stop an in-app message after it’s sent?
In most cases, you can’t stop messages after they’re Sent. You’ll want to set an Expiration period for your messages to make sure that your messages expire when they’re no longer useful.
However, if you’re willing to stop a campaign, you can use the Exit Immediately option to cancel in-app messages that have been sent but not opened. Note that stopping messages in this way only works for in-app messages. You can’t stop other kinds of messages in this same way.


You will cancel in-app messages that have been “Sent” but not “Opened” when you:
- Delete an in-app action from a campaign workflow. This recalls any unopened messages associated with the action.
- Delete a campaign containing in-app messages. This recalls any unopened in-app messages sent by the campaign.
- Stop a newsletter that was in-progress. This recalls any unopened in-app messages sent by the newsletter.
- Delete a newsletter. This recalls any unopened in-app messages sent by the newsletter.
- Delete an API Triggered broadcast containing an in-app message. This recalls any unopened in-app messages sent by the broadcast.
- Disable in-app messaging for your workspace. This recalls any unopened in-app messages for the entire workspace.
How do in-app messages handle unsubscribes?
In-app messages ignore our standard unsubscribed
attribute. People can’t unsubscribe from in-app messages unless you give them that option through a custom subscription center with an attributeA key-value pair that you associate with a person or an object—like a person’s name, the date they were created in your workspace, or a company’s billing date etc. Use attributes to target people and personalize messages. that you use with segmentsA group of people who match a series of conditions. People enter and exit the segment automatically when they match or stop matching conditions. to prevent your messages from going to people.
Abusing in-app messages can cause your audience to ignore your messages or delete your app. When you set up in-app messages, be conscious of the frequency and relevance of the messages you send. To make sure that you don’t over-message your audience, you might:
- Set up page rules to ensure that your messages are relevant to the pages/screens your audience visits.
- Set up delays between in-app messages in campaigns.
- Filter people out of campaigns if they received messages or other campaigns within the same time frame.
What happens if a person doesn’t have a version of my app that supports in-app messages?
If you send a message to a person who hasn’t updated their app to a version supporting in-app messages, your message will appear as sent
, but will never be opened
. If you want to filter out people who can’t yet receive your messages, you can set up a segment to target people with an appropriate version of the Customer.io SDK.
Why are my messages delayed? How do I send real-time in-app messages?
When a message is “sent” from Customer.io, our SDKs fetch them and store them on the device, and they’ll show in real time when customers match the the page rule(s) specified in the message. But event-triggered messages aren’t sent until a person performs an event, meaning that our SDKs don’t prefetch them. The round-trip traffic between the device-side event, starting a campaign, and fetching a message results in a delay between when a person triggers a message and when it appears in your app.
If you want messages to appear in real-time, you can trigger your messages in advance using any other campaign or broadcast, so that your messages are stored locally. If you use page rules you can display messages immediately based on your audience’s activities in your app rather than waiting for an event trigger your message.
- Use a campaign or broadcast to trigger the message(s) to your target audience. Set up each in-app message with a custom page rule determining it will appear.
- When a user opens your app, all in-app messages with the
Sent
status will be retrieved and saved in the device’s local storage, waiting for the user to visit the right page or screen. - When the user goes to the page/screen defined in a message’s page rule, they’ll immediately trigger the in-app message, retrieving it from local storage. If your use case doesn’t have a target page, use a custom page or screen view instead to force the in-app message to show. This call is processed client-side and cause the in-app message to show immediately.
In the long term, we plan to extend the prefetching functionality to events so that we automatically store event-triggered messages on devices and they’re ready to display when the event is triggered. In the interim, use page rules for real-time display.