Symplify uses handlebars for placeholders, custom tracking and dynamic content. This article is a reference of the handlebars you can use, with examples.
- Contact data
- Letter casing and fallbacks
- Date formats
- URL encoding
- Switch and compare
- When
- Anniversary
- Purchase history
- JSON arrays
- Calculations with numbers and dates
- Symplify entities
- Regular expressions and substrings
All handlebars that work in message content also work in links and in tracking. In links, the result is URL-encoded. To reuse handlebars you use often, save them as snippets.
Contact data
A handlebar starts with {{ and ends with }}. To show the value of a contact attribute, write contact. followed by the attribute name:
{{contact.firstName}}
When the message is sent, this is replaced with the value in the contact's firstName attribute. Attribute names aren't case sensitive, so {{contact.firstname}} works too.
Letter casing and fallbacks
Letter casing
| Handlebar | Result |
|---|---|
| {{#capitalize}}{{contact.firstName}}{{/capitalize}} | Anna |
| {{lower contact.firstName}} | anna |
| {{upper contact.firstName}} | ANNA |
Fallback for empty values
Use print to show a fallback when the attribute is empty:
Hi {{print contact.firstName "dear customer"}}
This renders Hi Anna, or Hi dear customer if the contact has no first name. You can combine print with other helpers:
HI {{#upper}}{{print contact.firstName "dear customer"}}{{/upper}}
This renders HI ANNA, or HI DEAR CUSTOMER.
Date formats
Dates are stored in the format yyyy-MM-dd, so {{contact.dateOfBirth}} renders for example 1979-08-03. See Date and time in the database. To show the date in another way, add a format:
| Handlebar | Result |
|---|---|
| {{date "d MMM. yyyy" contact.dateOfBirth}} | 3 Aug. 1979 |
| {{date "MMMM d" contact.dateOfBirth}} | August 3 |
| {{date "dd/MM/yy" contact.dateOfBirth}} | 03/08/79 |
You can use these parts in the format:
| Format | Example result |
|---|---|
| M | 8 |
| MM | 08 |
| MMM | Aug |
| MMMM | August |
| d | 3 |
| dd | 03 |
| yy | 79 |
| yyyy | 1979 |
Note: The parts are case sensitive. Use lowercase d and y. Uppercase D is the day of the year and Y is a week-based year, which give wrong dates.
Dates in other languages
Month and day names are in English by default. To use another language, use localizedDate with a language code, such as sv-SE (Swedish) or de-DE (German):
{{localizedDate "dd MMMM yyyy" "fr-FR" contact.dateOfBirth}}
This renders 03 août 1979. See Supported handlebar languages.
To show the day of the week, use EEEE:
{{localizedDate "EEEE" "fr-FR" contact.dateOfBirth}}
For a date that falls on a Tuesday, this renders mardi.
URL encoding
In links and tracking, values are URL-encoded so that they work in a URL. In content, you can encode a value yourself with urlEncode:
{{urlEncode contact.firstName}}
If an attribute holds a complete link, use noEncode in the link so the address isn't encoded:
<a href="{{noEncode contact.linkTarget}}">
Switch and compare
Use switch to show different content depending on a value. This is useful if you, for example, store short product codes but want to show the full name in your message.
This example checks the contact's product_size attribute:
{{#switch contact.product_size}}{{#compare "==" 'S'}}size: small{{/compare}}{{#compare "==" 'M'}}size: medium{{/compare}}{{#compare "==" 'L'}}size: large{{/compare}}{{#default}}Default value{{/default}}{{/switch}}
It renders size: small if the value is S, size: medium if it is M, size: large if it is L, and Default value for anything else.
The value doesn't have to match completely. To match values that start with something, use stringcompare:
{{#switch contact.status}}{{#stringcompare "startsWithIgnoreCase" "pro"}}professional{{/stringcompare}}{{#default}}creative mind{{/default}}{{/switch}}
This renders professional for values such as pro_sewer or pro_painter, and creative mind for everything else.
You can also compare numbers:
Level: {{#switch contact.bonusPoints}}{{#compare ">" 100}}Gold member{{/compare}}{{#compare "<" 100}}Silver member{{/compare}}{{#default}}New{{/default}}{{/switch}}
This renders Level: Gold member for more than 100 points, Level: Silver member for less than 100, and Level: New otherwise.
Compare operators
| Operator | Example | Matches when the value |
|---|---|---|
| > | {{#compare ">" 100}} | is greater than 100 |
| < | {{#compare "<" 100}} | is less than 100 |
| >= | {{#compare ">=" 100}} | is 100 or greater |
| <= | {{#compare "<=" 100}} | is 100 or less |
| == | {{#compare "==" 100}} | is equal to 100. Works for text too, and ignores letter case. |
| != | {{#compare "!=" 100}} | is not equal to 100 |
| % | {{#compare "%" 4 0}} | divided by 4 leaves 0, that is, it can be divided by 4 |
| !% | {{#compare "!%" 4 0}} | divided by 4 doesn't leave 0 |
Only the first matching compare in a switch is used.
Switch on a part of a value
Use switchOnExpression to switch on the result of another handlebar. For example, {{message.sendtime}} renders the full send time, such as 2026-02-07T08:55:30.587. To show the month as a name, pick out the month with date 'M':
{{#switchOnExpression "{{date 'M' message.sendtime}}"}}
{{#compare "==" '1'}}January{{/compare}}
{{#compare "==" '2'}}February{{/compare}}
{{#compare "==" '3'}}March{{/compare}}
...
{{/switchOnExpression}}
For a message sent in February, this renders February. Use y for the year, M for the month and d for the day.
When
when is a simpler alternative to switch and compare, for when you want to check one value:
{{#when contact.level "equals" "gold"}}
For gold members, our sale starts on Monday.
{{else}}
Our sale starts on Thursday.
{{/when}}
Text operators
| Operator | Matches when the value |
|---|---|
| equals | is exactly the text |
| contains | contains the text |
| startsWith | starts with the text |
| endsWith | ends with the text |
The text operators are case sensitive. Add IgnoreCase at the end to ignore letter case, and not at the start to reverse the operator, for example equalsIgnoreCase, notEquals or notContainsIgnoreCase:
{{#when contact.level "notEquals" "VIP"}}
Become a VIP member today.
{{/when}}
If you leave out the operator, when uses equalsIgnoreCase: {{#when contact.level "vip"}}.
Number operators
| Operator | Matches when the value is |
|---|---|
| > | greater than the number |
| >= | greater than or equal to the number |
| < | less than the number |
| <= | less than or equal to the number |
| == | exactly the same as the number, compared as text (so 5 and 5.0 don't match) |
{{#when contact.points ">=" 500}}
You are a gold member.
{{/when}}
To check a range, put one when inside another:
{{#when contact.points ">=" 1}}{{#when contact.points "<=" 250}}Membership: Silver{{/when}}{{/when}}
{{#when contact.points ">=" 251}}{{#when contact.points "<=" 500}}Membership: Gold{{/when}}{{/when}}
when also works with purchase history and DataDocs:
{{#when ph.last.paymentOption "equals" "card"}}{{#when ph.last.totalPrice ">" 400}}You have earned a bonus with your latest purchase.{{/when}}{{/when}}
{{#when payment "equals" "accepted"}}Paid and ready to go.{{/when}}
Empty values
Without an operator or a value, when checks that the value isn't empty. Add {{else}} for a fallback:
{{#when contact.points}}Current points: {{contact.points}}{{else}}You have no points yet.{{/when}}
If you don't want to show anything when the value is empty, leave out the {{else}}.
Anniversary
ifAnniversary shows content when a date attribute has the same month and day as today. If there is no match, nothing is shown, or the {{else}} content if you add one. anniversary renders the number of years:
{{#ifAnniversary contact.date}}Time flies! You've been a member for {{anniversary contact.date}} {{#ifAnniversary contact.date 1}}year{{else}}years{{/ifAnniversary}}!{{/ifAnniversary}}
This renders, for example, Time flies! You've been a member for 2 years! Without a number, ifAnniversary matches dates one year ago or more, not dates from this year.
Add one number to match an exact anniversary. This only matches if the date is exactly 1 year ago today:
{{#ifAnniversary contact.date 1}}
Time flies! You've been a member for a whole year!
{{/ifAnniversary}}
Add two numbers to match a range. This matches if the date is 2, 3, 4 or 5 years ago today:
{{#ifAnniversary contact.date 2 5}}...{{/ifAnniversary}}
As in the first example, you can also use a number to choose the wording: {{#ifAnniversary contact.date 1}}year{{else}}years{{/ifAnniversary}} renders year on the first anniversary and years otherwise.
Purchase history
You can show purchase history data in your messages. Use the name of any purchase history column, standard or custom. The standard columns are transactionDate, ItemPrice, ItemCount and TotalPrice. To target the right rows, you sometimes need a segment.
There are three ways to pick rows:
- The first or last row, for example "Are you happy with your new tent?"
- The first or last row in a segment, for example "Are you running out of gas canisters?"
- All rows, for example "This is your order history".
First or last row
{{ph.first.YourColumn}} gets the value from the oldest row, by transaction date. {{ph.last.YourColumn}} gets the value from the newest row.
For example, with this purchase history:
| OriginalID | TransactionDate | ProductCategory |
|---|---|---|
| 100245 | 2025-09-13 | tents |
| 100245 | 2025-11-20 | boots |
| 100245 | 2025-10-14 | jackets |
| Handlebar | Result |
|---|---|
| {{ph.first.ProductCategory}} | tents |
| {{ph.last.ProductCategory}} | boots |
| {{ph.last.transactionDate}} | 2025-11-20 |
First or last row in a segment
Create a purchase history segment to target specific purchases, and use it as the master segment or as a content segment. {{ph.firstInSegment.YourColumn}} gets the value from the oldest matching row, and {{ph.lastInSegment.YourColumn}} from the newest.
For example, with a segment for everyone who bought gas canisters three weeks ago:
Hi {{contact.firstName}}, are you running out of {{ph.lastInSegment.ProductName}}?
This renders, depending on the contact's purchases, Hi Anna, are you running out of Camping Gas 230 g? or Hi Erik, are you running out of Camping Gas 450 g?
All rows
To show all purchase rows, from oldest to newest, use ph.all and choose the columns:
{{#each ph.all}}{{this.YourColumn}} {{/each}}
This is useful, for example, to list all purchased items on a Dynamic web profile page. To show only the rows that match a segment, for example purchases in a period or a product category, use ph.allInSegment:
{{#each ph.allInSegment}}{{this.YourColumn}} {{/each}}
If the message has no purchase history segment, ph.allInSegment returns all rows.
Format purchase history values
You can combine purchase history with the other helpers:
| Handlebar | Stored value | Result |
|---|---|---|
| {{date 'd MMM. yyyy' ph.last.transactionDate}} | 2025-11-03 | 3 Nov. 2025 |
| {{capitalize ph.last.ProductName}} | trail runner | Trail runner |
JSON arrays
For example for order confirmations, you can store a JSON array in an attribute or a DataDoc and show it in the message.
From a contact attribute
Use jsonRender. With this JSON in an attribute called LastOrder:
{
"Products": [
{ "Product": "Trail runner", "Price": "1 499 SEK" },
{ "Product": "Wool socks", "Price": "199 SEK" }
]
}
this handlebar:
Your order:
{{#jsonRender contact.LastOrder}}
{{#each Products}}
{{Product}} ({{Price}})<br>
{{/each}}
{{/jsonRender}}
renders:
Your order: Trail runner (1 499 SEK) Wool socks (199 SEK)
If the attribute holds a JSON array rather than an object, loop over dataAsArray: {{#jsonRender contact.attributeName}}{{#each dataAsArray}}{{.}} {{/each}}{{/jsonRender}}.
From DataDocs
With this array in a document:
"orderItems": [
{ "ticketType": "Adult", "quantity": 2, "price": 40 },
{ "ticketType": "Child", "quantity": 1, "price": 10 },
{ "ticketType": "Student", "quantity": 1, "price": 15 }
]
this handlebar:
{{#documents}}
Your order:
{{#each orderItems}}{{ticketType}} x {{quantity}} = {{price}} €<br>
{{/each}}{{/documents}}
renders:
Your order: Adult x 2 = 40 € Child x 1 = 10 € Student x 1 = 15 €
Calculations with numbers and dates
Numbers
In these examples, the contact has value1 = 10 and value2 = 5.
| Handlebar | What it does | Result |
|---|---|---|
| {{add contact.value1 contact.value2}} | Adds the values | 15 |
| {{subtract contact.value1 contact.value2}} | Subtracts value2 from value1 | 5 |
| {{multiply contact.value1 contact.value2}} | Multiplies the values | 50 |
| {{divide contact.value1 contact.value2}} | Divides value1 by value2 | 2 |
| {{random 1 1000}} | A random number from 1 to 1000 | For example 417 |
Results are rounded to at most two decimals, with a comma as the decimal separator, for example 2,5. Dividing by 0 gives 0. To choose the format, add a number pattern and a language code:
{{multiply contact.price "0.8" "0.00" "en"}}
For a price of 199, this renders 159.20.
Dates
In these examples, the contact has StartDate = 2026-05-22.
| Handlebar | What it does | Result |
|---|---|---|
| {{dateAdd contact.StartDate 2 "DAYS"}} | Adds 2 days | 2026-05-24 |
| {{dateAdd contact.StartDate 2 "WEEKS"}} | Adds 2 weeks | 2026-06-05 |
| {{dateAdd contact.StartDate 2 "MONTHS"}} | Adds 2 months | 2026-07-22 |
| {{dateAdd contact.StartDate 2 "YEARS"}} | Adds 2 years | 2028-05-22 |
| {{dateSubtract contact.StartDate 2 "DAYS"}} | Subtracts 2 days | 2026-05-20 |
| {{dateAdd contact.StartDate 2 "DAYS" "MM/dd/yyyy"}} | Adds 2 days and shows the result as MM/dd/yyyy | 05/24/2026 |
Symplify entities
These handlebars show data about the message, campaign, project and link:
| Handlebar | Shows |
|---|---|
| {{contactdb.id}} | The ID of the contact database |
| {{contactdb.name}} | The name of the contact database |
| {{contact.originalId}} | The contact's originalId |
| {{message.id}} | The system ID of the message |
| {{message.guid}} | The unique identifier of the message |
| {{message.sendtime}} | The send time in the format yyyy-MM-dd'T'HH:mm:ss.SSS, for example 2026-06-25T15:30:24.123. To change the format, use the date formats or switchOnExpression. |
| {{message.abslice}} | A, B, C or D, if the message is part of an A/B test. If the message is sent as the winning version, the winning version's letter is returned. |
| {{campaign.id}} | The ID of the email |
| {{campaign.name}} | The name of the email |
| {{campaign.segmentid}} | The ID of the master segment. Returns -1 if there is no master segment, for example for transactional sendouts. |
| {{campaign.segmentname}} | The name of the master segment |
| {{project.id}} | The ID of the project |
| {{project.name}} | The name of the project |
| {{link.id}} | The ID of the link |
| {{link.name}} | The name of the link |
| {{link.categories}} | All categories on the link, separated by commas |
| {{link.segmentid}} | The ID of the content segment on the block that contains the link |
| {{link.segmentname}} | The name of the content segment on the block that contains the link |
| {{link.clicktime}} | The click time in the format yyyy-MM-dd'T'HH:mm:ss.SSS. To change the format, use the date formats. |
Regular expressions and substrings
Regular expressions
Use regex to pick out parts of a value:
{{#regex valueToMatchIn regexPattern}}
Your text, with the matched parts as {{match.1}}, {{match.2}} and so on.
{{/regex}}
valueToMatchIn can be an attribute, such as contact.firstName, or a fixed text in quotes. The pattern must match the whole value, and each part in parentheses becomes match.1, match.2 and so on. The pattern uses Java regular expression syntax.
Example:
{{#regex 'Hello World!' '([A-Za-z]+) World(!)'}}{{match.1}} Universe{{match.2}}{{/regex}}
This renders Hello Universe!
Substrings
Use substring to show part of a value:
{{substring beginIndex endIndex value}}
or as a block:
{{#substring beginIndex endIndex}}value{{/substring}}
The first character has index 0, and the character at endIndex isn't included. For example, if myValue is This is my Hello World! string:
{{substring 11 23 myValue}}
This renders Hello World!