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" }] }
});
PropertyControlsDefault
{{#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, 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.