Liquid upgrade
UpdatedWe are upgrading how we render liquid in your messages to better support you. The version we use to render your liquid depends on when you created your account with us.
What liquid version are you on?
If your Customer.io account was created on or after Nov 28, 2023, you are using the latest liquid version for all messages. If your Customer.io account was created before Nov 28, 2023, see Changing your liquid version for more info.
See below for the differences between the two versions.
How to check your liquid version
Within any message editor, hover over the last saved date at the top to see the liquid version you’re using.
If you’re using the legacy liquid version, you can upgrade to the latest version. If you upgraded a message to the latest liquid but want to return it to legacy due to syntax issues, you can also downgrade, but we recommend using a fallback if possible.
Change your liquid version
We’ve updated many accounts already to use the latest liquid version by default for new messages. You can check your liquid version on any message.
The latest liquid version offers improved filters (e.g. default
filter), faster rendering, and better tools for troubleshooting liquid syntax. See the differences between our legacy and latest liquid versions below.
For accounts created on or after Nov 28, 2023, you’re already using the latest liquid version for all messages.
For accounts created before Nov 28, 2023, you have the option to upgrade and downgrade:
- You can upgrade all new messages to use the latest liquid version by default in your workspace settings. (There is no setting for upgrading all existing messages at once.)
- You can downgrade if you find you’re not ready. Review the differences between versions so you can be confident you’re making the right choice.
- You can upgrade your liquid version on a template-by-template basis. That is, if you upgrade an email then make a copy, the copy will use the latest liquid, too.
Workspace: upgrade liquid
For accounts created before Nov 28, 2023, you can go to workspace settings to change what liquid version your new messages use by default. Accounts created on or after this date already use the latest liquid version for all messages, which is our long-term goal for everyone.
Go to General Workspace Settings, and scroll down to What liquid version do you want to use by default for new messages?
What does this mean for your messages?
- In your workspace, any new message moving forward (email, in-app, etc) will use our latest liquid version.
- You must upgrade this setting in each of your workspaces; there is no account-level setting.
- All new messages, including their translations, will use the latest liquid version.
- You must upgrade existing messages to use the latest liquid version.
- There is no setting for upgrading all existing messages at once.
- You should still preview your messages before sending to make sure your liquid renders as you’d expect.
Review the differences between liquid versions to make sure you’re ready to upgrade. Keep in mind, you can also upgrade individual messages if you’re not ready to commit to all new messages.
To upgrade at the workspace level, click “Upgrade liquid” then confirm your action.
You cannot upgrade snippets and layouts directly; these will render based on the liquid version of the message they are used in.
Workspace: downgrade liquid
For accounts created before Nov 28, 2023, you can go to workspace settings to change what liquid version your new messages use by default. Go to General Workspace Settings, and scroll down to What liquid version do you want to use by default for new messages?
What does this mean for your messages?
- In your workspace, any new message moving forward (email, in-app, etc) will use our legacy liquid version.
- You must downgrade this setting in each of your workspaces; there is no account-level setting.
- All new messages, including their translations, will use the legacy liquid version.
- You must downgrade existing messages to use the legacy liquid version.
- There is no setting for downgrading all existing messages at once.
- You should still preview your messages before sending to make sure your liquid renders as you’d expect.
Provide a fallback instead of downgrading
We recommend you provide a fallback instead of downgrading, if possible, as we intend to move everyone over to our latest liquid verison in the long-term.
Keep in mind, you can downgrade individual messages instead of all new messages, as well.
To downgrade at the workspace level, click Downgrade liquid” then confirm your action.
You cannot downgrade snippets and layouts directly; these will render based on the liquid version of the message they are used in.
Message: upgrade liquid
For accounts created before Nov 28, 2023, you can upgrade to the latest liquid version on a template-by-template basis. That is, if you upgrade an email then copy it, the copy will use the latest liquid, too. Go to a message with legacy liquid, click Actions or three horizontal dots in the top right, and see “Upgrade Liquid version…” in the dropdown.
If you want to upgrade a translated message, you’ll need to upgrade each language variant in the message, not just the default.
Check out the differences between our two versions of liquid to make sure you’re ready to upgrade.
To upgrade, click “Upgrade Liquid version…” then confirm your action. This will only upgrade the liquid version for the message you are on. You must go into each message to upgrade the version.
You cannot upgrade snippets and layouts directly; these will render based on the liquid version of the message they are used in.
Message: downgrade liquid
For accounts created before Nov 28, 2023, you can also downgrade a message to the legacy liquid version. To downgrade, go to a message with the latest liquid, click Actions or three horizontal dots in the top right, and click “Switch Liquid version…” in the dropdown.
If you want to downgrade a translated message, you’ll need to downgrade each language variant in the message, not just the default.
Provide a fallback instead of downgrading
We recommend you provide a fallback instead of downgrading, if possible, as we intend to move everyone over to our latest liquid verison in the long-term.
Click “Switch Liquid version…” then confirm your action. This will only downgrade the liquid version for the message you are on. You must go into each message to downgrade the version.
Fallback for both latest and legacy liquid versions
This section is useful if you want to reference liquid across messages and not worry about which liquid version you’re on. You’ll assign a variable to establish the liquid verison of the message and reference the variable to display the correct output.
You must assign the variable and reference it in the template itself or in a snippet. You cannot assign a variable in a snippet, then reference it in a template and vice versa.
Assign the variable in the template or snippet followed by this conditional:
{% assign liquid_version = nil | default: "latest" %}{% unless liquid_version == "latest" %}{% assign liquid_version = "legacy" %}{% endunless %}
Then you can reference the variable in a conditional to display the proper content:
{% if liquid_version == "latest" %}liquid that renders for latest liquid version{% else %}liquid that renders for legacy liquid version{% endif %}
Below is a breakdown of what is deprecated and new across liquid versions. A fallback like the one above can help you make sure, for instance, that operators supported by the legacy liquid version render when possible while a replacement for these operators renders with the latest version:
{% assign liquid_version = nil | default: "latest" %}{% unless liquid_version == "latest" %}{% assign liquid_version = "legacy" %}{% endunless %}
{% if liquid_version == "latest" %}{{ product_color | default: "red" }}{% else %}{% if product_color != blank %}{{ product_color }}{% else %}red{% endif %}{% endif %}
Differences in liquid versions
Deprecated with the latest liquid version:
timezone
- We deprecated thetimezone
filter in the latest liquid version. Moving forward, usetimezone
as an argument with thedate
filter instead.- Legacy:
{{ created_at | timezone: 'America/New_York' }}
- Latest:
{{ created_at | date: '%Y-%m-%d %H:%M:%S', 'America/New_York' }}
- Note: We support the
Asia/Riyadh
timezone in the latest version of liquid. We no longer support:- Asia/Riyadh87
- Asia/Riyadh88
- Asia/Riyadh89
- Mideast/Riyadh87
- Mideast/Riyadh88
- Mideast/Riyadh89
- Legacy:
htmlencode
- Useescape
to escape a string moving forward.- Legacy:
{{ "win+help@customer.io" | htmlencode }}
or{{ "win+help@customer.io" | escape }}
- Latest: only
{{ "win+help@customer.io" | escape }}
- Legacy:
New to the latest liquid version:
default
- It’s finally here! Now you can set a default value when one does not exist.json_array_uniq
- Now you can evaluate an array of JSON objects to output an array containing all the unique objects based only on the value of the passed-in key name. Use the filterto_json
if you need to output string values.break
- You can use a break tag to exit a loop.
Differences between filters supported in both versions
These filters exist across both versions, but behave differently in the latest liquid:
timezone
- You can offset the timezone in minutes, not hours. For instance, 360 would offset the timezone by -6:00 hours.currency
androunded_currency
- These filters accept both a locale and currency code. The legacy version only accepted a locale. These locales are only supported in the latest version:gsw-CH, ja-JP, kk, mg, sv-FI, sv-SE, uk, zh-Hant-MO, zh-MO
. The localezh-YUE
is only supported in the legacy version.escape
- Useurl_encode
to encode URLs instead.sort
- This no longer throws an error, preventing messages from sending, when a list/array contains null values. However, when an array contains null values, it won’t reorder the array.concat
- Now this accepts an object or an array.sha256
- This converts a string to the same output ashmac_sha256
.times
- Compare examples from the filter list to see when outputs contain decimals or not. In the latest version, if the output is a whole number, it will never contain a decimal.divided by
- Compare examples from the filter list to see when outputs contain decimals or not. In the latest version, if the output is a whole number, it will never contain a decimal.modulo
- The output will always be a positive number, even when there’s a negative number as input.sum
- The output aggregates numbers. Every value is cast to a number. Unlike with legacy liquid,sum
does not concatenate numbers, strings, or booleans.
Variable fallbacks
Both versions
With both our liquid versions, you can compare to blank
to establish a fallback to some default value. For example, the if
statement below renders “Hello there!” when first_name
is not stored on a person’s profile or when first_name
equals null
, false
, or an empty string.
{% if customer.first_name == blank %}
Hello there!
{% else %}
Hello {{customer.first_name}}!
{% endif %}
You can also compare to nil
to check if a value exists. For example, if the value below for previous_purchases
is false
, the value exists/is not null
. Compare key-values to nil
if false
is a valid value. Otherwise, you should compare key-values to blank
if false
is not a valid value.
{% if customer.previous_purchases == nil %}
Make a purchase!
{% else %}
{% comment %}else statement renders if previous_purchases equals false{% endcomment %}
If you liked your last purchase, try these other products!
{% endif %}
Also, consider math functions. You could use this conditional to set a fallback with either liquid version.
{% if customer.order_count < 10 %}
We thought you might like these items:
{% else %}
As a thank you, take 20% off your next order!
{% endif %}
The else
statement would render even if the order_count
did not exist for a customer (people who had not ordered yet). If that’s not what you want, you should check if the variable exists first.
{% if customer.order_count %}
{% if customer.order_count < 10 %}
Have you checked out these items?
{% else %}
As a thank you, take 20% off your next order.
{% endif %}
{% endif %}
This way, people without an order_count
would not see either conditional statement.
Latest only
With our latest liquid, you can also use the default
filter to set a fallback.
{{ customer.first_name | default: 'there' }}
With our latest liquid, you can check if an array has values with empty
.
{% if customer.purchases == empty}
Ready to make a purchase?
{% else %}
Ready to make your next purchase?
{% comment %} You could also loop through purchases here!{% endcomment %}
{% endif %}