# In-app messages

When you use our JavaScript client, you can send in-app messages to your website visitors. This page helps you understand how some in-app features work so that you can better target and display messages.

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

In-app messages for your website work differently than push notifications would: they require JavaScript, and they don’t go through a push notification service (like APNs or FCM).

In most cases, you simply need to `identify` your web visitors, and they’ll become eligible to receive your in-app messages.

## Send an in-app message[](#send-an-in-app-message)

To send an in-app message, you’ll need to do the following things. Because most of these things happen outside the SDK, we’ve linked to relevant documentation.

1.  [Enable in-app messaging](#enable-in-app-messaging)
2.  [Set up message templates](/journeys/in-app-messages/)
3.  [Add in-app messages to your campaigns or broadcasts](/journeys/send-in-app-message/#send-an-in-app-message)
4.  In most cases, you’ll need to [identify visitors to your website](/integrations/data-in/connections/javascript/method-reference/#identify) before they can receive an in-app message.

## Enable in-app messaging[](#enable-in-app-messaging)

To set up in-app messages with our JavaScript client, you only need to enable in-app messaging in your workspace. When you have in-app messaging enabled, we’ll automatically load the in-app messaging plugin on pages containing your JavaScript snippet.

1.  Go to [**Settings** > **Workspace Settings**](https://fly.customer.io/env/last/settings) and click **Get Started** next to *In-App*.
    
2.  Click **Enable in-app**.
    
3.  (Optional) Click **Send Test** and enter the email address or ID of a test user to prove your implementation. If this is your first in-app message, it might take a minute for it to appear and you might need to refresh the page where you expect to see your test message.
    
    When you send your first message, we poll slowly for messages (about once a minute). When you receive your first message, polling speeds up, eliminating the delay.
    

### Add support for anonymous messaging[](#add-support-for-anonymous-messaging)

If you want to send in-app messages to people who aren’t identified, you’ll need to add an `anonymousInApp` flag to your snippet. This lets you support anonymous messaging. See [Anonymous in-app messages](/journeys/anonymous-in-app/) for more information.

```javascript
!function(){var i="cioanalytics", analytics=(window[i]=window[i]||[]);if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute('data-global-customerio-analytics-key', i);t.src="https://cdp.customer.io/v1/analytics-js/snippet/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._writeKey=key;analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.15.3";
    analytics.load("YOUR_CDP_API_KEY", 
    {
        "integrations": {
            "Customer.io In-App Plugin": {
                anonymousInApp: true
            }
        }
    });
    analytics.page();
}}();
```

## Listen to in-app message events[](#listen-to-in-app-message-events)

We expose in-app message events that you can listen for and respond to—performing additional functions in response to a person interacting with or dismissing your message.

You’ll define functions handling each event type in an `events` key when you initialize the SDK. These events all have a `detail` object containing additional data about the event, like the `deliveryId` or `messageId` that you can act on.

```javascript
analytics.load(
    "CDP_WRITE_KEY",
    { 
        "integrations": {
            "Customer.io In-App Plugin": { 
                siteId: "YOUR_SITE_ID",
                events: function(event) {
                    switch (event.type) {
                        case "in-app:message-opened":
                            // do something when a message is opened
                            break;
                        case "in-app:message-dismissed":
                            // do something when a message is dismissed
                            break;
                        case "in-app:message-action":
                            // do something when a message is interacted with
                            break;
                        case "in-app:message-error":
                            // do something when a message errors
                            break;
                        case "in-app:message-changed":
                            // do something when a user moves to the next step in a multi-step message
                            break;
                    }
                }
            }
        }
    }
);
```

If you set up our JavaScript client by importing the `@customerio/cdp-analytics-browser` package, [learn more about listening for in-app message events](/integrations/data-in/connections/javascript/js-source/#import-the-javascript-client).

### Events and examples[](#events-and-examples)

You can listen for the following in-app events:

*   **Message opened:** this happens when your message is displayed to a person.
*   **Message dismissed:** happens when someone dismisses your message. Remember, dismissing a message doesn’t necessarily mean that a person didn’t respond; dismissing a message often happens when someone responds to a message too.
*   **Message action:** these are the things that happen when a person interacts with your message
*   **Message error:** respond when something goes wrong with your message.
*   **Message changed:** respond when someone engages the next step in a multi-step message. See [Multi-step messages](/journeys/multi-step/) for more information.

Each event has a `detail` object containing additional data about the event, like the `deliveryId` or `messageId` that you can act on. For the `message-action` event, we also expose the `actionName` and `actionValue`.

```json
{
    // one of: "in-app:message-opened", "in-app:message-dismissed", 
            // "in-app:message-action", "in-app:message-error"
    "type": "in-app:message-action",
    "detail": {
        "deliveryId": "1234567890",
        "messageId": "1234567890",
        // only for "in-app:message-action and in-app:message-changed"
        "actionName": "action name", // for message-changed, this is the name of the next step
        "actionValue": "action value"
    }
}
```

## Page rules and in-app messages[](#page-rules-and-in-app-messages)

**[Page rules](/journeys/send-in-app-message/#page-rule)** help you determine the pages where people can encounter your messages, ensuring that they’re relevant to the pages people visit on your website.

Page rules also help avoid conflicting messages by distributing messages to the pages where they’re most relevant to your audience. If you send two messages of the same priority without page rules, they’ll appear one after the other.

[![set in-app page rules to determine the page your message appears on](https://docs.customer.io/images/in-app-page-rule.png)](#a55af0f9917c15a7b484c9df200f448d-lightbox)

When you set a page rule for the *Web* platform, we use the page URL unless you pass `page` calls with a different `name` parameter.

For example, an *include* rule for `https://example.com/*/billing` allows a message to appear on `https://example.com/ui/billing` or documents about billing under `https://example.com/billing`. You can also match on a query parameter in the URL using the *contains* operator. See the [page method reference](/integrations/data-in/connections/javascript/method-reference/#page) for more information.

 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 `*`.

### Page rules for single-page applications[](#page-rules-for-single-page-applications)

The JavaScript snippet automatically sends page calls when it loads. But if you import/bundle the JavaScript SDK, or have a single page application (SPA), you’ll need to [call `cioanalytics.page()` manually for each page or route](/integrations/data-in/connections/javascript/method-reference/#page).

This tells the SDK what “page” a person is on so you can target in-app messages to people on certain pages of your app.