# Create in-app messages in the built-in editor

Build an in-app message template in the Pushwoosh built-in editor without writing code. You get a reusable layout with content blocks, images, buttons, and personalized text that you can show in a Customer Journey, as a one-time in-app, or from a push.

<Aside type="note">
Before you start, integrate the Pushwoosh SDK so in-app messages can appear in your app. [Learn more](/product/messaging-channels/in-apps/)
</Aside>

## Create a new in-app template

An in-app template is a reusable design you create once and then show to users in campaigns. You can create one by uploading a custom HTML ZIP or by building it in the built-in editor. This article covers creating a template from scratch in the built-in editor. Follow the same steps to customize an existing template.

1. Go to **Content** → **In-apps**.
2. Click **Add template**.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-1.webp" alt="Content In-apps page with the Add template button in the top right of the templates list"/>

3. Enter a template name.
4. Choose how to create the template:
   * **Upload ZIP:** [upload a ZIP file](/developer/guides/content/rich-media-templates-syntax) with your HTML in-app message.
   * **Create new template:** build a template in the built-in editor.
5. Select **Create new template**.
6. Click **Add template**.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-2.webp" alt="New template form with name field, Upload ZIP option, and Create new template selected"/>


### Explore the editor layout

The built-in editor has four areas. Each one has a clear job.

**Top bar**

Use the top bar to rename the template, undo mistakes, save your work, or open **In-app settings** when you need to change how the message appears on the device. See [Configure how the in-app looks on device](#configure-how-the-in-app-looks-on-device).

<img src="/rich-media-create-rich-media-in-the-built-in-editor-3.webp" alt="Top bar of the in-app editor with template name, Undo, Redo, In-app settings, and Save"/>

**Canvas**

Use the canvas to see the message as users will see it and to edit text, images, and buttons directly on the layout. An empty template shows **Start with a block**. Above the canvas, a phone/tablet toggle switches the preview width — it doesn't change your layout, just how wide a screen you're previewing it on.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-4.webp" alt="Empty canvas in the in-app editor with the Start with a block prompt in the center" width="480"/>

**Layers**

The Layers panel lists every block in your template as a tree, in the same order as on the canvas. Open it from the left edge when you want to select a nested block (for example, a button inside a group) or drag rows to change the order of content.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-5.webp" alt="Layers panel listing Card, Image, Heading, Text, Timer, Buttons, and Footer in a tree"/>

**Right panel**

Use **Blocks** in the right panel to add content to the message, and **Settings** when you want styling that applies to the whole template at once. See [Configure template-wide styling](#configure-template-wide-styling).

<img src="/rich-media-create-rich-media-in-the-built-in-editor-6.webp" alt="Blocks tab in the right panel with Heading, Text, Button, Image, and other content blocks" width="320"/>

### Start building the template

After you create a template, the editor opens with an empty canvas and the **Blocks** tab on the right.

1. Drag a block from the **Blocks** panel onto the canvas, or click a block in the panel to add it.
2. Keep adding blocks the same way until the layout is ready.
3. Open the **Settings** tab when you need template-wide styling.


<img src="/rich-media-create-rich-media-in-the-built-in-editor-7.webp" alt="Empty in-app editor with Start with a block on the canvas and the Blocks panel open"/>

### Add content blocks

Content blocks are the building pieces of an in-app template in the built-in editor. You combine headings, text, images, buttons, and other blocks into one layout.

Open the **Blocks** tab and drag a block onto the canvas, or click a block to add it. Available blocks:

* **[Heading](#heading-and-text):** titles and short headlines in the message
* **[Text](#heading-and-text):** body copy and longer descriptions
* **[Button](#button):** a tappable call to action
* **[Image](#image):** pictures from [Media store](/product/content/media-store/), upload, or URL
* **[Divider](#divider):** a line that separates sections visually
* **[2 columns](#columns):** two equal columns side by side
* **[3 columns](#columns):** three equal columns side by side
* **[4 columns](#columns):** four equal columns side by side
* **[33 / 67](#columns):** two columns where the left takes about 33% of the width and the right about 67%
* **[67 / 33](#columns):** two columns where the left takes about 67% of the width and the right about 33%
* **[Timer](#countdown-timer):** a countdown for offers and deadlines
* **[Menu](#menu):** a row or column of links, such as navigation or contacts
* **[Social](#social):** icons that link to your social profiles
* **[HTML](#html):** custom HTML, such as a form or embedded video

### Heading and text

**Heading** and **Text** blocks hold the copy users read in the in-app message. Edit the text on the canvas and format it with the toolbar.

Click a **Heading** or **Text** block to edit its copy on the canvas. Select some text to bring up the formatting toolbar: bold, italic, underline, alignment, a link button, and a **text style** dropdown.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-8.webp" alt="Heading block selected on the canvas with the text formatting toolbar showing style and formatting options"/>

Merge Tags are placeholders that insert a [Tag](/product/audience-data-and-segmentation/user-data-tags/tags/) value from the user’s profile into the message, so each subscriber sees personalized copy. To add one, select the text, click **Merge Tags** in the toolbar, and choose a Tag from your account. [Learn more about personalized in-app messages](/product/how-to-guides/how-to-send-a-personalized-message/how-to-send-a-personalized-in-app-message/)


### Image

An **Image** block displays a picture in the in-app template. Select it on the canvas to open the **Image** settings in the right panel.

* **Add image** / **Replace image:** click **Add image** when the block is empty, or **Replace image** when a picture is already set. You can upload a file or pick one from your [Media store](/product/content/media-store/).
* **Image URL:** paste a hosted link to the image.
* **Alt text:** describe the image for accessibility.
* **Link URL:** open a website when the image is tapped.
* **Link target:** open the link in the same tab or a new one.
* **File:** after you add an image, shows the path of the file in use.

In **Spacing**, turn on **Padding** to add space around the image. Use **All sides** for the same padding on every side, or turn on **More options** to set each side separately.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-9.webp" alt="Empty Image block on the canvas with Image settings showing Add image, Image URL, Alt text, Link URL, and Spacing" width="600"/>

### Button

A **Button** is a tappable call to action in the in-app message. Use it to open a URL, run custom JavaScript, or close the message.

Click a **Button** block to edit its label on the canvas. Use the toolbar to change font size, text color, bold, italic, underline, and alignment.

To set what happens when the user taps the button:

1. Click the link icon in the toolbar to open **Insert/Edit Link**.
2. Choose an **Action type**.
3. Fill in the fields for that action (see below).
4. Click **Save**.

#### Open a website

**Open Website** opens a link when the user taps the button. Enter the address in **URL**. What you can enter:

* A website: `https://example.com`
* An app link that opens a screen inside your app: `myapp://promo`
* Close the in-app without JavaScript: `pushwoosh://close`

<img src="/rich-media-create-rich-media-in-the-built-in-editor-10.webp" alt="Insert Edit Link dialog for a Button with Action type Open Website and a URL field"/>

#### Run custom JavaScript

**Custom Javascript** runs code when the user taps the button. Enter the code in the **onClick** field.

Use it when a tap should do something in Pushwoosh, not only open a link. The person in the app still sees a normal button. They do not see tags or events. You decide what happens next on screen: leave the message open, or close it in the same **onClick**.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-11.webp" alt="Insert Edit Link dialog for a Button with Action type Custom Javascript and onClick set to closeInApp"/>

**Available methods in onClick**

* `pushwoosh.closeInApp()`: close the in-app message. Omit it to keep the message open after the tap.
* `pushwoosh.sendTags({...})`: save values as [device tags](/product/audience-data-and-segmentation/user-data-tags/tags/) for later campaigns.
* `pushwoosh.postEvent(...)`: send a [custom event](/product/audience-data-and-segmentation/events/custom-events/), for example to start a Customer Journey.
* `pushwoosh.getTags(...)`: read current tags. Useful in custom HTML to change what the message shows.
* `pushwoosh.getCustomData()`: read custom data passed from the push that opened this in-app.

##### Example: let users pick an interest and save it for later campaigns

1. Add a question in a **Text** or **Heading** block, for example: "Which sport are you into?"
2. Add one **Button** per option, for example: **Yoga** and **Gym**.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-12.webp" alt="In-app template with Yoga and Gym buttons and Custom Javascript onClick for the Yoga button"/>

3. Set **Action type** to **Custom Javascript** for each button.
4. For the **Yoga** button, paste this into **onClick**:

```js
pushwoosh.sendTags({ interest: "yoga" });
pushwoosh.closeInApp();
```

5. For the **Gym** button, paste this into **onClick**:

```js
pushwoosh.sendTags({ interest: "gym" });
pushwoosh.closeInApp();
```


When the user taps **Yoga**, Pushwoosh writes the `interest` tag on their device and closes the in-app. You can then target that user in a [segment](/product/audience-data-and-segmentation/segmentation/) or [Customer Journey](/product/customer-journey/journey-elements/#in-app).

<LinkCard title="Learn more about how to create in-apps with JavaScript" href="/developer/guides/messaging-channels/inapp-with-javascript/" />

### Divider

A **Divider** is a horizontal line between content blocks. Use it to separate sections visually in the template.

Configure **line style** (Solid, Dashed, Dotted), **color**, **thickness**, and **width** in the settings panel.

### HTML

The **HTML** block lets you paste custom HTML into an in-app template. Use it for a custom form, survey, or embedded video when there is no dedicated Form block for in-app messages.


##### Examples

The examples below show common ways to use the HTML block in an in-app template: a lead form, a survey, and an embedded video.

<Aside type="note">
The form and survey examples save device tags and send events through Pushwoosh. Create the custom events in your account before you use them in campaigns.
</Aside>

<Tabs>
<TabItem label="Lead form">

This lead form writes name and email as tags, sends a `promo_requested` event, shows a thank-you message, then closes the in-app.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-13.webp" alt="HTML lead form in the in-app editor with name and email fields and a Send me the code button" width="360"/>

<details>
<summary>HTML code</summary>

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
  body { margin: 0; padding: 20px; font-family: Arial, sans-serif; }
  h2 { font-size: 18px; margin-bottom: 8px; color: #222; }
  p { font-size: 14px; color: #666; margin-bottom: 20px; }
  input {
    width: 100%;
    padding: 12px;
    margin-bottom: 12px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 15px;
    box-sizing: border-box;
  }
  button {
    width: 100%;
    padding: 14px;
    background: #FF6B35;
    color: white;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
  }
  .thanks { display: none; text-align: center; padding: 40px 0; font-size: 18px; color: #333; }
</style>
</head>
<body>

<h2>Get your 20% discount</h2>
<p>Leave your name and email — we'll send the promo code right away.</p>

<div id="form">
  <input type="text" id="name" placeholder="Your name" />
  <input type="email" id="email" placeholder="Your email" />
  <button onclick="submit()">Send me the code</button>
</div>

<div class="thanks" id="thanks">
  🎉 Done! Check your inbox for the promo code.
</div>

<script>
function submit() {
  const name = document.getElementById('name').value.trim();
  const email = document.getElementById('email').value.trim();
  if (!name || !email) return;

  pushwoosh.sendTags({ name: name, email: email });
  pushwoosh.postEvent("promo_requested", { email: email });

  document.getElementById('form').style.display = 'none';
  document.getElementById('thanks').style.display = 'block';
  setTimeout(() => pushwoosh.closeInApp(), 3000);
}
</script>

</body>
</html>
```


</details>

</TabItem>
<TabItem label="Survey">

This survey saves the selected workout time as a tag, sends a `schedule_survey_completed` event, shows a thank-you message, then closes the in-app.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-14.webp" alt="HTML survey in the in-app editor asking when the user prefers to work out with four time options" width="360"/>

<details>
<summary>HTML code</summary>

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
  body { margin: 0; padding: 20px; font-family: Arial, sans-serif; text-align: center; }
  h2 { font-size: 18px; margin-bottom: 6px; color: #222; }
  p { font-size: 13px; color: #888; margin-bottom: 20px; }
  .option {
    display: block;
    width: 100%;
    padding: 14px;
    margin-bottom: 10px;
    background: #f5f5f5;
    border: 2px solid transparent;
    border-radius: 10px;
    font-size: 15px;
    cursor: pointer;
    box-sizing: border-box;
  }
  .option:hover { border-color: #FF6B35; background: #fff5f0; }
  .thanks { display: none; font-size: 17px; padding: 40px 0; color: #333; }
</style>
</head>
<body>

<h2>When do you prefer to work out?</h2>
<p>Help us schedule the best classes for you</p>

<button class="option" onclick="pick('morning')">☀️ Morning (6:00–10:00)</button>
<button class="option" onclick="pick('afternoon')">🌤️ Afternoon (12:00–15:00)</button>
<button class="option" onclick="pick('evening')">🌙 Evening (18:00–21:00)</button>
<button class="option" onclick="pick('weekend')">📅 Weekends only</button>

<div class="thanks" id="thanks">Got it! We'll send you the best schedule 💪</div>

<script>
function pick(time) {
  pushwoosh.sendTags({ preferred_time: time });
  pushwoosh.postEvent("schedule_survey_completed", { time: time });
  document.querySelector('h2').style.display = 'none';
  document.querySelector('p').style.display = 'none';
  document.querySelectorAll('.option').forEach(el => el.style.display = 'none');
  document.getElementById('thanks').style.display = 'block';
  setTimeout(() => pushwoosh.closeInApp(), 2000);
}
</script>

</body>
</html>
```


</details>

</TabItem>
<TabItem label="Video">

This example embeds a YouTube video in the in-app message.

<details>
<summary>HTML code</summary>

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>In-App Video Example</title>
<style>
  body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    text-align: center;
  }
  .video-container {
    position: relative;
    padding-bottom: 56.25%;
    height: 0;
    overflow: hidden;
  }
  .video-container iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
</style>
</head>
<body>

<h1>In-App Video Example</h1>

<div class="video-container">
       <iframe src="https://www.youtube.com/embed/TN1uyD2mONs?autoplay=1&mute=1" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>

</body>
</html>
```


</details>

</TabItem>
</Tabs>



### Menu

The **Menu** block places several clickable items in a row or column. Use it for a navigation bar or a list of company contacts.

For each menu item, set:

* **Label:** the text users see
* **URL:** where the item opens
* **Target:** same tab or a new tab

In the block settings, you can also set:

* **Direction:** Horizontal or Vertical
* **Alignment:** Left, Center, or Right
* **Separator:** an optional divider between items
* Font, size, weight, letter spacing, and link/text colors

### Social

The **Social** block displays a row of social media icons that link to your profiles. Use it to send users to Facebook, Instagram, X, and other platforms from the in-app message.

Add platform entries, then set alignment, icon size, and the gap between icons.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-15.webp" alt="Social block settings with TikTok, Instagram, and Facebook links plus Alignment, Icon size, and Gap" width="320"/>

### Countdown timer

The **Timer** block is a countdown in the in-app message. Use it for limited-time offers, flash sales, and event reminders.

To set it up:

1. In **Countdown**, set **End date** and **End time**, then choose the **Timezone** and **Language** for the timer labels.
2. Turn **Labels** on to show "days / hours / minutes / seconds" captions under the digits, or off for numbers only.
3. In **Appearance**, set **Background**, **Digits color**, **Labels color**, and the font size for digits (default 40px) and labels (default 16px).
4. Adjust **Spacing** (padding) as needed.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-16.webp" alt="Timer block settings with Countdown end date and time, Labels, Appearance, and Spacing options"/>

### Columns

**Columns** split the canvas into side-by-side sections so you can place content next to each other in one row.

Drag one of these blocks onto the canvas:

* **2 columns:** two equal columns
* **3 columns:** three equal columns
* **4 columns:** four equal columns
* **33 / 67:** left column about 33% wide, right about 67%
* **67 / 33:** left column about 67% wide, right about 33%

Then add content to each column. To change spacing for all columns in the template, open **Settings** → **Columns defaults** and adjust outer padding, column padding, and the gap between columns.

## Configure template-wide styling

Template settings control styling for the whole in-app template: document size and background, popup look, and default styles for blocks.

Open the **Settings** tab in the right-hand panel. 

<img src="/rich-media-create-rich-media-in-the-built-in-editor-17.webp" alt="Settings tab with Document, Popup, and default style sections for blocks and columns" width="320"/>

Available sections:

* **Document:** size and look of the whole message area: width, padding, background color or image, text color, font family, and the gap between blocks.
* **Popup:** how the message sits on the dimmed backdrop: corner radius, plus overlay color and opacity.
* **Block defaults:** shared starting styles for blocks you add later, so new content matches the template until you override a block on the canvas.
* **Columns defaults:** spacing for every Columns layout: outer padding, padding inside each column, and the gap between columns.
* **Card defaults:** starting look for Card containers that group content in the layout, applied until you style a card individually.
* **Button group defaults:** spacing and alignment when several buttons sit together as a group.
* **Button defaults:** starting look for new Button blocks so CTAs stay consistent across the template until you style one separately.
* **Divider defaults:** starting line style, color, thickness, and width for new Divider blocks.

Defaults apply wherever an individual block does not override them.


<Aside type="note">
There is no height setting. The popup grows with its content. For a full-screen message, set **Width** in **Settings** and choose **Fullscreen** in **In-app settings**.
</Aside>

## Localize the template

A multi-language template stores localized copy for each language in one in-app design. Use the language switcher above the canvas to add languages and edit content per language. For how multi-language messaging works across channels, see [Multi-language messaging](/product/personalization/multi-language/).

Content you haven't translated yet for the current language shows dimmed. Start typing to create the translation. The default language keeps showing until you do.

<Aside type="note">
Any block you add appears with the same content for every language. Remember to translate new text and button labels for every language you use in your template.
</Aside>

## Configure how the in-app looks on device

**In-app settings** control how the message appears and behaves on the device: position, animations, swipe gestures, and the close button. These settings only apply to iOS and Android Native.

Click **In-app settings** in the top bar:

* **Position on Screen:** Fullscreen, Top, Center, or Bottom.
* **Present Animation** / **Close Animation:** None, Fade, Left, Right, Up, or Down, or Default to use your app's SDK default.

<Aside type="note">
**None** and **Fade** currently work on Android. On iOS, the message appears and disappears instantly (alignment coming soon).
</Aside>

* **Animation Duration (MS):** 100 to 3000 milliseconds. Leave empty to use the SDK default timing.
* **Swipe to Close:** enable any combination of Left, Right, Up, and Down.
* **Show close button:** turn the close control on or off. When on, set **Position** (Top right, Top left, Bottom right, Bottom left), **Background** (a color, or **Transparent**), and **Icon Color**. Unlike the other settings in this modal, the close button's appearance is rendered into the message itself and shows on every platform, not just iOS and Android Native.

<img src="/rich-media-create-rich-media-in-the-built-in-editor-18.webp" alt="In-app settings modal with position, animations, swipe to close, and close button options"/>

Click **Apply** to save your choices, or **Cancel** to discard them.

## Save the template

Click **Save** in the top bar to save your changes. Use **Undo**/**Redo** in the top bar to step back and forward through your edits.

<Aside type="note">
Saving stores your in-app template in **Content** → **In-apps**. From there you can preview, edit, and manage templates. [Learn more](/product/content/in-apps/#view-and-manage-your-in-app-content)
</Aside>

## Use the saved template

After you save an in-app template, you can show it to users in a Customer Journey, as a one-time in-app, or when a user taps a push.

* [Show an in-app as part of a customer journey](/product/customer-journey/journey-elements/#in-app)
* [Send a push that opens an in-app when clicked](/product/messaging-channels/push-notifications/send-push-notifications/one-time-push)
* [Display a single in-app to your users](/product/messaging-channels/in-apps/)