9 Power Tips for Using Liquid to Personalize Emails
Personalizing your emails requires personalized content — and one incredibly powerful way to do that is with Liquid, an open-source template language created by Shopify.
Liquid enables you to load and display dynamic content based on the data you have, whether it’s for an e-commerce experience built with Shopify or messages sent through Customer.io. You can even incorporate dynamic logic to personalize your emails without needing an advanced computer science degree. This provides much more flexibility than the basic merge tags many email service providers use.
My name is Carl and my company MailCharts, which allows e-commerce companies to plan and optimize their campaigns, uses Customer.io. Over the last few years, I’ve gained loads of experience in working with Liquid. In this post, I’ll show you high-value tricks and “good to knows” — from the basics to the more advanced — that you’ll find useful when creating your next email in Customer.io.
First, some Liquid basics
There are 3 types of Liquid code:
Objects, or variables output dynamic content. Objects use double curly braces {{
}}
to output, or render, the content.
Filters modify the output of a Liquid object. You add filters inside the output braces and denote it using a pipe character |
.
Tags create the programming logic that directs templates on what to do with data. You can do things like apply if/then logic, assign variables, and create conditions.
Next-level Liquid Tips
Day of the week
Ever receive an email with a “Happy Thursday” towards the end of the email? I find this detail to be super friendly. Here’s how to add this to your mailers:
Happy {{ 'now' | timezone: "US/Central" | date: "%A"}}
Notice the timezone: “US/Central” part. Make sure you change this to your own timezone (and test the timezone to make sure it works).
Grabbing the first name from a full name
Let’s say you want to include your customer’s first name in the subject line, but all you have is their full name (first name and last name together in one entry, like “Kimmy Schmidt”). Yes, you could create a script to add a new attribute to every subscriber — or you can use this code:
{{ customer.name | truncatewords: 1, "" }}
(This works 99% of the time. You’ll run into a small issue if someone has a first name with two names. So if someone entered Ford Allen Mc Miller — with Ford Allen as their first name and Mc Miller as their last, you’d be sending the email displaying Ford in the subject.)
Capitalizing names
It’s always a good idea to capitalize words correctly, like someone’s first name. The problem is that data entered manually by your users probably won’t be consistent over time. Here’s how to address that:
{{ customer.first_name | capitalize }}
Voila! Their name will always be capitalized.
You can also mix and match the tricks shared in this post. For example, here’s the Liquid to display the first name from a full name and make sure it’s always capitalized:
{{ customer.name | truncatewords: 1, "" | capitalize }}
If / else logic
With Liquid, you can include if / else logic in your emails. This allows you to personalize email content based on different conditions, controlling what you render and when. Here’s how you can create a very simple if / else statement:
Hi {% if customer.first_name %}{{ customer.first_name }}{% else %}there{% endif %},
welcome to MailCharts!
If a user has the customer.first_name
attribute, the message will merge in the name — and if the attribute doesn’t exist, you’ll see “Hi there, welcome to MailCharts!”
Dynamic logic if an attribute exists
When using an if / else statement, it’s a best practice to double-check that a field actually exists. This prevents you from running into unexpected errors, which can happen if the property technically exists on the user record but is empty.
You can do this by appending .size > 0
to your if / else logic. Putting that together with the | capitalize
filter, here it is in action:
Hi {% if customer.first_name.size > 0 %}{{ customer.first_name | capitalize }}
{% else %}there{% endif %}, welcome to MailCharts!
Randomizer
Let’s say you want to add a nice, random quote to the end of your emails. Or maybe you want to randomize which product benefits you show over time. You can achieve this by using a capture group:
{% capture timeSeed %}{{ 'now' | date: "%s" }}{% endcapture %}
{% assign random = timeSeed | modulo: 5 %}
{% if random == 0%}
Message 1
{% elsif random == 1 %}
Message 2
{% elsif random == 2 %}
Message 3
{% elsif random == 3 %}
Message 4
{% elsif random == 4 %}
Message 5
{% endif %}
Here, we created a timeSeed variable which gets assigned the seconds of the current date. Then we use modulo: 5 on it. Why 5? Because in our example, we wanted to rotate through 5 different messages. If you had 6 messages, use modulo 6
. If you had only 2 messages, use modulo 2
— and so forth.
We then use the typical if, elsif, else logic to display the different messages.
Here’s another example in action, with randomized burger specials:
Advanced Liquid Tips
Loops with limits
Imagine you want to send an email featuring 4 products that a user checked out on your site. If you’re saving each product viewed inside an array in your data, you can simply use a for loop with a limit, as such:
{% for product in customer.products_viewed limit:4 %}{{ product.name }}, {% endfor %}
Here’s how we recently used this on a MailCharts email:
You can now get detailed insights on {% if customer.suggested_companies.size > 3 %}
{% for company in customer.suggested_companies limit:4 %}{{ company.name }}, {% endfor %}
or any other company{% else %}any company{% endif %} by running a Company Overview Report.
The result, based on my attributes: “You can now get detailed insights on J Crew, MailChimp, Warby Parker, Litmus, or any other company by running a Company Overview Report.”
And here’s a preview:
Notice how we combined a for
loop with a limit parameter inside an if statement that used a .size
check. (Try saying that fast four times. Go.)
Clean(er) if logic
If you’ve ever had to manage emails with lengthy if/else logic then you know how difficult code maintenance can be. No worries though, the capture tag is your friend.
Here’s an example:
{% if customer.items_in_cart.size > 1 %}
{% capture destinationUrl %}https://www.example.com/products/{{ customer.items_in_cart.last.id }}{% endcapture %}
{% capture buttonText %}Buy {{ customer.items_in_cart.last.name }}{% endcapture %}
{% else %}
{% capture destinationUrl %}https://www.example.com/products{% endcapture %}
{% capture buttonText %}View all products{% endcapture %}
{% endif %}
<a href="/%7B%7BdestinationUrl%7D%7D">{{buttonText}}</a>
Neat, right? You define all your variables at the top of the email and then simply use them throughout.
(Note: You can also use {% assign buttonText = "View all products" %}
if the value you’re assigning doesn’t rely on Liquid code being executed. In the example above, we need to use a capture group because of the {{ customer.items_in_cart.last.id }}
part of the destination url.)
URL encoding
Last, but certainly not least, if you want to include a user’s email address in a link. A common use-case is to pre-populate a form or other tracked paramters with their email address). But how do you handle users that have a plus sign (“+”) in their email address? (e.g. carl+yourcompany@mailcharts.com)
Sometimes, if you simply use {{ customer.email }}
, what you’ll see is something like carl%2Byourcompany@mailcharts.com inside the form. That’s not what you want!
If that happens, all you need to do is use the filter | escape
. Using escape allows you to fully escape all special characters.
Here’s the code:
{{ “carl+yourcompany@mailcharts.com” | escape }}
Or
{{ "customer.email" | escape }}
Instead of carl%2Byourcompany%40mailcharts.com, you’ll see “carl+yourcompany@mailcharts.com” in the form.
Want to learn more? Shopify has a great basics overview. The Customer.io documentation on Liquid and merging structured data get very detailed, and here are the Liquid tags that Customer.io supports.
Do you have any other tips or tricks the community would find helpful? If so, leave them in the comments below!
Carl Sednaoui is the co-founder and director of marketing at MailCharts and a veritable Liquid expert. MailCharts helps email marketers plan and optimize their email programs, using competitive and industry intel, plus persona-based analysis and transactional insights.