Personalisation and dynamic programmable content

Use Twig's programmatic syntax to achieve various use cases

Xtremepush uses Twig, a PHP template engine for dynamic content. For further information you can review Twig's official documentation. Dynamic content can be used with most channels (email, mobile and web push, onsite / in-app messages and inbox). Details and examples of some of the most commonly used programmatic functions and capabilities are given in the following sections.

🚧

Implementing Twig for older projects

Projects created before the 20th of July of 2020 may not have this feature enabled, or only enabled for email campaigns. Contact our support team to enable this feature.

Some considerations need to be taken into account before enabling the feature:

  • Existing campaigns prior to this feature being enabled will still not support it. Therefore, a new campaign will need to be created.
  • This change will also imply a change in behaviour: for older projects that don't have the current settings, when sending users a message with an attribute that is not set for a particular user, the result will be that the message won't be sent to that user. In this case, the error message 'not personalised' will be shown in the detail from the notifications log. With the current settings, if the campaign cannot be personalised, it will be sent with an empty string in place of the unpopulated attribute.

Personalisation

Profile attributes that have been manually created, tagged into the platform from an app or website, or synced with the platform via API can be used to personalise communications.

The syntax uses double curly brackets that wrap the attribute name:

{{user.attribute.name}}

From the campaign builder, click to search for available attributes and add them in the format shown in this example.

👍

Our database is case sensitive, so whenever referencing an attribute the exact same name must be used.

For example a message like:

Hi Sam, your balance is €20. Tap today to top-up!

May be created using the following attributes for personalisation:

Hi {{user.first_name}}, your balance is €{{user.balance}}. Tap today to top-up!

Indicating a fallback value

It is best practice, if possible, to use a fallback value in case the attribute doesn't exist for the user.

📘

Depending on the implementation of your project, if the attribute doesn't exist for a user the message might be sent with an empty string or not be sent altogether. Testing beforehand by targeting a user profile without the attribute stored, should always be carried out.

Use the following syntax for a fallback value:

{{user.attribute.name || 'Alternative'}}

For example:

{{ user.first_name || 'Hi' }}, check out our new feature!

If the attribute exists for the user the following message will be rendered:

Laura, check out our new feature!

Otherwise the fallback value will be rendered:

Hi, check out our new feature!

👍

Strings can be wrapped by single quotation marks ' ' or double quotation marks " ".

The attribute can also be combined with some text, including a fallback value:

{{' Some Text ${user.attribute.name}' || 'Alternative'}}

Snippets

Please see our snippets guide for more details.

Utility functions

Capitalisation

This function can be used in combination with variable content to make sure only the initial character is capitalised.

{{name | capitalize}}

Date

This function generates the current date.

{{ "now" | date() }}
// To render  (Month DD, YYY HH:MM)

Result: January 26, 2021 16:22

Specific formats can be used too:

{{ "now" | date("l, F jS") }}
// To render day of the week, Month and calendar day

This will render day of the week, Month and day, like this: Tuesday, January 26th

The elements used within the date function can also be used individually:

{{ "now"|date("F") }}
// To render the month

Result: January

{{ "now"|date("d/m/Y") }}
// To render date in a numeric format (dd/mm/YYYY)

Result: 26/01/2019

Again, the elements used within the date function can also be used individually:

{{ "now"|date("Y") }}
// To render the year in a numeric format (YYYY)

Result: 2021

Read Twig's documentation on date function for additional options.

Format number

This function allows to change the format of a number. Amongst many other things, it can be useful to round numbers. For example:

{{ PointsBalance | number_format(2) }}
//Display only 2 decimal places

Full documentation for number formatting.

Basic Slicing

This function allows to cut short dynamic content or take a sub string from it.

A common use case is truncating dynamic text, for example if you want to cut short some text at 50 characters and add trailing dots you can use:

{{text|slice(0,50)}}...

If the dynamic content was:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

It would become:
Lorem ipsum dolor sit amet, consectetur adipiscing...

Advanced Slicing

Include striptags within the function to remove HTML tags included in your content:

{{text|striptags|slice(0,20)}}

If your dynamic text is likely to vary a lot in length you can also use the length function to concatenate the text to a fraction of it's length and avoid over/under concatenating.

{{text|striptags|slice(0,text|length/2)}}
// To slice the text in length by half

Required values

This function prevents a message from being sent in case an important value is missing. A common use case is for transactional messages which include a unique URL or code.

{{ verification_url | required }}

When a required value is missing the message will not be sent., in which case it be displayed in the notifications log with a 'Required values are not set' error.

Conditional statements

Conditional statements (if / else) will ask the system to take an action if something is true; otherwise, do something else. The simplest version would include just an if statement and an endif to indicate the end of the conditional statement. In some cases, dynamically added information is not always present, so this can be handled with the following syntax:

{% if entry.brand.location %}, {{entry.brand.location}} {% endif %}
// If that information exists, render it, otherwise don't render anything

Within the same conditional statement, we can include alternatives (using if / else). For instance, to do regional variations in a single email if you have an appropriate region or geo attribute for your users:

{% if region == 'US' %} 
20 W 34th St,
New York, NY 10001,
United States
{% elseif region == 'UK' %} 
Westminster, 
London SW1A 0AA,
United Kingdom
{% else %} 
O'Connell Street Lower,
North City, 
Dublin 1, D01 TX31
Ireland
{% endif %}
// If the region equals "US" then render the US address, if it equals UK, render the London address and otherwise render Ireland's address.

Advanced conditional statements

Another use case for conditional statements is to address inconsistency in dynamically generated links. Some links might end in a ? and some not, but we want to be able to add UTM tracking to all the links. We can handle this on the template side by using the following syntax:

{% if '?' in entry.page_url %}<a href="{{entry.page_url}}&utm_source=xp&utm_medium=email&utm_campaign=example.campaign" style="display:block; text-decoration:none;">{% else %}</a><a href="{{entry.page_urll}}?utm_source=xp&utm_medium=email&utm_campaign=blah" style="display:block; text-decoration:none;">{% endif %}

Loops

For loops can be useful for generating a section of content that has a number of similar repeating elements but whose number and content varies for users.

One common use case for this type of function is a recommendation email that runs daily or weekly and that is linked to a recommender system for products, articles or some other form of personalised content. These emails will typically have a varying number of recommendations per user per day with many different variations in content and the for loop can be used to build the personalised recommendation portion of the email for each user. This example is from an API triggered template campaign:

<p><!-- {% for entry in jobs %} --></p>
<hr noshade="noshade" color="#686868" width="100%" size="1" style="padding:0; margin:8px 0 8px 0; border:none; width:100%; height: 1px; color:#686868; background-color: #686868">
<table border="0" cellspacing="5" cellpadding="0" align="center" bgcolor="#ffffff"><tbody><tr><td width="45" rowspan="2" align="left" valign="centre"> <a href="{{entry.job.job_page_url}}" style="display:block; text-decoration:none;" data-pos="IC4AP9-t"> <img src="{{entry.brand.logo}}" alt="{{entry.brand.name}} logo" width="70" style="border-radius: 50%;"></a> </td> <td height="30" valign="bottom"><a href="{{entry.job.job_page_url}}" style="display:block; text-decoration:none;" data-pos="IDhr4HnC"><span style="color: #63c3d1; font-size: 18px; font-weight: bold; line-height: 1; vertical-align:middle;">{{entry.job.post_name }}</span></a></td></tr><tr><td valign="top" height="30"><a href="{{entry.job.job_page_url}}" style="display:block; text-decoration:none;" data-pos="eSPO0o6O"><span style="color: #686868; font-size:13px; font-weight: lighter;"><span style="color: #686868; font-size:13px; font-weight: lighter;">{{entry.brand.name}}{% if entry.brand.location %}, {{entry.brand.location}} {% endif %}</span></span></a></td> </tr></tbody></table>
<p><!-- {% endfor %} --></p>

Then content like the following is posted via API to target individual users with personalised recommendations. The job array can vary in size and content and is dynamically unpacked by the for loop template:

{"apptoken":"app_token","id":111111,"target_by":"email","target":["[email protected]"],
  "params":{"user.first_name":"BOB","jobs":[{"job.post_name":"Job1","job.job_page_url":"https://example.com/jobs/view?1",
  "brand.name":"Brand1","brand.logo":"https://example.com/logo1.jpg","brand.location":null},
  {"job.post_name":"Job2","job.job_page_url":"https://example.com/jobs/view?2","brand.name":"Brand2",
   "brand.logo":"https://example.com/logo2.jpg""brand.location":null},
  {"job.post_name":"Job3","job.job_page_url":"https://example.com/jobs/view?3",
   "brand.name":"Brand3","brand.logo":"https://example.com/logo3.jpg""brand.location":"Dublin, County Dublin, Ireland"},
  {"job.post_name":"Job4","job.job_page_url":"https://example.com/jobs/view?4","brand.name":"Brand4",
   "brand.logo":"https://example.com/logo4.jpg""brand.location":"Dublin, Ireland"},{"job.post_name":"Job5",
   "job.job_page_url":"https://example.com/jobs/view?5","brand.name":"Brand5",
   "brand.logo":"https://example.com/logo5.jpg""brand.location": "Dublin,Ireland"}]}}

In the drag and drop builder, a for loop, conditional statement, beginning and end statements can be added in custom HTML blocks to keep them separate from other content. You can see this in the example shown the article - how to work with custom HTML.

Updated about a month ago


Personalisation and dynamic programmable content


Use Twig's programmatic syntax to achieve various use cases

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.