# How to Deploy Liquid Code for a Highly Personalized CRM Strategy

- Link: https://phiture.com/mobilegrowthstack/how-to-deploy-liquid-code-crm/
- Published: 2023-06-20T08:59:45+01:00
- Author: Alejandra Escobal

Delivering a highly personalized user experience is one way to stand out from the
crowd for your users.  [Phiture’s partner Braze](https://phiture.com/braze/) – the
leading customer engagement platform – relies on Liquid code to help their clients
deliver this personalized experience. 

Originally developed by Shopify, and [now an open source project](https://github.com/Shopify/liquid)
on Github, Liquid is a versatile templating language written in Ruby that enables
the dynamic rendering of content in different channels, such as emails, push notifications,
and in-app messages. Due to its simplicity, flexibility, and ease of integration,
Liquid has become a popular framework for developers to manipulate, format, and 
display data, allowing for the creation of tailored and customizable content.

This article explores the world of Liquid, its purpose, and use cases. We explain
why decision-makers should consider incorporating Liquid into their CRM Strategies,
and some common examples of its application with [Braze.](https://www.braze.com/)

 

### **The importance of personalization**

We cannot underline enough how important personalization is. At a top level, [76% of consumers are more likely to consider purchasing from brands that personalize.](https://www.mckinsey.com/capabilities/growth-marketing-and-sales/our-insights/the-value-of-getting-personalization-right-or-wrong-is-multiplying)
This is also reflected in [Braze’s experience of using personalization](https://www.braze.com/resources/reports-and-guides/the-power-of-personalization)
across different channels, where they recorded:

 * 40% uplift in in-app message click rates
 * 37% uplift in email click rates
 * 48% uplift in mobile push open rates

So why doesn’t everyone embrace personalization given the uplifts? Well, if a CRM
Team needs to implement individual variants for each campaign, it quickly becomes
very time consuming, and CRM teams typically have limited resources. Indeed, it’s
with this problem that Liquid is able to play a role. 

 

#### **Beyond basic personalization**

While personalization is key to engaging users, just adding the first name and sending
in the preferred language of the user is not enough. Liquid can help your brand 
resonate with each individual customer by incorporating rules based on the user’s
behavior in the app/website, and dynamically generating content based on custom 
data and preferences. For example, using connected content or Braze catalogs to 
provide product recommendations based on previous purchases. This helps maintain
consistency across all customer interactions and strengthens brand affinity.

#### **The importance of good taxonomy**

Scoping your app’s or website taxonomy when creating your Lifecycle Communications
Roadmap is of utmost importance, as it lays the foundation for effective personalization
using Liquid Code in Braze. 

A well-defined taxonomy ensures clarity and consistency, allowing CRM Teams to know
which custom attributes, event properties, and API-trigger properties are available
to use for personalization purposes, as well as their format and type (string, array).
This will enable them to know which tags and operators from Liquid Code are most
useful and ensures seamless integration with data sources that will later feed all
personalized campaigns. Ultimately, a good taxonomy serves as a guiding framework
for CRM Managers and empowers them to create impactful campaigns.

 

### **Examples of How to Program Liquid for an App**

#### **Basic personalization: Name, Language**

Liquid provides a vast number of [objects, tags, filters, and operators](https://shopify.github.io/liquid/tags/iteration/)
that help you insert information into the message, even giving the right format.
This will give consistency and a professional look across all channels. One of the
most used tags is the “if” statement”, which allows you to establish rules and conditions
to display (or not display) content. For example:

First, we determine the languages we want to use. We want to display the copy in
Spanish or a default language (English):

    ```lang-js
    {% if {{${language}}} == "es" %}
          Gracias por tu compra 
    {% else %}
          Thanks for your order.
    {% endif %}
    ```

Then, we check if the user has a first name on their user profile. If there’s no
first name, we make sure we don’t have any blank spaces:

    ```lang-js
    {% if {{${language}}} == "es" %}
    ¡{% if ${first_name} != blank %}{{${first_name}}}, g{% else %}G{% endif %}racias por tu compra! 
    {% else %}
    {% if ${first_name} != blank %}{{${first_name}}}, t{% else %}T{% endif %}hanks for your order! 
    {% endif %}
    ```

Finally, we want to make sure that we have the right format, so the name is in the
correct case. 

    ```lang-js
    {% if {{${language}}} == "es" %}
    ¡{% if ${first_name} != blank %}{{${first_name} | capitalize}}, g{% else %}G{% endif %}racias por tu compra! 
    {% else %}
    {% if ${first_name} != blank %}{{${first_name} | capitalize}}, t{% else %}T{% endif %}hanks for your order! 
    {% endif %}
    ```

#### **The result:**

#### If there is a first name, for example, “Alexa” , and the language is Spanish, it’ll generate “¡Alexa, gracias por tu compra!”

 

![](https://phiture.com/wp-content/uploads/2023/06/image5-2-e1687247073603.png)

If there’s no first name and the language is not Spanish, for example Dutch, it 
will generate, “Thanks for your order!”

![](https://phiture.com/wp-content/uploads/2023/06/image3-3-e1687247170522.png)

Other things that can be edited in a similar fashion to this example include: 

 * append
 * capitalize
 * downcase
 * first
 * last
 * upcase
 * split
 * [date format](https://strftime.net/)

 

### **Dynamic content using event properties**

By leveraging event properties, as well as custom attributes, you can dynamically
insert information based on a user’s action in the app. If you have a triggered 
campaign, you can insert Liquid tags with all the event properties included in the
triggering event. This will enable real-time messages with specific information 
about user behavior. For example, if you wanted to trigger an abandoned cart nudge
to users who added an item but didn’t complete the purchase.

    ```lang-ruby
    {% if {{${language}}} == "es" %}
         ¿{% if ${first_name} != blank %}{{${first_name} | capitalize}}, a{% else %}A{% endif %}ún estás interesado en comprar {{event_property.${product_name} | capitalize}}?
    {% else %}
         {% if ${first_name} != blank %}{{${first_name} | capitalize}}, a{% else %}A{% endif %}re you still interested in buying {{event_property.${product_name} | capitalize}}. 
    {% endif %}
    ```

#### **In this script we are: **

 * Asking the user’s preferred language. If the user doesn’t speak Spanish, we show
   the default (English).
 * We’re formatting the copy to display the first name of the user (if any) with
   the proper case.
 * We’re adding the name of the product the user added to their cart but didn’t 
   buy.

 

**The result:**
 Alexa, are you still interested in buying Cool T-Shirt?

### 

### **Highly personalized messages **

Liquid code’s power is truly evident when you utilize Control Flows, Iterations,
Templates, and Variables tags.

 * **Control Flows**, create conditions that decide whether blocks of Liquid code
   get executed. Here’s where we use “if” statements, the most commonly used and
   useful tag we will use.
 * **Iterations**, repeatedly run blocks of code. One of the most common tags is“
   for,” which is commonly used to find objects inside an array. Check out the example
   below.
 * **Templates** tell Liquid where to disable processing for comments or non-Liquid
   markup, and how to establish relations among template files. “comment” is the
   most used one: {% comment %} Your comment here {% endcomment %}
    Variables create
   new variables. For example, “assign” and “capture.”

Combining these with Braze’s features, such as connected content, promotional codes,
and catalogs, you can build automated flows where users receive tailored recommendations,
timely messages, and highly personalized content in real time with less effort on
the part of the CRM Team. That’s because once set up, it’s continuously maintaining
and monitoring performance.

For example, based on the user’s order, you can recommend more products, encouraging
re-purchases. This could be a dynamic product carousel displayed as in-app messages.

    ```lang-ruby
    {% connected_content https://yourAPIurl.com :save response %}
    {% assign favoriteProducts = {{custom_attribute.${favorite_products}}} %}
    {% assign productids = {{response.data.campaigns[0].content.productids}}%}
    {% assign productbought ={{event_property.${product_name}}} %}

    {% for favorite_product in {{favoriteProduct}} %}
      {% assign id = {{ids[favorite_product["id"]]}} %}
      {% if {{id}} != nil %}
       {% break %}
      {% endif %}
    {% endfor %}
    {% if id == nil %}
    {% abort_message('No match found') %}
    {% else %}
    People that bought {{productbought}} also liked {{id.ProductName}}
    {% endif %}
    ```

Here we’re using the %for% loop to find a match between the product ids in the catalog
or connected content call, and the “ids” inside the array favoriteProducts. If it
matches, you send the message.

 

#### **The result: **

People that bought Cool T-Shirt also liked Awesome Sweatshirt. 

![](https://phiture.com/wp-content/uploads/2023/06/image2-3.png)

Another interesting use case is using Liquid Code for Dynamic pricing, the practice
of having multiple price points based on a few critical factors, such as user behavior
or characteristics. [You can read more about this strategy and how to implement it in Braze here](https://phiture.com/mobilegrowthstack/the-ethics-of-dynamic-pricing-the-good-the-bad-and-the-ugly/).

### **Transactional messages using API-triggered campaigns**

Transactional API-Triggered campaigns are set up with Braze where the CRM manager
takes care of all the settings except the actual sending, as the IT Team or Developer
usually performs this task. 

API-triggered campaigns are ideal for more advanced transactional use cases. These
allow marketers to manage campaign copy, multivariate testing, and re-eligibility
rules within the Braze dashboard while triggering the delivery of that content from
their servers and systems. The API request to trigger the message can also include
additional data to be templated into the message in real-time (similar to event 
properties).

To facilitate and make the code more readable, when using Liquid Code it’s better
to assign tags to all the items from the API call at the beginning of the HTML and
later just name them in the HTML body. 

For example, this is the information you’re receiving from the API call (payload)

    ```lang-ruby
    "campaign_id": "YOUR-CAMPAIGN-ID",
            "recipients": [

               {
                 "external_user_id": user_1234,
                 "trigger_properties": {
                   "first_name": "John",
                   "language": "en",
                   "order_number": "12345",
                   "order_items": [
                   {
                      "product_id": "product_1",
                      "product_name": "Product 1",
                      "quantity": "1",
                      "price": "32.99",
                      "price_formatted": "32,99 €",
                      "image_link": "image.png",
                      "product_link": "mywebsite.com/product-1"
                   }
                ]
              }
    ```

Then, in the HTML, you can assign a tag to each item and make the content fully 
dynamic. 

    ```lang-ruby
    {% assign fname = {{api_trigger_properties.${first_name}}} %}   
    {% assign language = {{api_trigger_properties.${language}}}%}
    {% assign order_id = {{api_trigger_properties.${order_number}}}%}
    {% assign product_name = {{api_trigger_properties.${order_items.product_name}}}%}
    {% assign price = {{api_trigger_properties.${order_items.price_formatted}}}%}
    {% assign quantity = {{api_trigger_properties.${order_items.quantity}}}%}

    <!DOCTYPE html>
    <html>
    <head>
          <meta charset="utf-8">
          <title>Order Confirmation - {{ order_ide }}</title>
    </head>
    <body>
          <div>
                <p>Dear {{ fname }},</p>
                <p>Thank you for your order!</p>

           <table>
               <thead>
                     <tr>
                         <th>Product Name</th>
                         <th>Quantity</th>
                         <th>Price</th>
                     </tr>
              </thead>
              <tbody>
                    {% for order_item in {{api_trigger_properties.${order_items}}} %}
                     <tr>
                          <td>{{ product_name}}</td>
                          <td>{{ quantity }}</td>
                          <td>{{ price | money }}</td>
                     </tr>
                       {% endfor %}
             </tbody>
             <tfoot>
                  <tr>
                        <td></td>
                        <td><strong>Total:</strong></td>
                        <td>{{ price | money }}</td>
                  </tr>
             </tfoot>
           </table>
           <p>If you have any questions or concerns about your order, please don't hesitate to contact us.</p>
           <p>Thank you for shopping with us!</p>
         </div>
    </body>
    </html>
    ```

For order confirmation emails, consider using %for% statements to make the HTML 
dynamic and display all products purchased. For example:

    ```lang-ruby
    {% assign order_items = {{api_trigger_properties.${order_items}}} %} 
    {% for order_item in order_items %}
        {% assign product_id = {{order_item.product_id}} %}     
        {% assign img = {{order_item.image_link}} %} 
        {% assign url = {{order_item.product_url}} %}
        {% assign price = {{order_item.price}} %}
        {% assign quantity = {{order_item.quantity}} %}
        {% assign price_formatted = {{order_item.price_formatted}} %}
        {% assign voucher = {{order_item.used_voucher}} %}
        {% assign code = {{order_item.voucher_code}} %}
        {% assign alt = {{order_item.product_name}} %}
        {% assign product_name = {{order_item.product_name}} %}

         <tr>
         <!-- 1. Space Column left 10px -->
         <html info> 
         <!-- 2. Column Product image --> 

         <a href="{{url}}">

         <!-- 3. Column Product name -->
           <HTML info> {{product_name}}
         <!-- 4. Column Quantity -->
           <HTML info>{{quantity}}  

         <!-- 5. Column Price -->
           <HTML info>{{price_formatted}}
         <!-- 6. Space Column right 10px -->    
           <HTML info>

    {% endfor %}
    ```

### 

_An example of an order confirmation message with Liquid_

### **Conclusion**

Incorporating Liquid into your CRM strategy is a game-changer for delivering a highly
personalized and engaging customer experience. Using Liquid goes far beyond basic
personalization, allowing you to create tailored messages with dynamic content based
on the user’s behavior and characteristics. Liquid Code can empower your App to 
connect with your customers on a deeper level, driving increased engagement, conversion,
and brand loyalty. As a Braze partner and heavy users of Liquid, we have witnessed
the impact of Liquid in CRM Strategies, allowing teams to be more efficient when
creating campaigns, unlocking Braze’s full potential, and rocketing your App to 
success. 

 

### **Before you go**

 * Need support to understand how to deploy Liquid Code to supercharge your CRM 
   strategy? [Reach out to us here.](https://phiture.com/work-together/) 
 * Phiture’s Subscription Stack is designed to help growth marketers conceptualize
   their subscription optimization strategy and understand the essential components
   of running a mobile subscription business. CRM is vital across the stack, and
   [you can check it out here. ](https://phiture.com/subscriptionstack/)
 * [Phiture’s Mobile Growth Stack Slack Community](https://phiture.com/mobile-growth-stack-slack-community/)
   brings together professionals from around the world, who are engaging with technology
   like Liquid to supercharge their CRM strategy. Join today to stay on top of the
   latest industry updates and trends, pose questions (or answer them), and connect
   with fellow mobile growth marketers. 

 

### **Further Reading**

[Read Github’s guide to Liquid Code.](https://shopify.github.io/liquid/)

[Braze’s guide to personalization using liquid tags. ](https://www.braze.com/docs/user_guide/personalization_and_dynamic_content/liquid)

[Read Braze’s guide to API campaigns. ](https://www.braze.com/docs/api/api_campaigns/)

 

 

 
