Liquid Use Case
Overview
Liquid Tags help you create highly personalised, dynamic campaigns using a single template, rather than maintaining multiple audience segments or duplicated journeys.
This use case library demonstrates how Liquid Tags can adapt content in real time based on user attributes, dates, regions, language preferences, loyalty status, and inactivity duration. Each use case includes:
- The business problem being solved
- Recommended Liquid constructs
- Example Liquid templates
- Implementation notes and best practices
These examples are designed to help teams move beyond basic personalisation and build messaging that feels timely, relevant, and human across every customer interaction.
Click any card to expand the full Liquid template. 14 use cases across 5 patterns.
Templates that use profile attributes like name, city, or image URL to personalise message content. The right starting point for any campaign that addresses the user directly.
When first_name is missing for a subset of users, the message renders with a blank gap. The default filter prevents this. One extra filter, zero broken messages.
Hi {{ user.first_name | default: "there" }},
Your exclusive offer is waiting.
When first_name = "Ravi"
Hi Ravi, Your exclusive offer is waiting.
When first_name is missing
Hi there, Your exclusive offer is waiting.
Rule: Apply | default: to every attribute that could be null or missing for any user in your segment.
Formal campaigns often use the full name. Each part needs its own fallback so a missing last name does not break the greeting.
Dear {{ user.first_name | default: "Valued Customer" }} {{ user.last_name | default: "" }},
Your order is confirmed and on its way.
When first_name = "Priya" and last_name = "Sharma"
Dear Priya Sharma, Your order is confirmed and on its way.
When both are missing
Dear Valued Customer, Your order is confirmed and on its way.
Tip: Consider using {% assign %} to build a clean display_name variable combining both parts before outputting.
City-specific visual campaigns need the hero image to match the user's city. Without Liquid, this requires a separate campaign per city.
{% if user.city == "Mumbai" %}
https://cdn.azafashion.com/campaigns/mumbai-hero.jpg
{% elsif user.city == "Delhi" %}
https://cdn.azafashion.com/campaigns/delhi-hero.jpg
{% else %}
https://cdn.azafashion.com/campaigns/national-hero.jpg
{% endif %}
When city = "Mumbai"
https://cdn.azafashion.com/campaigns/mumbai-hero.jpg
When city is any other value
https://cdn.azafashion.com/campaigns/national-hero.jpg
Placement: This template goes in the Image URL field of the APN editor, not the body. The block outputs a plain URL with no extra characters.
Templates that read stored dates or the current date to display them in readable formats or branch into different messages based on the month or season. Replace one segment per time period with a single template.
Contextual messages based on a stored date (signup anniversary, renewal month, birthday) traditionally require one segment per month. Liquid collapses all 12 into a single template.
{% assign user_month = user.signup_date | date: "%m" %}
{% if user_month == "01" %}
Start the year strong. Your January member offer is live.
{% elsif user_month == "10" %}
Festive season is here. Explore our Diwali picks.
{% elsif user_month == "12" %}
December specials, just for members like you.
{% else %}
Your member offers are ready. Shop now.
{% endif %}
When signup_date month is January
Start the year strong. Your January member offer is live.
When signup_date month is any other month
Your member offers are ready. Shop now.
Important: The value returned by date is always a string. Compare it to "12", not 12.
Dates stored in user profiles are typically in ISO format (YYYY-MM-DD). Displaying them raw looks technical and cold. The date filter converts them into readable copy.
Your subscription renews on {{ user.renewal_date | date: "%d %B %Y" }}.
Don't miss out. Renew early and lock in your current rate.
When renewal_date = "2025-03-15"
Your subscription renews on 15 March 2025. Don't miss out. Renew early and lock in your current rate.
Format codes: %d = day, %B = full month name, %Y = four-digit year, %m = month number.
Push notifications for farmers need to be region-relevant and seasonally appropriate. Without Liquid, you need separate campaigns per state per season.
{% assign curr_month = 'now' | date: "%m" %}
{% if user.state == "Maharashtra" and curr_month == "06" %}
Monsoon is here, {{ user.first_name | default: "Farmer" }}.
Time to prepare your Kharif crops.
{% elsif user.state == "Punjab" and curr_month == "11" %}
Rabi season begins soon, {{ user.first_name | default: "Farmer" }}.
Check wheat seed availability in your area.
{% else %}
Good morning, {{ user.first_name | default: "Farmer" }}.
See today's crop advisory for your region.
{% endif %}
When state = "Maharashtra" and current month is June, first_name = "Ramesh"
Monsoon is here, Ramesh. Time to prepare your Kharif crops.
When state or month does not match
Good morning, Ramesh. See today's crop advisory for your region.
Note: 'now' | date: "%m" extracts the current month at send time, not from a stored attribute. No daily segmentation updates needed.
Templates that display a user's tier, points balance, or progress toward the next reward level. Use these to make loyalty communications feel specific to each member rather than generic broadcast messages.
Tiered loyalty programmes need different messaging per tier. Platinum users get early access, Silver users get a nudge to upgrade, and new users get an invitation to join. One campaign covers all four.
{% if user.loyalty_tier == "platinum" %}
{{ user.first_name | default: "Member" }}, your early-access sale starts today.
{% elsif user.loyalty_tier == "gold" %}
{{ user.first_name | default: "Member" }}, Gold members get 24-hour early access.
{% elsif user.loyalty_tier == "silver" %}
You're {{ user.points_to_gold | default: "just a few" }} points away from Gold.
{% else %}
Join our loyalty programme and start earning rewards today.
{% endif %}
When loyalty_tier = "platinum" and first_name = "Ananya"
Ananya, your early-access sale starts today.
When loyalty_tier = "silver" and points_to_gold = 120
You're 120 points away from Gold.
When no tier is set
Join our loyalty programme and start earning rewards today.
Note: user.points_to_gold must be pre-calculated by your loyalty engine and synced to Netcore as a user attribute.
Showing a user's actual points balance and what it can be redeemed for gets more action than a generic points reminder.
{% if user.loyalty_points >= 500 %}
You have {{ user.loyalty_points }} points. Enough to redeem a voucher.
Tap to redeem before they expire.
{% elsif user.loyalty_points > 0 %}
You have {{ user.loyalty_points }} points.
Earn more to unlock your first reward.
{% else %}
Start earning points today.
Every purchase brings you closer to your first reward.
{% endif %}
When loyalty_points = 750
You have 750 points. Enough to redeem a voucher. Tap to redeem before they expire.
When loyalty_points = 0
Start earning points today. Every purchase brings you closer to your first reward.
Tip: The high-balance branch builds goodwill with active users. Not every notification should be a warning.
Templates that branch on user attributes such as gender, language, or country to show different content in a single send. Each branch has a fallback for users whose attribute is not recorded.
Gendered product campaigns without Liquid require two separate sends. Liquid collapses this into a single template with a fallback for users whose gender is not recorded.
{% if user.gender == "male" %}
Picks for you: Oversized Tees, Cargo Shorts, Sneakers
{% elsif user.gender == "female" %}
Picks for you: Printed Kurtis, Denim Jackets, Tote Bags
{% else %}
Our latest collection has something for everyone.
{% endif %}
When gender = "male"
Picks for you: Oversized Tees, Cargo Shorts, Sneakers
When gender is not set
Our latest collection has something for everyone.
Critical: The else branch matters here more than almost anywhere. Gender is frequently unset for a large share of any audience.
Running separate campaigns per language is costly to maintain. One Liquid template handles multiple languages and falls back to English when no match is found.
{% if user.language == "ms" %}
Hai {{ user.first_name | default: "Pelanggan" }},
Pelan anda akan tamat tempoh pada {{ user.renewal_date | date: "%d %B %Y" }}.
{% elsif user.language == "zh" %}
您好 {{ user.first_name | default: "客户" }},
您的套餐将于 {{ user.renewal_date | date: "%d %B %Y" }} 到期。
{% else %}
Hi {{ user.first_name | default: "there" }},
Your plan expires on {{ user.renewal_date | date: "%d %B %Y" }}.
{% endif %}
When language = "ms", first_name = "Amir", renewal_date = "2025-06-30"
Hai Amir, Pelan anda akan tamat tempoh pada 30 June 2025.
When language = "en", first_name = "Sarah"
Hi Sarah, Your plan expires on 30 June 2025.
Note: Language codes should match the values stored in your user profiles. ISO 639-1 codes (ms, zh, en) are standard. Confirm against your schema.
A price shown in INR to a UAE customer creates confusion. Liquid outputs the right currency symbol and price based on the user's country, without a separate campaign per region.
{% if user.country == "IN" %}
Prices from ₹4,999. Shop the exclusive collection.
{% elsif user.country == "AE" %}
Prices from AED 225. Shop the exclusive collection.
{% elsif user.country == "GB" %}
Prices from £49. Shop the exclusive collection.
{% else %}
Shop our exclusive collection. Prices in your local currency at checkout.
{% endif %}
When country = "IN"
Prices from ₹4,999. Shop the exclusive collection.
When country = "AE"
Prices from AED 225. Shop the exclusive collection.
Note: Currency values are hardcoded here. For real-time exchange rates, this use case requires Content Fetch alongside Liquid Tags.
Templates for time-sensitive and transactional messages: policy renewals, wallet top-ups, and win-back offers. Urgency and offer size adapt automatically based on numeric attributes synced from your system.
A generic renewal reminder gets ignored. One that names the policy, shows the expiry date, and adjusts urgency based on days remaining gets acted on.
Dear {{ user.first_name | default: "Policyholder" }},
Your {{ user.policy_name | default: "life insurance policy" }}
(Policy No. {{ user.policy_number }}) is due for renewal on
{{ user.policy_expiry_date | date: "%d %B %Y" }}.
{% if user.days_to_expiry <= 7 %}
Your policy expires in {{ user.days_to_expiry }} days.
Renew immediately to ensure continuous coverage.
{% elsif user.days_to_expiry <= 30 %}
Renew in the next {{ user.days_to_expiry }} days to avoid a lapse.
{% else %}
Plan ahead and renew your policy before the due date.
{% endif %}
When first_name = "Rahul", policy_name = "Term Life Plan", policy_number = "LI-2891023", expiry = "12 May 2025", days_to_expiry = 5
Dear Rahul, Your Term Life Plan (Policy No. LI-2891023) is due for renewal on 12 May 2025. Your policy expires in 5 days. Renew immediately to ensure continuous coverage.
Dependency: user.days_to_expiry must be pre-calculated daily by the policy management system and synced to Netcore as a numeric attribute.
A notification showing the exact balance and what it covers is more actionable than a generic low-balance alert. Agents can take action immediately without opening the app.
{% if user.wallet_balance < 100 %}
Low balance alert, {{ user.first_name | default: "Agent" }}.
Your wallet has ₹{{ user.wallet_balance }} remaining.
Top up now to continue serving your customers.
{% elsif user.wallet_balance < 500 %}
Your wallet balance is ₹{{ user.wallet_balance }}.
Consider topping up before your next busy day.
{% else %}
Good news, {{ user.first_name | default: "Agent" }}.
Your wallet balance of ₹{{ user.wallet_balance }} is healthy.
{% endif %}
When first_name = "Suresh" and wallet_balance = 45
Low balance alert, Suresh. Your wallet has ₹45 remaining. Top up now to continue serving your customers.
When first_name = "Suresh" and wallet_balance = 1200
Good news, Suresh. Your wallet balance of ₹1,200 is healthy.
Design principle: The high-balance branch gives positive reinforcement. Not every notification should be a warning.
Win-back campaigns need different offer sizes based on how long a user has been inactive. Doing this with segments means duplicating campaigns. One Liquid template handles all three tiers.
{% if user.days_inactive >= 90 %}
We miss you, {{ user.first_name | default: "there" }}.
Here's 30% off your next order. Use code: COMEBACK30
{% elsif user.days_inactive >= 60 %}
Hey {{ user.first_name | default: "there" }}, it's been a while.
Here's 20% off. Use code: RETURN20
{% elsif user.days_inactive >= 30 %}
Hi {{ user.first_name | default: "there" }}, come back
and get 10% off. Use code: BACK10
{% endif %}
When first_name = "Arjun" and days_inactive = 95
We miss you, Arjun. Here's 30% off your next order. Use code: COMEBACK30
When first_name = "Arjun" and days_inactive = 35
Hi Arjun, come back and get 10% off. Use code: BACK10
Note: No else branch here. This template is for a pre-filtered audience of inactive users (30 or more days). Match your segment to your Liquid logic.
Updated about 3 hours ago
