Design In-App Messages with HTML

How to Design an In-App Messages with the OneSignal HTML Composer

1700

Image illustrating code in-app code beside a rendered in-app

In order to design your in-app message we provide two editor experiences: Our Drag and Drop GUI and our new HTML Editor. Our HTML editor allows for a fully customizable in-app messaging experience.

You now have complete control over the look and feel of your full-screen in-app messages, and the power to create in-app messages that are a seamless extension of your app. A few things you can now do by using in-app HTML:

  • Layouts: Have complex layouts incl. buttons side by side
  • Media: Embed videos, animations, and other forms of media such as slide decks
  • Device Responsiveness: Design for portrait, landscape and different device sizes
  • Forms: Add forms to your in-apps
  • Fonts: Add any font to align with your branding.

This new HTML editor is meant for users who are fluent in HTML and CSS to create mobile-responsive in-app messages. For non-technical users, the existing drag-and-drop editor will be a better fit. Our HTML Editor allows you to customize your in-app messages using HTML, CSS, and Javascript.

Getting Started

To get the best of our in-app message HTML, we recommend you use the following SDK versions, which have introduced our new true Full Screen:

  • iOS: 3.9.0
  • Android: 4.6.3

If your subscriber's app uses an older version of the SDK and has not been able to upgrade their app yet, then the in-app HTML will render in a Center Modal.

Tips:

  • Older App Versions: If some of your users are on an old app, then use our Segmentation tool to target older apps with in-apps using the GUI and new apps with in-app HTML.
  • Get Started with one of our templates: Get a quick start with one of our templates or copy them into the HTML editor directly from GitHub.

Step 1. Creating an In-App

Navigate to Messages > New In-App to create, view, edit, pause/resume, duplicate and delete your in-app messages.

Step 2: Using the In-App HTML Editor

Enter your code on the left-hand side of the screen. Press Send Test In-App to ensure your in-app renders correctly across devices.

Image showing the HTML Editor beside the preview

Image showing the HTML Editor beside the preview

👍

Get a quick start with a template

HTML Templates are available in our GitHub.


Key Features with the In-App HTML Editor

1. Click Support

Our In-App JS Library allows you to leverage key functionalities whilst creating your in-app with our HTML Editor.

In order to use Click Support, you need to specify the following:

  1. data-onesignal-unique-label - add this to the elements you are wanting to track, with a unique label. For example.

<button class="tag-user" data-onesignal-unique-label="my-tag-user-button">Tag User</button>

  1. QuerySelector - call actions based on when a user has clicked or engaged with your in-app
document.querySelector(".tag-user").onclick = (e) => {
        OneSignalIamApi.tagUser(e, { fiz: "baz" });
      }

📘

In-App JavaScript Library

Please see In-App JS Library for more details.

2. Asset Support

With HTML, we support the loading of a wide variety of assets, including fonts, images, videos, and anything else imaginable with HTML. Assets of HTML are loaded upon the point of rendering the in-app.

Example of loading Image from URL:

<img src="https://media.onesignal.com/iam/default_image_20200320.png" />

3. Tag Substitution

Personalize your in-apps designed with HTML using tag substitution. This allows you to substitute tags with data tags containing user information, such as the user's name. Read more about Personalization. A simple example is as follows:

<div>Hi there {{ name | default: 'you' }}!</div>

In the above snippet, name is the users name being the data tags key, with you being the default if this data tag is not set.

Tag substitution will work for:

  • Text displayed to the end user (text within a div, p, li, etc)
  • In <style> tags (i.e. body { background-color: "{{ favorite_color | default: '#fff' }}"; }
  • HTML element attributes which take a url
  • Elements with an href attribute
  • Elements with a src attribute
  • Action attribute on <form>
  • Data attribute on <object>

Tag substitution will not work for:

  • <script> tags
  • text in an element that has other children, i.e.:
<div>
  Hi there {{name}}
  <span>Here's your coupon!</span>
</div>

Best Practices of In-App HTML

1. Design Responsively

In order to ensure your in-app works across devices, you’ll need to ensure your design and code responsively. Responsive in-apps can leverage media queries to alter the in-app’s layout, text size, images, buttons, and the inclusion or exclusion of content across devices.

A CSS media query, or @media, is a group of styles that act as conditional rules for how in-app renders across devices. By embedding media queries in CSS, designers and developers can introduce new layouts for each resolution range, which can change how the layout appears on different devices, for example.

@media only screen and (max-width: 620px) {
  .btn-primary {
    width: 100% !important;
  }
}

2. Test Across Devices

Frequently send your in-app to multiple devices to ensure your in-app is behaving responsively and as expected.

3. Add Alt Tags to Images

To ensure your in-app is accessible, add alt tags to all images. An alt tag ensures that there is text for screen readers on mobiles.

4. Name and Format your HTML

It's important to ensure you correctly name HTML elements and format your HTML. This ensures the message is accessible for screen readers often used by a person who has a visual impairment or cognitive disability.

5. Design for Notches (aka safe-areas)

Many phones now have notches. The term 'notched display' refers to a smartphone screen that features an irregular shape due to a cutout on one of the device's edges. Notches on the top of a phone are one example of a safe-area, however others include sidebars or navigation at the bottom. Be sure to design and develop your in-app to account for these areas so that they do not cover critical information. To better facilitate your ability to do this our OneSignal SDK detects these safe areas and exposes them to the in-app's HTML document via safe-area-inset-* CSS variables. You can also use the css calc function to add extra spacing on top of the provided safe-area-inset values 👇

body {
  padding-top: var(--safe-area-inset-top);
  padding-right: var(--safe-area-inset-right);
  padding-bottom: calc(var(--safe-area-inset-bottom) + 20px);
  padding-left: var(--safe-area-inset-left);
  margin: 0;
}

6. Optimize Images for Mobile

Images can both improve the aesthetic and increase engagement levels within your app. We recommend you optimize your image sizes using a tool such as imagekit.io*. We also recommend delving into the following guidelines.

Image Size and Resolution for iOS by Apple
Images and Graphics Overview for Android


Sample In-App

We provide a default in-app HTML when loading the HTML Editor as a way to get started quickly. This includes a range of methods defined in our In-App JS Library, that you can use within your in-app.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Onesignal In-App Message</title>
    <style>
      body {
        margin: 0;
        padding-top: var(--safe-area-inset-top);
        padding-right: var(--safe-area-inset-right);
        padding-bottom: calc(var(--safe-area-inset-bottom) + 20px);
        padding-left: var(--safe-area-inset-left);
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
        display: flex;
        align-items: center;
      }

      .center-modal {
        position: relative;
        background: #FFF;
        margin: 18px;
        padding: 24px;
        border-radius: 8px;

        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        height: 85%;
        width: 100%;
        box-shadow: rgb(0 0 0 / 30%) 0px 0px 12.5px, rgb(0 0 0 / 15%) 0px 0px 2.5px;
      }

      .center-modal .close-button {
        position: absolute;
        top: 0;
        right: 0;
        background: rgba(0, 0, 0, 0);
        border: none;
        z-index: 1;
        display: flex;
        justify-content: center;
        flex-direction: column;
        align-items: center;
        /* Tip: Make your close-button relatively large so it's easy to click */
        min-width: 48px;
        min-height: 48px;
      }

      .center-modal img {
        width: 100%;
        min-height: 10px;
        margin-bottom: 12px;
        width: 100%;
        height: 100%;
        object-fit: contain;
      }

      .center-modal h1 {
        margin: 0px;
        margin-bottom: 12px;
        color: #222;
        font-size: 24;
        font-style: normal;
        font-weight: normal;
        text-align: center;
        text-decoration: none;
      }

      .center-modal button {
        font-size: 16px;
        color: #fff;
        background-color: #1F8FEB;
        width: 100%;
        padding: 12px;
        border-radius: 4px;
        border: none;
        margin-bottom: 12px;
      }

      .button-container {
        display: flex;
        flex-direction: column;
      }

      @media screen and (min-width: 480px) {
        .button-container {
          flex-direction: row;
          grid-gap: 12px;
          width: 100%;
        }

        .button-column {
          width: 50%;
        }

        .center-modal {
          height: 80%;
        }
      }
    </style>
  </head>

  <body>
    <div class="center-modal">
      <div class="close-button" data-onesignal-unique-label="close-button">
        <svg width="10" height="10" preserveAspectRatio="none" viewBox="0 0 8 8" fill="none"
          xmlns="http://www.w3.org/2000/svg">
          <path
            d="M7.80309 1.14768C8.06564 0.885137 8.06564 0.459453 7.80309 0.196909C7.54055 -0.0656362 7.11486 -0.0656362 6.85232 0.196909L4 3.04923L1.14768 0.196909C0.885137 -0.0656362 0.459453 -0.0656362 0.196909 0.196909C-0.0656362 0.459453 -0.0656362 0.885137 0.196909 1.14768L3.04923 4L0.196909 6.85232C-0.0656362 7.11486 -0.0656362 7.54055 0.196909 7.80309C0.459453 8.06564 0.885137 8.06564 1.14768 7.80309L4 4.95077L6.85232 7.80309C7.11486 8.06564 7.54055 8.06564 7.80309 7.80309C8.06564 7.54055 8.06564 7.11486 7.80309 6.85232L4.95077 4L7.80309 1.14768Z"
            fill="#111111" />
        </svg>
      </div>
      <h1>Heading</h1>
      <img src="https://media.onesignal.com/iam/default_image_20200320.png" />
      <div class="button-container">
        <div class="button-column">
          <button class="tag-user" data-onesignal-unique-label="my-tag-user-button">Tag User</button>
          <button class="push-prompt" data-onesignal-unique-label="my-push-prompt-button">Prompt Push</button>
          <button class="location-prompt" data-onesignal-unique-label="my-location-prompt-button">Prompt Location</button>
        </div>
        <div class="button-column">
          <button class="add-click-name" data-onesignal-unique-label="my-add-click-name-buton">Add Click Name</button>
          <button class="send-outcome" data-onesignal-unique-label="my-send-outcome-button">Send Outcome</button>
        </div>
      </div>
    </div>
    <script>
      // Your code here
      document.querySelector(".close-button").onclick = (e) => {
        OneSignalIamApi.close(e);
      }
      document.querySelector(".tag-user").onclick = (e) => {
        OneSignalIamApi.tagUser(e, { fiz: "baz" });
      }
      document.querySelector(".push-prompt").onclick = (e) => {
        OneSignalIamApi.triggerPushPrompt(e);
      }
      document.querySelector(".location-prompt").onclick = (e) => {
        OneSignalIamApi.triggerLocationPrompt(e);
      }
      document.querySelector(".add-click-name").onclick = (e) => {
        OneSignalIamApi.addClickName(e, "test_click_name");
     }
      document.querySelector(".send-outcome").onclick = (e) => {
        OneSignalIamApi.sendOutcome(e, "test_outcome");
      }
    </script>
  </body>
</html>

FAQ

How can I use my existing In-App templates from other providers?

If you have an existing in-app template from another provider, feel free to copy and paste it into our HTML editor. Don’t forget to you’ll need to make adjustments to use our In-App JS Library to add tags and outcomes and to gather click analytics. Note that some functionality other providers have may not be cross-compatible with OneSignal.

We also provide HTML templates to get you started.

I don't have any existing templates. How can I get started with HTML for In-App?

For now, we provide a sample in-app using HTML to help get you started. However, we do advise that you have experience with developing responsive HTML to ensure your in-app works across devices.

What SDK version do I need for in-app HTML? What will my user's experience be on an older SDK?

To get the best of our in-app HTML, we recommend you use the following SDK versions, which have introduced our new true Full Screen:

  • iOS: 3.9.0
  • Android: 4.6.3

If the user has not updated their application, so they are on an older SDK, they will still receive the in-app message, but it will have margins by default.

Can I access local assets?

Currently, you will not be able to access local assets and files within your application within an in-app message. Let us know if you’d be interested in this feature [email protected]

What happens to an In-App if the user is not connected to the internet?

We only show and fetch content when the user is connected to the internet. This ensures the in-app can fetch content correctly, which minimizes the user seeing a broken in-app with resources that are unable to load.


  • OneSignal does not have any affiliation with imagekit.io. There are alternative providers with similar services.