Get started
Working with merge field helpers

Alex Pribula
Alex Pribula
  • Updated

Merge field helpers extend the capabilities of standard merge fields, enabling more dynamic and complex logic using advanced helper syntax. With helpers, you can apply conditional logic to your templates and iterate over and display lists within channel-based nodes (for example, email body or SMS body fields).

Merge field helpers are only supported in message content fields within channel-based nodes. Other fields will display an error if helper syntax is used.

This guide outlines supported syntax, use cases, examples, and important considerations.

What are merge field helpers?

Merge field helpers are tools that let you perform advanced data manipulations within merge fields. These helpers allow for conditional rendering, looping through arrays, and using context-aware variables like @index or @first.

Supported helpers:

Helper Use Case Example
{{#if}} Conditional rendering if a value exists

Handlebars template: {{#if trigger_1.firstName}}Hi {{trigger_1.firstName}}{{/if}}

Result: If firstName exists: Hi {{trigger_1.firstName}}. If missing or false: nothing displayed.

{{#unless}} Render if the condition is false, empty, or null

Handlebars template: {{#unless active}}Account inactive{{/unless}}

Result: If active is false, empty, or null: Account inactive.

{{#each}} Iterate over arrays.
Works with arrays of primitives or arrays of objects.
Use arrays of objects to output tables or multi-field lists.
Use arrays of primitives for single-value lists.

Primitive example:

Payload:
{"names":["Alice","Bob","Charlie"]}

Handlebars:
{{#each names}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}

Result:
Alice, Bob, Charlie
          

Object array example: See Building tables with array data below.

{{else}} Define alternative output inside {{#if}} when the condition is false.
{{#if subscribed}}
  Thank you for being a subscriber!
{{else}}
  Stay informed and subscribe now!
{{/if}}
          
{{this}} Represents the current item inside {{#each}}. For objects, use {{this.field}} to access properties.
Primitive array:
{{#each names}}Name: {{this}} {{/each}}

Object array:
{{#each people}}Person: {{this.name}} {{/each}}
          

Building tables with array data

To generate tables or multi-column lists, you must use an array of objects. This is required for rendering itemised receipts, order summaries, or any structure where each row shows multiple fields.

Arrays of primitives (["A", "B", "C"]) can only be rendered as single-column lists. For tables, you must provide objects ([{"product":...}, ...]).

Required payload structure

{
  "customer": {
    "firstName": "Jess",
    "orders": [
      {
        "product": "Pendula T-shirt",
        "quantity": 2,
        "price": "$25.00"
      },
      {
        "product": "Sticker Pack",
        "quantity": 1,
        "price": "$5.00"
      },
      {
        "product": "Notebook",
        "quantity": 3,
        "price": "$12.00"
      }
    ]
  }
}

Example HTML in template

<table cellpadding="5" cellspacing="0" border="1"
style="border-collapse: collapse; width: 100%; border: 1px solid #0a2342; font-family: Arial, sans-serif; font-size: 14px;">
  <thead>
    <tr style="background-color: #f2f2f2;">
      <th>#</th><th>Product</th><th>Quantity</th><th>Price</th>
    </tr>
  </thead>
  <tbody>
    {{#each inboundWebhookTrigger_1.customer.orders}}
    <tr>
      <td>{{@index}}</td>
      <td>{{this.product}}</td>
      <td>{{this.quantity}}</td>
      <td>{{this.price}}</td>
    </tr>
    {{/each}}
  </tbody>
</table>

Example output

# Product Quantity Price
0 Pendula T-shirt 2 $25.00
1 Sticker Pack 1 $5.00
2 Notebook 3 $12.00

Notes

  • Arrays of primitives cannot produce tables.
  • Field names (product, quantity, price) must match your payload exactly (case sensitive).
  • @index gives the position in the loop (starts at 0).

Supported data variables (within #each loops):

Variable Description Example
@index The current index in the loop {{#each names}}{{@index}}: {{this}}\n{{/each}}0: Alice 1: Bob 2: Charlie
@key The key when looping over objects {{#each user}}{{@key}}: {{this}}\n{{/each}} (with { name: "Alice" }) → name: Alice
@first true if the current item is the first {{#each names}}{{#if @first}}First: {{/if}}{{this}}{{/each}}First: Alice Bob Charlie
@last true if the current item is the last {{#each names}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}Alice, Bob, Charlie

Partial support

  • Nested helpers: You can nest helpers (e.g., {{#each}} inside {{#if}}), but complex nesting may reduce readability and increase the risk of errors.
    {{#each users}}
      {{#if this.active}}
        {{this.name}}
      {{/if}}
    {{/each}}
        

Key considerations

  • Field-specific support: Merge field helpers are only supported in message content fields of channel nodes (e.g. email body). Other fields will display an error, ‘Helpers are not supported in this input field.’
  • Limited validation:
    • Unvalidated paths in helpers: Using this.some.path is not validated once helpers are used.
    • No deep syntax validation: Complex helper structures (e.g., nested loops with aliases) aren’t fully validated.
    • Closing tags: Helpers like {{/if}} must be properly closed. Pendula’s validation system won’t enforce this.
  • “Iterable” type error: The #each helper requires the referenced merge field to be an array or object. Using a non-iterable value triggers an error.

Troubleshooting common issues

Error Cause Solution
Wavy red underline on merge field Invalid or unrecognised merge field in helper block (misspelled or unsupported path) Check spelling and ensure the field exists in the payload
“Iterable” type error Using #each on a non-array or non-object Verify the merge field references an array/object
Blank output in message Merge field has no data, invalid path, or primitive array used in a table Use {{else}} or #unless for fallbacks, and check your payload structure