---
title: "Merge tags, MailKaro Docs"
description: "Merge tags let users drop {{tokens}}, like {{first_name}}, into text, links, image sources, and alt text. You supply the pickable set from your backend."
---

# Merge tags

Personalization

# Merge tags

Merge tags let users drop `{{tokens}}`, like `{{first_name}}`, into text, links, image sources, and alt text. You supply the pickable set from your backend.

## Passing tags

In the drop-in editor, pass them via `options.mergeTags` (react-email-editor parity, grouped arrays/objects are flattened automatically):

tsx

```
<EmailEditor
 options={{
 mergeTags: [
 { name: "First Name", value: "{{ user.first_name }}", sample: "Ada" }, { name: "Account", mergeTags: [ // nested group
 { name: "Plan", value: "{{ account.plan }}", sample: "Pro" }
 ]}
 ]
 }}
/>
```

That becomes the flat map MailKaro uses internally:

ts

```
{
 "user.first_name": { label: "First Name", value: "{{ user.first_name }}", sample: "Ada" }, "account.plan": { label: "Account · Plan", value: "{{ account.plan }}", sample: "Pro" }
}
```

## With EmailEditor

tsx

```
<EmailEditor
 mergeTags={{
 first_name: { label: "First name", value: "{{first_name}}", sample: "Alex" }
 }}
/>
```

## Conditions and lists

Text can also show or repeat parts of itself, based on the recipient. A condition shows its first part when it holds and its second part otherwise:

html

```
{{#if plan == "pro"}}Thanks for being a Pro customer.{{else}}Upgrade to Pro today.{{/if}}
```

A list repeats its body once per item. Give the list as an array in the values you render with (items can be text or records):

html

```
{{#each orders}}
 {{@number}}. {{name}}, {{this.total}}{{#if @last}}.{{else}};{{/if}}
{{/each}}
```

ts

```
renderDesign(design, {
 fullDocument: true,
 mergeTags: { plan: "pro", orders: [{ name: "Chai", total: "40" }, { name: "Coffee", total: "90" }] }
});
```

|Property |Controls |Default |
|`{{#if expr}}...{{else}}...{{/if}}` |Same expressions as display conditions: ==, !=, <, >, &&, ||, !, brackets, text and numbers. An expression that cannot be read counts as false. |, |
|`{{#each list}}...{{/each}}` |Repeats for each item, up to 100. |, |
|`{{name}} or {{this.name}}` |A field of the current item. Outside tags still work inside the loop. |, |
|`{{this}}` |The item itself, when the list holds plain text or numbers. |, |
|`{{@index}}, {{@number}}, {{@first}}, {{@last}}` |Position in the loop: from 0, from 1, and whether it is the first or last item. Conditions can use them too. |, |

ℹ Values printed inside a loop are HTML-escaped. Blocks may nest five levels deep, and a template that is not closed properly is left exactly as written so the mistake is easy to see. The Cloud API `POST /v3/render` and the MCP `render_design` tool accept the same lists in `merge_tags`.

## Resolving at send time

The `sample` values preview in the editor. When you [render on the server](https://mailkaro.com/docs/rendering), pass real recipient values so `{{first_name}}` becomes the actual name.

ℹ Embed tokens can also carry a server-configured merge-tag set: `/embed/runtime` returns `merge_tags` for the project, separate from the client `options.mergeTags`.

Source: https://docs.mailkaro.com/merge-tags
