Using Liquid Syntax
How to apply personalization to message content
To personalize the content of your messages, you can use Liquid Syntax. Liquid uses a combination of tags, filters, and conditional statements to ensure the right content is displayed at the right time.
You can personalize all messages, including email, push, sms, in-app, and live activities. Liquid Syntax is a templating language that OneSignal supports for messaging content. With Liquid Syntax, you can substitute names {{ name }}
or apply more complex personalizations by adding logic {% if true %}
.
To see more liquid syntax examples, view the source documentation maintained by Shopify.
Fields that support Liquid syntax
Channel | Applicability |
---|---|
- Subject Line - Pre-header - Message Body - Image substitution available with the HTML Block or HTML Editor. Example: <img src="{{image_url}}"/> - Does not work with "Send Test Message" button. | |
Push | - Subject Line - Message Body - Image URL - Launch URL (e.g https://example.com/{{last_category_viewed}} ) |
SMS | - Message Body |
In-App | - Text Blocks - Button Blocks - Image Blocks - Only Tag substitution supported at this time. Does not accept Property substitution. - Does not work with "Send Test Message" button. |
Live Activities | - Within the event_updates , contents and headings properties. |
Launch URL Substitution
If using custom links in your messages or Launch URLs for push notifications, these require a protocol in the format identifier://
like https://
or app_name://
. Its common to need personalization in these URIs such as properties like user.external_id
or custom Data Tags.
User ID Substitution Example
If you want to send the user to their specific profile page and leverage External ID alias. You can use the URL: https://yoursite.com/user-profile/{{user.external_id}}
Custom Page Example
If you want to send the user to a specific page, like an item they were interested in purchasing. You would tag them with something like: "item_of_interest" : "itm5762"
and the URL would be: https://yoursite.com/products/{{item_of_interest}}
Image Substitution
A common example for Abandoned Cart is to add the last item set to the cart's image in the message. In this case, you can tag the user with the full image URL resource. For example: a tag key like "cart_image"
and the value is the full URL to the image https://cdn.pixabay.com/photo/2017/12/06/20/23/accessory-3002608_1280.jpg
Then in the Dashboard Image field or API Image parameters, you can set the tag key surrounded by curly brackets {{cart_image}}
and/or add a default image
{{cart_image | default: 'https://cdn.pixabay.com/photo/2017/12/06/20/23/accessory-3002608_1280.jpg'}}
In addition to the main notification image, you can also use tag substitution for images and icons for different platforms under platform settings.
Syntax
There are two ways to use Liquid syntax in your content. Double curly braces {{ ... }}
will result in rendering data from a data source, object, or variable. A curly brace with a percent sign {% ... %}
will render logic.
User Data Tag Include
To render a Data Tag, include the tag in curly braces using the {{ data_tag }}
format.
Hello, {{ first_name }}
"first_name": "George"
Hello, George
API Data Tag Include
To render values from custom_data
in API notifications, call the data:
{{ message.custom_data.example_key }}
Your account balance is ${{ message.custom_data.balance }}
{
"app_id": "5eb5a37e-b458-11e3-ac11-000c2940e62c",
"template_id": "be4a8044-bbd6-11e4-a581-000c2940e62c",
"custom_data": { "balance": "23.40" }
}
Your account balance is $23.50
Property Include
As well as custom defined data tags, you can also include many predefined properties by using the same curly braces method as used for tag substitution. For example, the subscription's email address can be included like so:
Your current email address is {{ subscription.email }}
As well as properties relating to subscriptions and users, you can also use properties specific to your OneSignal app and organizaiton.
For a full list of the properties available to use with liquid syntax, please see below:
Subscription Properties:
- subscription.email: The email of the player (when an email)
- subscription.phone_number: The phone number of the player (when an SMS)
- subscription.push_token: The push token of the player (when a push)
- subscription.language: The language code of the player
- subscription.external_id: The external id of the player
- subscription.tags: The tags of the player
User Properties:
- user.language: The language of the user, currently same as player
- user.tags: The tags of the user, currently same as player
Organization Properties:
- notification.id: The id of the notification
Notification Properties:
- notification.id: The id of the notification
Template Properties:
(Only exists if the notification was built from a template)
- template.id: The id of the template
- template.name: The name of the template
Application Properties:
- app.id: The id of the application the notification is sent under
- app.name: The name of the application the notification is sent under
Organization Properties:
(Only exists if the app the notification was sent under is itself under an organization.)
- org.id: The id of the organization (i.e. Organization.id)
- org.name: The name of the organization (i.e. Organization.name)
Please note that properties are not available in In-App Messages or Live activities.
Logic Tags
Logic tags are used to create conditions for displaying content, and use the curly brace percent sign syntax:
{% ... %}
The content inside of these tags do not produce any visible output when the template is rendered. This lets you assign variables and create conditions or loops without printing any of the Liquid logic in the content.
{%- assign level = level -%}
{% if level == '2' -%}
Congrats on making it past the first level, {{ first_name }}!
{%- elsif level > '2' -%}
Congrats on making it to level {{ level}}, {{ first_name }}!
{%- else -%}
{{ first_name }}, come back to beat the first level!
{%- endif %}
"first_name": "George", "level": "3"
Congrats on making it to level 3, George!
Filters
You can apply Liquid filters to adjust how the data is displayed. Filters are added after the variable or object, and are separated by a pipe symbol:
{{ variable | filter }}
Default Value
The most common use case for a filter is to assign a default value.
Hello {{ first_name | default: 'there' }}.
If the Data Tag for first_name
is blank or does not exist, the default value will be rendered instead.
Hello there.
Additionally, you can specify the default, which will show its value if the input is nil
, false
, or empty
.
{{ product_price | default: "2.99" }}
2.99
Dates
The date filter converts a timestamp into another date format. The format for this syntax is the same as strftime. The input uses the same format as Ruby’s Time.parse.
Set dates as a unix timestamp in seconds with Data Tags. This allows for use of both liquid syntax personalization and segmentation with Time Operators. For example, a tag might look like: bill_due : 1687968776
{{ bill_due | date: "%a, %b %d, %y" }}
Wed, Jun 28, 23
{{ event_date | date: "%Y" }}
2023
Date formatting works on strings if they contain well-formatted dates.
{{ "March 14, 2016" | date: "%b %d, %y" }}
Mar 14, 16
To get the current time, pass the special word now
(or today
) along with the date filter.
This message was sent at {{ "now" | date: "%Y-%m-%d %H:%M" }}.
This message was sent at 2022-11-02 14:39.
Current Time is based on when the message is rendered
The current time will be rendered in the message based on when the message is sent to the recipient. If you are testing the message, you will see the current time as when the test message was sent.
Capitalize
This filter makes the first character of a string capitalized, and converts the remaining characters to lowercase.
{{ "my GREAT title" | capitalize }}
My great title
Round
This filter rounds a number to the nearest integer, or, if a number is passed as an argument, to that number of decimal places.
{{ 1.2 | round }}
{{ 2.7 | round }}
{{ 183.357 | round: 2 }}
1
3
183.36
Conditional Logic
Display different content depending on the presence of data.
Operators
In conditional statements, you have logical operators available to use. The operators available are:
==
equals!=
does not equal>
greater than<
less than>=
greater than or equal to<=
less than or equal toor
logical orand
logical andcontains
checks for the presence of a substring inside a string, and for the presence of a string in an array of strings.
Order of operations
In tags with more than one and
or or
operator, operators are checked in order from right to left. You cannot change the order of operations using parentheses — parentheses are invalid characters in Liquid, and will prevent your tags from working.
{% if true or false and false %}
This evaluates to true, since the `and` condition is checked first.
{% endif %}
if, elsif, else
You can use logical operators such as if
, else
, and elsif
as control flow tags to create conditions that decide whether blocks of Liquid code get executed.
{%- assign userLang = user.language -%}
{% if userLang == 'es' -%}
Hola {{ first_name }}!
{%- elsif userLang == 'fr' -%}
Bonjour {{ first_name }}!
{%- else -%}
Hello {{ first_name }}!
{%- endif %}
language: "fr", tags: {"first_name": "George"}
Bonjour George!
unless
The opposite of if
executes a block of code only if a certain condition is not met. unless
might be similar to using the !=
not equal operator.
{% unless level == "1" %}
Great job getting past the first level!
{% endunless %}
Iteration
for loops
Repeatedly executes a block of code. For a full list of attributes available within a for
loop, refer to the for
loop object.
{% for product in message.custom_data.products %}
- {{ product.name }}
{% else %}
Sorry, we're sold out of all products.
{% endfor %}
{
"app_id": "5eb5a37e-b458-11e3-ac11-000c2940e62c",
"template_id": "be4a8044-bbd6-11e4-a581-000c2940e62c",
"custom_data": {
"products": [
{ "name": "Sweater" },
{ "name": "Hat" },
{ "name": "Shirt" }
]
}
}
// if message.custom_data.products has a value
- Sweater
- Hat
- Shirt
// if message.custom_data.products is empty
Sorry we're sold out of all products
limits & offsets
Limits the loop to the specified number of iterations. For example, if you only want to show 4 products in a message, you could use Limits and Offsets to specify the number of products shown.
great_numbers = [1,2,3,4,5,5]
{% for number in great_numbers limit:2 %}
{{ number }}
{% endfor %}
1 2
To begin the loop at the specified index, add an offset value:
great_numbers = [1,2,3,4,5,5]
{% for number in great_numbers limit: 3 %}
{{ number }}
{% endfor %}
{% for number in great_numbers limit: 3 offset: continue %}
{{ number }}
{% endfor %}
1 2 3
4 5 6
where
Creates an array including only the objects with a given property value, or any truthy value by default.
In this example, assume you have a list of products and you want to show your kitchen products separately. Using where
, you can create an array containing only the products that have a type
of kitchen
.
products = [
{name:"Vacuum", type:"electronics"},
{name:"Spatula", type:"kitchen"},
{name:"Television", type:"electronics"},
{name:"Garlic press", type:"kitchen"}
]
All products:
{% for product in products %}
- {{ product.name }}
{% endfor %}
{% assign kitchen_products = products | where: "type", "kitchen" %}
Kitchen products:
{% for product in kitchen_products %}
- {{ product.name }}
{% endfor %}
All products:
- Vacuum
- Spatula
- Television
- Garlic press
Kitchen products:
- Spatula
- Garlic press
FAQ
Why is substitution not working?
Property substitution doesn't work for In-App Messages at this time.
Tag substitution will not work when sending to test users via the "Send Test Message" buttons. You need to send the actual message.
Tag substitution will not work if you have spaces, periods, or "dots" in tag keys. Only use alphanumeric characters and an underscore ("_") or hyphen ("-") in your tag keys if needed.
Tag substitution will not work in the previews. You need to send the actual message.
How to control whitespace and newlines?
Whitespace control is a part of Liquid where you can add hyphens -
inside of the Liquid syntax {{- ... -}}
and {%- ... -%}
to remove newlines and whitespace on the side of the Liquid code that generates it.
For example, with this syntax, you may see a newline in the notification above and below the text.
{% assign name = "Jon" %}
{{ name }}
{% unless level == "1" %}
Great job getting past the first level!
{% endunless %}
Jon
Great job getting past the first level!
By including hyphens -
, you can strip the whitespace. See Whitespace control for more details.
{% assign name = "Jon" -%}
{{ name -}}
{% unless level == "1" %}
Great job getting past the first level!
{%- endunless %}
Jon
Great job getting past the first level!
Updated over 1 year ago