Templating languages, sometimes called personalization languages – every customer engagement platform has one, but in a different flavour. So which one is the best one?
To find out, I’ve taken 15 most popular customer engagement platforms used for B2C marketing and analyzed the capabilities of their personalization languages to find out which ones offer the most capabilities and customization.
Platform | Templating Language |
ActiveCampaign | Personalization tags |
Adobe Campaign | ECMAScript for XML (E4X) |
Braze | Liquid |
CleverTap | Liquid |
Customer.io | Liquid & EMCAScript |
Emarsys | Emarsys Scripting Language (ESL) |
HubSpot | HubSpot Markup Language (HubL) |
Iterable | Handlebars |
Klaviyo | Personalization tags |
Leanplum | Jinja |
Mailchimp | Personalization tags |
MoEngage | Jinja |
OneSignal | Liquid |
Salesforce Marketing Cloud | AMPscript, GTL, Server-side JavaScript |
SendGrid | Handlebars |
Some of the most popular personalization languages are Liquid, Jinja and Handlebars, but there are also platforms like Salesforce who use custom languages – AMPscript.
Also, two platforms using the same templating language doesn’t mean they offer the same capabilities – for example, Liquid OneSignal supports fewer tags compared to Liquid in Braze. This happens because the platforms choose to support different versions of the language, or choose not to support certain functionalities due to their complexity and potential commuting resources they would use.
Comparing Liquid, Jinja, Handlebars and other Templating Languages
Based on my experience, there are 5 things I look for in every personalization language. Each capability builds upon the previous ones, creating a hierarchy of personalization power.
1. Inserting Dynamic Values
The foundation of any personalization language is its ability to dynamically insert values into various communication channels – from emails and push notifications to in-app messages and SMS campaigns. These dynamic values typically come from three main sources:
- User profile data: Names, preferences, past behaviors
- Campaign or Flow attributes: Send time, campaign ID, trigger events
- External data: Promo codes, product information, inventory status
Code:
Hi {{firstName}}, your flight to {{trigger.city}} has been delayed.
Output:
Hi John, your flight to Paris has been delayed.
2. Using Conditional Logic & Operators
This is where personalization gets interesting. Conditional logic acts as the “brain” of your templates, determining what content each user sees based on specific conditions. It’s powered by two key elements:
- Control Structures: if/else statements and for-loops that direct content flow.
- Operators: Mathematical and logical tools (addition, subtraction, equals, contains, greater than) that enable comparisons and calculations.
Code:
{% if user.lang == "en" %}
Hi, your flight has been delayed.
{% else if user.lang == "fr" %}
Bonjour, votre vol a été retardé.
{% endif %}
3. Applying Filters
Think of filters as your content’s styling team. They transform raw data into polished, presentation-ready format without changing the underlying information. Common applications include:
- Array Manipulation: Sorting lists, filtering collections
- Text Transformation: Capitalizing names, truncating long descriptions
- Date Formatting: Converting timestamps to user-friendly formats
- Number Formatting: Rounding decimals, adding currency symbols
Code:
Hi {{firstName}}
Hi {{firstName | capitalize }}
Hi {{firstName | length }}
Date is: {{user.subscription_expiration_date}}
Date is: {{user.subscription_expiration_date | | date: "%B %-d, %Y"}}
Output:
Hi John
Hi JOHN
Hi 4
2024-11-04T13:18:25Z
November 4, 2024
4. Assigning Variables
Variables are temporary containers that make complex personalization more manageable and efficient. Instead of repeating the same calculation or data manipulation multiple times, you store it once and reuse it throughout your template. It’s a foundational element of programming languages, yet many platforms don’t support this – severely limiting their personalization capabilities.
Code:
{% set name = "John" %}
{% set favorite_fruit = "Pineapple, Cherry, Apricot" %}
{% for fruit in favorite_fruit %}
{% if fruit == "Pineapple" %}
Hey {{name}}, here's a recipe for Pina Colada.
{% else if fruit == "Mango" %}
Hey {{name}}, here's a recipe for Mango Margarita.
{% endif %}{% endfor %}
Output:
Hey John, here's a recipe for Pina Colada.
5. Fetching Dynamic Data via API
The most advanced capability of personalization languages is the ability to make API calls to fetch real-time data during message rendering. This allows for truly dynamic content and advanced use cases like:
- Content Recommendations: “You might like Beetlejuice because you watched Wednesday.”
- Weather-Based Recommendations: “It’s 75°F in Miami – perfect for our new summer collection!”
- Live Inventory Updates: “Only 3 left in stock at your nearest store.”
Personalization Platform Power Rankings
After analyzing 15 leading customer engagement platforms and their templating languages, clear patterns emerge in their personalization capabilities. Here’s how they stack up:
They’ll help you to achieve your wildest wishes:
- Liquid – used by Braze, CleverTap, Customer.io, OneSignal
- Jinja & Jinja-derivatives – used by Leanplum, MoEngage, HubSpot, Emarsys
- JavaScript-based – used by AdobeCampaign, Salesforce Marketing Cloud
They’ll serve you well, but some things will always be out of reach.
- Handlebars – used by Iterable, SendGrid
- Personalization tags – used by Klaviyo
I feel sorry for you
- Personalization & Merge tags – used by ActiveCampaign and Mailchimp
*The table has horizontal scroll.
Platform | Templating Language | Inserting Dynamic Values | Conditional Logic & Operators | Applying Filters | Assigning Variables | Fetch Dynamic Content via API |
ActiveCampaign | Personalization tags | Yes | If/else | Very limited | No | No |
Adobe Campaign | ECMAScript for XML (E4X) | Yes | If/else, for, while, switch case | Yes | Yes | Yes, via External API |
Braze | Liquid | Yes | If/else for, case, unless | Yes | Yes | Yes, via Connected Content |
CleverTap | Liquid | Yes | If/else, for, switch case, unless | Limited | Yes | Yes, via Linked Content |
Customer.io | Liquid & EMCAScript | Yes | If/else, for, case, unless | Yes | Yes | Yes, via Webhook actions & JavaScript |
Emarsys | Emarsys Scripting Language (ESL) | Yes | If/else, foreach | Limited | Yes | No, but feed into relational data |
HubSpot | HubSpot Markup Language (HubL) | Yes | If/else, for | Yes | Yes | Yes, Serverless functions |
Iterable | Handlebars | Yes | If/else, each, unless | Limited | Yes | Yes, via Data Feeds |
Klaviyo | Personalization tags | Yes | If/else, for | Limited | No | No |
Leanplum | Jinja | Yes | If/else, for | Yes | Yes | Yes, Linked Data |
Mailchimp | Personalization tags | Yes | If/else | No | No | No |
MoEngage | Jinja | Yes | If/else, for | Limited | Yes | Yes, Content APIs |
OneSignal | Liquid | Yes | If/else for, unless | Limited | Yes | No |
Salesforce Marketing Cloud | AMPscript (proprieraty), GTL (based on Handlebars) & Server-side JavaScript | Yes | If/else, for, while. switch case | Yes | Yes | Yes, AMPscript HTTP functions |
SendGrid | Handlebars | Yes | If/else, each, unless | Limited | No | No |
The Conclusion
In the end, open-source templating languages like Liquid and Jinja dominate the top tier for good reason—they’re battle-tested and feature-rich, while custom solutions often end up reinventing the wheel (not always well).
Most templating languages share similar syntax patterns, so learning a popular one will give you transferable skills across platforms. To wrap up, here’s a cheat sheet showing which templating languages are most similar and different.