Handlebars and Dynamic Content

Use handlebars to insert dynamic content and send personalized messages to each member of your audience. Pass variables to templates, determine the message text you want to show to each recipient based on those variables, and even iterate over objects and arrays of message variables.

You can use Airship’s handlebarAirship’s message personalization syntax using double curly braces, more commonly known as {{handlebars}}. Use handlebars to insert variables and conditional logic in messages and templates. syntax to personalize templates and messages based on information associated with your audience. When you send a message, Airship evaluates the conditions in your template or message, and issues personalized Dynamic ContentVariable message content using handlebar syntax that you populate at send time. Use dynamic content to personalize messages for each member of your audience. to each member of your audience.

You can personalize messages using:

Dynamic content uses handlebar syntax:

{{#eq merge_field "string value"}}
    If merge_field contains "string value", this string will appear!

Basic Syntax and Merge Fields

Handlebar syntax works by wrapping operators in curly braces. Merge fields are the most basic way to use handlebars. Insert your merge field into templates by wrapping the name of your field in curly braces — {{merge_field}}. Airship will replace the merge field (and braces) with the data specified by the merge field at send time — just like mail merge in your standard word processor or mail client.

URL Encoding

Some properties in Airship messages expect URLs — message actions, image and “link” properties in the Interactive Editor, etc. For these fields, items in double-curly braces are URL-encoded e.g. my value becomes my%20value. Use triple braces to escape URL encoding — {{{url}}}.

  • Use double braces to reference parameters that need URL encoding: https://www.example.com/user/{{user_name}}/{{cart_id}}
  • Use triple braces when referencing a variable or complete URL that is already URL-safe: {{{url}}}

When writing your own custom HTML or in any other situation where you might want to URL encode variables, you can use the urlEncode helper — {{urlEncode var_name}}.

Push example
    "audience": {
        "named_user": "one_user"
    "notification": {
        "android": {
        	"template": {
        		"fields": {
        			"alert": "Hi {{value_nospace}} go to https://www.example.com/{{urlEncode value_with_space}}!"
    	"actions": {
    		"open": {
    			"type": "url",
    			"content": "{{{value_full_url}}}"
    "device_types": [ "android" ]

The Default Handler

If you send a message and the value for a merge field is empty or doesn’t exist, your message won’t make sense. Use $def to set a default value for one or more merge field variables, so that your message will still make sense if your merge field is empty or doesn’t exist.

{{$def key1 key2 key<x> "value if keys are empty"}}

In handlebars using a default, you’ll provide the variables you want to use in your message and the default value if your variables are empty.

The example below uses the value you if the name event property is empty or does not exist.

{{$def name "you"}}

Not Statements

A not statement renders content if a merge field does not exist, is empty, or 0. This is a simple way to test for the availability of a merge field.

{{#not movies}}You might be interested in our new TV shows!{{/not}}`

If/Else Statements

If/else statements conditionally render blocks of content. *If and else if statements render content when the condition is true, and else renders content when all other conditions are false.

Use if explicitly to test that a variable exists, is not empty, or is not 0. Otherwise, any condition that evaluates a variable acts as an implicit if statement.

For example, you must explicitly declare if when testing whether or not the fav_movie variable exists, is not empty, and is not 0.

{{#if fav_movie}}
   Your favorite movie is {{fav_movie}}.
   Maybe you'd enjoy a book instead.

You do not need to explicitly declare if when testing the value of the fav_movie variable.

{{#eq fav_movie "Indiana Jones"}}Did you like The Last Crusade or Temple of Doom?
{{else eq fav_movie “Star Wars”}}Are you into the OG trilogy or are you a prequel person?
{{else}}What's your favorite book?{{/eq}}

You can chain multiple else statements — similar to else if statements in other languages — to test a series of variables. Generally, the last else statement contains no parameters and determines what happens if all previous conditions fail.

Unless — The Negative If Statement

Unless renders content in a template if a condition is false — like a negative if condition. You might want to use unless when you only really need the else statement for a condition.

In this example, Airship will render message content if the condition dislikes_indiana_jones is empty or false.

{{unless dislikes_indiana_jones}}You'll probably like Indiana Jones{{/unless}}

Equality Operators

Equality operators let you test the value of a merge field — whether it is equal to, or not equal to, specific value. Equality operators work well with string (text) values.

In this example, the message is different if the category merge field contains the value Accessories.

{{#eq category "Accessories"}}
   Enjoy up to $25 off!
   Get up to $75 off!

Use the not equal (neq) operator to render content when a merge field is not equal to a value.

{{#neq things "thing 1"}}You must be thing 2!{{/neq}}

Greater Than and Less Than

Use the following operators to show content if the value in a field — or the length of a string/array in a field — is greater than or less than a particular value.

  • {{#gt}} greater than
  • {{#lt}} less than
  • {{#gte}} greater than or equal to
  • {{#lte}} less than or equal to

String and array lengths are 0-indexed. For example, if a string has 3 characters, {{#gte field 2}} will be true.

The following example displays text if “quantity” is less than 2.

{{#lt quantity 2}}You have < 2 items in your cart{{/lt}}

Combining Operators

Use and and or to test multiple conditions for a block of content. The and and or operators help you string together complex conditions to show the right content to the right members of your audience.

and renders a block of content if all conditions are true.

{{#and (eq genre "action") (eq era "80s") }}
   You will definitely like Indiana Jones!

or renders a block of content if any of the conditions are true.

{{#or (eq movies "action") (eq era "80s") }}
   You might like Indiana Jones!

Object and Array Notation

The user data and merge fields you use to populate a template are often nested in objects or arrays — like when using Custom Events to populate a template in an automation rule.

Use standard dot notation to access properties in objects or an item/index in an array. For example, you could access a productName property in a suggestedProduct object using suggestedProduct.productName.

Use the array index to access an item at a particular location in an array. For example, if your message includes an array of objects called suggestedProducts for each member of your audience, you can access the first suggested product with suggestedProducts.[0] (array index 0).


Array indexes start at 0.

If you want to reference a key called image belonging to the first suggested product in the array, you would use suggestedProducts.[1].image.

Setting Context Using #with

Use {{#with}} to set the context within your template. This can help you access nested keys without having to repeat the parent object’s path.

For example, if your audience’s shipping information is nested in an object called shippingAddress, you might use the with helper to limit context and simplify your template like this:

We'll ship your package to:
{{#with shippingAddress}}
   {{yourState}}, {{yourPostCode}}

Object and Array Notation for CSV Uploads

When you Upload Users to send a message, you can include complex arrays and objects in your CSV using object notation to represent object properties in the header. When referencing an array index, you must wrap the array index in brackets. Your CSV should include headers for each item in the array and each property in the object that you want to reference in your message.

For example, if you want to use an array of objects called items for each member of your uploaded audience, your CSV will include items.[#] for each item in the array. If each object in the array had name, image, and url properties, you would add items.[0].name, items.[0].image, items.[0].url to your CSV, and reference additional objects in the array by incrementing the index (e.g. items.[1] and so on).


Array indexes start at 0.

If you wanted to personalize an email to members of your audience based on their addresses and the names of items they’re interested in, you might format your CSV as follows:

someone@sample.com,2018-04-01T18:45:30,Joe Someone,Portland,OR,Rubber Gloves,Bleach Alternative
else@sample.com,2018-04-21T16:13:01,Sir Else,Seattle,WA,Flashlight,Shovel 

Loop Through Objects and Arrays

Use the #each operator to loop through and repeat content from an array or object. For example, you can show a user all the items in their shopping cart, including quantity, description, and price.


You cannot limit loops using handlebars. If you want to limit iterations in a loop, you must limit the array or object data that you pass to Airship.

You specify the key of the array or object that you want to start your loop from using {{#each <property> }}. You can access properties within the loop with the following handlebars.

  • {{.}} Accesses the current item in the array, generally for simple arrays of strings or integers.

  • {{key}} References a property in the object in the loop. Because your loop reference begins from the object or array specified by #each, you don’t need to provide the full path of the property that you want to evaluate — just the path to the key within the current iteration of the loop.

    For example, if looping through an array of objects called suggestedProducts, you could specify the keys within each object — qty and productName.

       {{#each suggestedProducts}}
       {{qty}}x {{productName}}

  • {{@index}} References the current array index in the loop.

  • {{this}} Limits the context to the current object iteration of the loop. Use dot notation to reference a key in the object, i.e., {{this.key}}.

    In general, you don’t need to use this unless you have a duplicate key outside the loop and the key in your loop is optional. In such a case, this prevents the template from finding and using a duplicate key outside the current iteration of the loop if the key in the loop is missing.

Reference names in a simple array:
Everybody coming to the pizza party:
{{#each pizza_partiers}}
{{@index}}: {{.}}

Reference items in a user’s shopping cart as an array of objects:
Are you still interested in the following items? 
{{#each cart}}
* {{qty}}x {{product}} for {{price}}