Personalize emails with Liquid
This page lists the Liquid email personalization ReputeCast supports in campaign subjects, preheaders, email bodies and link URLs: the personalization tokens, filters and tags, and what happens when a value is missing.
ReputeCast renders Liquid with the osteele/liquid engine (version 1.9.2), once per recipient at send time. Transactional templates use the variables you declare for each template instead; see transactional templates.
Syntax
Section titled “Syntax”| Form | Example | Prints |
|---|---|---|
| Variable | {{ first_name }} |
The contact’s first name, or nothing when it is empty. |
| Variable with a fallback | {{ first_name | default: "there" }} |
The first name, or there when it is empty. |
| Short fallback | {{ first_name | "there" }} |
The same: ReputeCast rewrites it to default: "there". |
| Filters, chained left to right | {{ first_name | downcase | capitalize }} |
Ana for ANA. |
| Tag | {% if plan == "pro" %}…{% endif %} |
The block between the tags when the condition holds. |
| Whitespace control | {{- first_name -}} |
The value, with the spaces and line breaks around it removed. |
Variables, filter names and tags are lowercase. Insert a token from the text toolbar with Insert a personalization token; it adds the suggested fallback for you (there for first_name, free for a custom field called plan). In the MJML view, the Tokens tab lists the same tokens; select one to copy it.
Variables
Section titled “Variables”Contact
Section titled “Contact”| Variable | Holds | Notes |
|---|---|---|
first_name, last_name, email |
The contact’s first name, last name and email address. | Also as contact.first_name, contact.last_name, contact.email. |
<field key>, for example plan |
The value of one of the workspace’s custom fields, with its type (text, number, date, boolean or select). | Also as contact.<field key>. Keys use lowercase letters, digits and _, and start with a letter. |
Other contact data, such as company, country, language, tags or engagement tier, isn’t available as a variable. To show different content to different contacts, use conditional content instead.
Links ReputeCast fills in per recipient
Section titled “Links ReputeCast fills in per recipient”| Variable | Holds | Notes |
|---|---|---|
unsubscribe_url |
The recipient’s own unsubscribe page. | The Footer + unsubscribe block links to it; the content checks require a visible unsubscribe link. |
preferences_url |
The recipient’s preference center. | |
view_in_browser_url |
The recipient’s own copy of the email on the web. | |
upgrade_url |
The recipient’s personal upgrade page. | Paid subscriptions only. Never click-tracked. |
manage_subscription_url |
The recipient’s page to manage a paid subscription. | Paid subscriptions only. Never click-tracked. |
In a test send these links point to test pages, and in the composer’s preview they read “per-recipient link”.
Paid access
Section titled “Paid access”| Variable | Holds | Notes |
|---|---|---|
paid.tier |
The name of the reader’s paid tier. | Every paid.* value is empty for free subscribers. |
paid.status |
The reader’s subscription status, for example Active. | |
paid.price |
The price the reader pays, for example $80/year. |
|
paid.renews_at |
The renewal date. | |
paid.ends_at |
The date access ends, for a cancelled subscription. |
Referral program
Section titled “Referral program”These are empty for readers who aren’t in a referral program; the Referral block hides itself for them.
| Variable | Holds | Notes |
|---|---|---|
referral.link |
The reader’s referral link. | |
referral.code |
The reader’s referral code. | |
referral.hub_url |
The reader’s rewards page. | |
referral.count |
Referrals that counted. | |
referral.pending |
Referrals not counted yet (still in their hold period). | |
referral.next_milestone.count |
The referrals the next milestone needs. | |
referral.next_milestone.reward |
The next milestone’s reward. | |
referral.to_next |
Referrals still needed for the next reward. | |
referral.rewards |
Rewards the reader has earned. |
Milestone emails also have reward.name, reward.description, reward.note, reward.download_url, reward.code, reward.claim_url, reward.expires_at, reward.url and reward.image_url for the reward being sent.
Recommendations block
Section titled “Recommendations block”recommendations.show, recommendations.url and recommendations.items hold the data of the Recommendations block. Each item has id, name, description, kind, initials, host, button, logo_url and url. See recommend other newsletters.
Recurring digests
Section titled “Recurring digests”Digest templates have the issue’s data. It is the same for every recipient and is filled in when the issue is built.
| Variable | Holds | Notes |
|---|---|---|
feed.title |
The feed’s title. | |
feed.url |
The feed’s address. | |
issue.number |
The issue number. | |
issue.date |
The send day. | |
issue.items |
The issue’s posts. Each has title, url, date, author, image, excerpt and categories. |
Loop with {% for item in issue.items %}, or use issue.items.size and issue.items.first.title. |
Variables you don’t type
Section titled “Variables you don’t type”Variables whose names start with rc_ (rc_poll_…, rc_survey_…, rc_open_url, rc_link_…) are written by ReputeCast’s Poll block, survey links and tracking. They change per recipient; leave them as they are.
There are no workspace.* or campaign.* variables. The postal address in the footer is plain text that comes from your workspace’s footer address in Settings, then Senders.
Filters
Section titled “Filters”Filters change a value: {{ value | filter }} or {{ value | filter: argument, argument }}. ReputeCast supports the engine’s standard filters and adds with_query.
| Filter | Example | What it does |
|---|---|---|
default |
{{ first_name | default: "there" }} |
Uses the fallback when the value is missing, empty or false. A value of only spaces isn’t empty. Add allow_false: true to keep false. |
with_query |
{{ upgrade_url | with_query: "offer", "FALL26" }} |
Sets one query parameter on an http or https link and leaves anything else unchanged. Can be chained. |
append, prepend |
{{ first_name | append: "," }} |
Adds text after or before the value. |
upcase, downcase, capitalize |
{{ first_name | capitalize }} |
Changes letter case. capitalize lowercases the rest of the text. |
strip, lstrip, rstrip, strip_html, strip_newlines, newline_to_br |
{{ bio | strip_html }} |
Remove spaces, HTML tags or line breaks, or turn line breaks into <br>. |
replace, replace_first, replace_last, remove, remove_first, remove_last |
{{ company_name | remove: " Inc." }} |
Replace or remove part of the text. |
truncate, truncatewords, slice, split |
{{ headline | truncate: 40 }} |
Shorten or cut the text. |
escape, escape_once, url_encode, url_decode, handleize |
{{ city | url_encode }} |
Make text safe for HTML or a URL, or turn it into a lowercase hyphenated handle. |
plus, minus, times, divided_by, modulo, abs, ceil, floor, round, at_least, at_most |
{{ points | plus: 10 }} |
Arithmetic on numbers. |
pluralize |
{{ referral.to_next | pluralize: "referral", "referrals" }} |
Picks the singular word when the number is 1, else the plural. |
date |
{{ trial_ends | date: "%d %B %Y" }} |
Formats a date with strftime codes. |
size, first, last, join, map, where, sort, sort_natural, uniq, reverse, compact, concat, sum |
{{ issue.items | map: "title" | join: ", " }} |
Work on lists, such as a digest’s items. |
json, inspect, type |
{{ contact | json }} |
Print a value as JSON or name its type, for debugging a test send. |
Values are inserted as they are stored, without HTML escaping. Add | escape to a custom field that could hold <, > or &.
| Tag | Use |
|---|---|
if, elsif, else, unless |
Show text when a condition holds, for example {% if paid.tier != "" %}. |
case, when, else |
Pick one of several texts by value. |
for (with else, limit, offset, reversed, ranges), break, continue, cycle, tablerow |
Loop over a list. Inside the loop, forloop.index, forloop.first, forloop.last and forloop.length are available. |
assign, capture |
Store a value or a piece of text in a variable for later. |
comment, raw |
Leave a note that never prints, or print Liquid code as text. |
include and render aren’t available: an email can’t load another template, and using either tag is a syntax error on its line.
Missing values and errors
Section titled “Missing values and errors”| Situation | What happens |
|---|---|
| The contact has no value | The token prints nothing, or its fallback. The composer’s preview notes how many recipients have no first name and see the fallback. |
| A token isn’t a known field and has no fallback | The composer warns “{{ key }} isn’t a contact field; it prints nothing”. Check the spelling, or add a fallback. |
A syntax error (an unclosed tag, include, a typo in a tag) |
The composer shows a Block naming the part (Subject, Preheader or Body) and the line. A send can’t start while the personalization doesn’t render. See fix content warnings. |
| A filter name that doesn’t exist | The syntax check doesn’t catch it. The preview shows the failing part as raw text with the error, and at send time each message that uses it fails. Check filter names against the table above. |
| The rendered email is larger than 4 MB | The message fails with “the rendered email is larger than 4 MB”. |
A for loop over a literal range of more than 1,000 items |
A syntax error: loops over a range are limited to 1,000 items. |
- Preview as in the preview fills every token for a real contact, a contact without a first name, or a random Active contact; the Personalization card lists each token with its value. Real contacts need
subscribers:view. See design emails in the composer. - Tokens work in link addresses too, for example
https://example.com/welcome?ref={{ email | url_encode }}. The content checks skip links that contain{{or{%. - A preview takes a contact’s first name up to the first space; the send uses the first name as stored.