What Youβll Learn in This Module
Filters are Liquidβs tools for transforming data. In this module, youβll learn every standard text filter available in Cast β the tools for changing capitalization, trimming whitespace, replacing or removing characters, adding text to the beginning or end of a value, cutting text short, counting characters, splitting strings into arrays, and providing safe fallbacks for missing data.
By the end of this module, youβll be able to take any messy text value from a CRM and transform it into exactly the clean, formatted output your Cast narration needs.
What Is a Text Filter?
A filter is a small transformation you apply to a value using the pipe character (|). Text filters specifically work on strings β they take text in, change it somehow, and pass the changed text out.
Excel analogy: Text filters are Liquidβs equivalent of Excelβs text functions β
UPPER(),LOWER(),TRIM(),SUBSTITUTE(),LEFT(), and so on. If youβve ever cleaned up messy spreadsheet data with those functions, you already understand what text filters do. The only difference is the syntax: instead of=UPPER(A1), you write{{ value | upcase }}.
You can chain multiple filters together, and they execute left to right:
{{ value | filter1 | filter2 | filter3 }}
The original value flows into filter1, the result flows into filter2, and that result flows into filter3. What comes out the end is what the customer sees.
Why text filters matter in Cast
CRM data is messy. Company names arrive in ALL CAPS. Names have extra spaces. Fields contain characters you need to remove or replace. Text filters are how you take raw CRM data and make it presentation-ready β clean, properly formatted, and professional.
Quick Reference β All Standard Text Filters
Before diving into each filter, hereβs the complete list for reference. Each one is explained in detail below.
| Filter | What It Does | Input β Output |
|---|---|---|
upcase | Convert to ALL CAPS | "acme" β "ACME" |
downcase | Convert to all lowercase | "ACME" β "acme" |
capitalize | Uppercase first letter only | "acme corp" β "Acme corp" |
strip | Remove leading/trailing spaces | " acme " β "acme" |
replace | Replace all occurrences of text | "hello" \| replace: "l", "r" β "herro" |
remove | Remove all occurrences of text | "hello" \| remove: "l" β "heo" |
append | Add text to the end | "hello" \| append: "!" β "hello!" |
prepend | Add text to the start | "hello" \| prepend: "Say " β "Say hello" |
truncate | Cut to n characters (adds ...) | "hello world" \| truncate: 8 β "hello..." |
truncatewords | Cut to n words (adds ...) | "one two three" \| truncatewords: 2 β "one two..." |
size | Count characters (or array items) | "hello" \| size β 5 |
split | Split string into an array | "a,b,c" \| split: "," β ["a","b","c"] |
default | Fallback if nil or empty | "" \| default: "N/A" β "N/A" |
Now letβs explore each one.
upcase β Convert to ALL CAPS
What is it?
The upcase filter converts every letter in a string to uppercase. Numbers, spaces, and punctuation are unaffected.
Excel analogy: Identical to
=UPPER(A1).
Why it matters in Cast
Use upcase when you want to emphasize a word or ensure consistency in labels, headings, or status values that should always appear in capitals.
Liquid syntax
{{ "acme corp" | upcase }} β ACME CORP
{{ product_tier | upcase }} β ENTERPRISE (if product_tier is "Enterprise")
Real Cast example
Status: {{ product_tier | upcase }}
If product_tier is "Professional", output: Status: PROFESSIONAL
Common mistakes
β Using upcase on company names for display:
{{ contact_account_name | upcase }} β ACME LLC
This works, but most of the time you want title case, not ALL CAPS. Company names in all caps look like theyβre shouting.
β
Use cast_titlecase for company names (Module 8):
{{ contact_account_name | cast_titlecase }} β Acme LLC
downcase β Convert to All Lowercase
What is it?
The downcase filter converts every letter to lowercase. The opposite of upcase.
Excel analogy: Identical to
=LOWER(A1).
Why it matters in Cast
Use downcase when you need to normalize text for comparison. String comparisons in Liquid are case-sensitive β "Enterprise" does not equal "enterprise". Converting both sides to lowercase before comparing ensures you catch all variations.
Liquid syntax
{{ "ACME CORP" | downcase }} β acme corp
{{ contact_email | downcase }} β jason@acme.com
Real Cast example
Normalizing a value before comparison:
{%- assign tier = product_tier | downcase -%}
{% if tier == "enterprise" %}
You have access to all premium features.
{% endif %}
This catches "Enterprise", "ENTERPRISE", "enterprise", and any other casing variation.
Common mistakes
β Case-sensitive comparison without normalizing:
{% if product_tier == "enterprise" %}
This fails if the CRM stores it as "Enterprise" or "ENTERPRISE".
β
Normalize with downcase first:
{%- assign tier = product_tier | downcase -%}
{% if tier == "enterprise" %}
capitalize β Uppercase First Letter Only
What is it?
The capitalize filter makes the first character of the string uppercase and leaves everything else exactly as it is. It does not capitalize the first letter of every word β only the very first character of the entire string.
Excel analogy: Similar to
=PROPER(A1), but only for the first letter β not each word. There isnβt a perfect Excel equivalent; itβs more like=UPPER(LEFT(A1,1)) & MID(A1,2,LEN(A1)).
Why it matters in Cast
capitalize is useful for ensuring a sentence or label starts with a capital letter, especially when the value comes from a CRM field that might be all lowercase. However, itβs not the right tool for company names β for that, use cast_titlecase.
Liquid syntax
{{ "acme corp" | capitalize }} β Acme corp
{{ "hello world" | capitalize }} β Hello world
{{ "ACME CORP" | capitalize }} β ACME CORP (only affects the first character)
Notice the critical detail: capitalize does NOT lowercase the rest of the string. If the input is "ACME CORP", the first character is already uppercase, so nothing changes.
Real Cast example
{%- assign status = account_status | downcase | capitalize -%}
Account status: {{ status }}
If account_status is "ACTIVE":
downcaseβ"active"capitalizeβ"Active"
Output: Account status: Active
Common mistakes
β Expecting capitalize to title-case every word:
{{ "acme corp" | capitalize }} β "Acme corp" (NOT "Acme Corp")
β
Use cast_titlecase for proper company name casing:
{{ "acme corp" | cast_titlecase }} β "Acme Corp"
β Using capitalize on ALL CAPS input expecting it to fix casing:
{{ "JOHN SMITH" | capitalize }} β "JOHN SMITH" (unchanged!)
capitalize only uppercases the first character. It doesnβt lowercase anything.
β
Chain downcase first, then capitalize:
{{ "JOHN SMITH" | downcase | capitalize }} β "John smith"
(Still not ideal for names β but correct behavior for how these filters work.)
strip β Remove Leading and Trailing Whitespace
What is it?
The strip filter removes spaces, tabs, and newlines from the beginning and end of a string. It does not touch whitespace in the middle of the string.
Excel analogy: Identical to
=TRIM(A1), which removes extra spaces from both ends of a cell value.
Why it matters in Cast
CRM data frequently arrives with invisible extra spaces β a name field might contain " Jason " or a snippet might return " yes ". These hidden spaces cause string comparisons to fail silently. strip is your first line of defense.
Liquid syntax
{{ " hello world " | strip }} β "hello world"
{{ " Jason " | strip }} β "Jason"
Real Cast example
The most critical use of strip is when comparing snippet output:
{%- assign region = IsEMEA | strip -%}
{% if region == "yes" %}
EMEA-specific content.
{% endif %}
Without | strip, if the snippet returns " yes" (with a leading space), the comparison " yes" == "yes" would be false, and the EMEA content would never appear. This is one of the most common silent bugs in Cast narrations.
Common mistakes
β Comparing snippet output without stripping first:
{% if IsEMEA == "yes" %}
If the snippet returns "yes " (with a trailing space), this comparison fails.
β Always strip snippet output before comparing:
{%- assign region = IsEMEA | strip -%}
{% if region == "yes" %}
π‘ Make it a habit: Whenever you assign a snippet result to a variable for comparison, add | strip. It costs nothing and prevents an entire category of bugs.
replace β Find and Replace All Occurrences
What is it?
The replace filter finds every occurrence of one piece of text and replaces it with another. It works on the entire string and replaces all matches, not just the first one.
Excel analogy: Identical to
=SUBSTITUTE(A1, "old", "new")β replaces all occurrences throughout the text.
Why it matters in Cast
Use replace to clean up CRM data β swap unwanted characters, fix formatting, or adapt text for different contexts.
Liquid syntax
{{ "hello world" | replace: "world", "there" }} β "hello there"
{{ "2024-01-15" | replace: "-", "/" }} β "2024/01/15"
{{ "$95,000" | replace: "$", "" | replace: ",", "" }} β "95000"
The filter takes two arguments separated by a comma: the text to find and the text to replace it with. To remove text entirely, replace it with an empty string "".
Real Cast example
Cleaning a currency field before converting to a number:
{%- assign arr_raw = arr | default: "0" -%}
{%- assign arr_clean = arr_raw | replace: "$", "" | replace: ",", "" -%}
{%- assign arr_numeric = arr_clean | plus: 0 -%}
Your annual recurring revenue is ${{ arr_numeric }}.
If arr is "$250,000":
replace: "$", ""β"250,000"replace: ",", ""β"250000"plus: 0β250000(number)
Output: Your annual recurring revenue is $250000.
Common mistakes
β Forgetting that replace is case-sensitive:
{{ "Hello World" | replace: "hello", "hi" }} β "Hello World" (no change!)
The lowercase "hello" doesnβt match the uppercase "Hello".
β Match the exact casing, or normalize first:
{{ "Hello World" | downcase | replace: "hello", "hi" }} β "hi world"
β Forgetting the replacement argument:
{{ "hello" | replace: "l" }} β error or unexpected behavior
β
Always provide both arguments β use "" to delete:
{{ "hello" | replace: "l", "" }} β "heo"
remove β Delete All Occurrences
What is it?
The remove filter deletes every occurrence of the specified text from the string. Itβs a shortcut for replace: "text", "".
Excel analogy: Like
=SUBSTITUTE(A1, "text", "")β replacing something with nothing to delete it.
Why it matters in Cast
Use remove when you need to strip out unwanted characters β dollar signs, commas, special characters, or any text that shouldnβt appear in the output.
Liquid syntax
{{ "hello world" | remove: "world" }} β "hello "
{{ "$95,000" | remove: "$" | remove: "," }} β "95000"
{{ "Contact: Jason" | remove: "Contact: " }} β "Jason"
Real Cast example
Cleaning a phone number for display:
{%- assign phone = contact_phone | default: "" -%}
{%- assign clean_phone = phone | remove: "(" | remove: ")" | remove: "-" | remove: " " -%}
{% if clean_phone != "" %}
Phone on file: {{ contact_phone }}
{% endif %}
Here, remove cleans the phone number for validation purposes (checking if anything is actually there), while the original formatted version is displayed to the customer.
Common mistakes
β Using remove when you need replace:
{{ "2024-01-15" | remove: "-" }} β "20240115"
If you wanted slashes instead of hyphens, remove is the wrong tool.
β
Use replace when you need to substitute, not just delete:
{{ "2024-01-15" | replace: "-", "/" }} β "2024/01/15"
append β Add Text to the End
What is it?
The append filter adds a string to the end of the value. The original value stays the same; the new text is tacked on after it.
Excel analogy: Like
=A1 & " Inc."β concatenating text onto the end of a cell value.
Why it matters in Cast
Use append to add units, suffixes, punctuation, or any trailing text to a value dynamically.
Liquid syntax
{{ "hello" | append: "!" }} β "hello!"
{{ "Acme" | append: " Inc." }} β "Acme Inc."
{{ score | append: " points" }} β "85 points"
Real Cast example
{%- assign pct = used | divided_by: reserved | times: 100 | round: 0 -%}
Your license utilization is {{ pct | append: "%" }}.
Output: Your license utilization is 75%.
π‘ In many cases, you can achieve the same result by putting the trailing text directly in the narration: Your utilization is {{ pct }}%. The append filter is most useful inside assign or capture blocks where youβre building up a value before using it later.
Common mistakes
β Using append to build text that should use capture:
{% assign msg = "" %}
{% assign msg = msg | append: "Hello " %}
{% assign msg = msg | append: name %}
{% assign msg = msg | append: ", welcome!" %}
This works, but itβs hard to read.
β
Use capture for complex text assembly:
{% capture msg %}Hello {{ name }}, welcome!{% endcapture %}
prepend β Add Text to the Start
What is it?
The prepend filter adds a string to the beginning of the value. The mirror image of append.
Excel analogy: Like
="Dear " & A1β putting text before a cell value.
Why it matters in Cast
Use prepend to add prefixes, titles, or labels before a dynamic value.
Liquid syntax
{{ "hello" | prepend: "Say " }} β "Say hello"
{{ "Smith" | prepend: "Dr. " }} β "Dr. Smith"
{{ arr_numeric | prepend: "$" }} β "$250000"
Real Cast example
{%- assign arr_val = arr | default: 0 | plus: 0 -%}
{%- assign arr_display = arr_val | prepend: "$" -%}
Your current ARR is {{ arr_display }}.
Output: Your current ARR is $250000.
truncate β Cut Text to a Character Limit
What is it?
The truncate filter shortens a string to a specified number of characters. If the string is longer than the limit, it cuts off the excess and adds an ellipsis (...) by default. The character count includes the ellipsis characters.
Excel analogy: Similar to
=LEFT(A1, 10), but with an automatic ββ¦β added to show that text was cut.
Why it matters in Cast
Use truncate when you need to fit long text values β like company names, descriptions, or notes β into limited space on a slide or narration box.
Liquid syntax
{{ "hello world" | truncate: 8 }} β "hello..."
{{ "hello world" | truncate: 8, "β¦" }} β "helloβ¦"
{{ "hello world" | truncate: 8, "" }} β "hello wo"
{{ "hello" | truncate: 10 }} β "hello" (not truncated β under limit)
The second argument (optional) lets you customize the trailing text. Use "" for no trailing indicator at all.
Real Cast example
{%- assign company = contact_account_name | default: "your company" | cast_titlecase -%}
Slide header: {{ company | truncate: 25 }}
If the account name is "International Business Machines Corp":
- After
cast_titlecase:"International Business Machines Corp" - After
truncate: 25:"International Business..."(25 characters including...)
Common mistakes
β Forgetting that the ellipsis counts toward the character limit:
{{ "abcdefghij" | truncate: 5 }} β "ab..." (NOT "abcde...")
The 5-character limit includes the 3 characters of ..., leaving room for only 2 characters of actual content.
β
Account for the ellipsis length when choosing your limit: If you want to show 10 characters of actual text plus ..., set the limit to 13:
{{ "abcdefghij" | truncate: 13 }} β "abcdefghij..."
truncatewords β Cut Text to a Word Limit
What is it?
The truncatewords filter shortens a string to a specified number of words (not characters) and adds an ellipsis. It cuts at word boundaries, so you never get a word chopped in half.
Excel analogy: No direct equivalent β but imagine a formula that counts spaces to find the nth word and cuts everything after it.
Why it matters in Cast
Use truncatewords when you want to preview a longer text field β like notes, descriptions, or feature lists β without worrying about cutting words in the middle.
Liquid syntax
{{ "one two three four five" | truncatewords: 3 }} β "one two three..."
{{ "one two three four five" | truncatewords: 3, "β" }} β "one two threeβ"
{{ "one two" | truncatewords: 5 }} β "one two" (not truncated)
Real Cast example
{%- assign notes = private_notes | default: "No notes available." -%}
Summary: {{ notes | truncatewords: 15 }}
If private_notes is a long paragraph, only the first 15 words appear, followed by ....
Common mistakes
β Using truncate (characters) when you mean truncatewords (words):
{{ "Your account has been active for several years now" | truncate: 3 }} β "..."
truncate: 3 allows only 3 characters total β and the ... uses all three.
β
Use truncatewords when you want to cut by word count:
{{ "Your account has been active for several years now" | truncatewords: 3 }}
β "Your account has..."
size β Count Characters or Items
What is it?
The size filter returns the number of characters in a string, or the number of items in an array. It doesnβt change the value β it produces a number.
Excel analogy: For strings, itβs identical to
=LEN(A1). For arrays, itβs like=COUNTA(A1:A10).
Why it matters in Cast
Use size to check the length of a value before displaying it, to count items in a list, or to provide dynamic counts in narration text.
Liquid syntax
{{ "hello" | size }} β 5 (characters)
{{ "" | size }} β 0
{{ "Analytics,Reporting" | split: "," | size }} β 2 (array items)
Real Cast example
{%- assign features = feature_list | split: "," -%}
You are currently using {{ features | size }} features.
{%- assign name = contact_first_name | default: "" -%}
{% if name | size > 0 %}
Hi {{ name }},
{% else %}
Hi there,
{% endif %}
β οΈ Note on using size in conditions: In some Liquid implementations, {% if name | size > 0 %} may not work as expected inside a tag. The safer pattern is to assign first:
{%- assign name = contact_first_name | default: "" -%}
{%- assign name_length = name | size -%}
{% if name_length > 0 %}
Hi {{ name }},
{% else %}
Hi there,
{% endif %}
Common mistakes
β Using size on nil without a default:
{{ contact_first_name | size }}
If the field is nil, this may error in strict mode.
β Always provide a default before checking size:
{%- assign name = contact_first_name | default: "" -%}
{{ name | size }}
split β Turn a String into an Array
What is it?
The split filter breaks a string apart at every occurrence of a specified separator and produces an array (a list of items). This is how you convert a comma-separated text field from your CRM into individual items you can loop through, count, or access by position.
Excel analogy: Similar to the βText to Columnsβ feature in Excel, where you split a cellβs contents at each comma (or other delimiter) into separate cells.
Why it matters in Cast
Multi-value fields from CRMs β feature lists, product names, region lists, task lists β typically arrive as a single comma-separated string. Before you can loop through the items, check if a specific value is in the list, or count the items, you need to split the string into an array.
Liquid syntax
{% assign items = "a,b,c" | split: "," %}
{{ items | size }} β 3
{{ items | first }} β a
{{ items[1] }} β b
You can split on any separator β commas, semicolons, spaces, pipes, or any character sequence:
{% assign words = "hello world" | split: " " %}
{% assign parts = "one;two;three" | split: ";" %}
{% assign segments = "first||second||third" | split: "||" %}
Real Cast example
{%- assign features = feature_list | split: "," -%}
Your active features:
{% for feature in features limit: 5 %}
{{ forloop.index }}. {{ feature | strip }}
{% endfor %}
{% if features.size > 5 %}
...and {{ features.size | minus: 5 }} more.
{% endif %}
If feature_list is "Analytics, Reporting, Alerts, Dashboards, API Access, Integrations, SSO":
Your active features:
1. Analytics
2. Reporting
3. Alerts
4. Dashboards
5. API Access
...and 2 more.
π‘ Notice | strip inside the loop β when the source string has spaces after commas (like "Analytics, Reporting"), splitting on "," produces items with leading spaces (" Reporting"). The strip filter cleans each one.
Common mistakes
β Splitting on ", " (comma-space) when some items donβt have the space:
{% assign items = "a,b, c" | split: ", " %}
{{ items | size }} β 2 (only "c" got split off; "a,b" is one item)
β Split on comma only, then strip each item:
{% assign items = "a,b, c" | split: "," %}
{% for item in items %}
{{ item | strip }}
{% endfor %}
default β Safe Fallback for Missing Values
What is it?
The default filter provides a replacement value when the input is nil, false, or an empty string. If the input has an actual value, default does nothing and passes it through unchanged. Itβs your primary safety net for missing CRM data.
Excel analogy: Similar to
=IF(A1="", "N/A", A1)or theIFBLANKpattern β if the cell is empty, show a fallback; otherwise, show the cellβs value.
Why it matters in Cast
In Castβs strict mode, displaying a nil variable causes an error. And even if it didnβt error, a blank space in the middle of a spoken narration sounds awkward. default ensures thereβs always something meaningful in every position, no matter how incomplete the CRM data is.
Liquid syntax
{{ contact_first_name | default: "there" }}
{{ health_score | default: "not available" }}
{{ csm_name | default: "your account manager" }}
default triggers when the value is:
- nil β the field doesnβt exist
- empty string
""β the field exists but is blank - false β the boolean value false
default does NOT trigger when the value is:
- any non-empty string β even
"0"or" "(a single space) - any number β even
0
Real Cast example
A complete safe greeting pattern:
{%- assign name = contact_first_name | default: "there" -%}
{%- assign company = contact_account_name | default: "your company" | cast_titlecase -%}
{%- assign csm = csm_name | default: "your account manager" -%}
{%- assign score = health_score | default: "N/A" -%}
Hi {{ name }},
Welcome to {{ company | cast_apostrophe }} review.
Your CSM, {{ csm }}, has prepared this overview.
Your current health score is {{ score }}.
Every variable has a natural-sounding fallback. The worst case β every field missing β still produces a coherent narration:
Hi there,
Welcome to Your Company's review.
Your CSM, your account manager, has prepared this overview.
Your current health score is N/A.
default with numeric conversion
When you need a numeric fallback, chain default before the number conversion:
{%- assign score = health_score | default: 0 | plus: 0 -%}
This reads as: βTake health_score. If itβs nil or empty, use 0. Then convert whatever we have to a number.β
β οΈ Order matters. If you reverse the chain:
{%- assign score = health_score | plus: 0 | default: 0 -%}
The plus: 0 runs first on a nil value, which may cause an error before default ever gets a chance to provide its fallback.
Common mistakes
β Relying on default to catch a single space " ":
{{ " " | default: "fallback" }} β " " (NOT "fallback")
A string containing only spaces is technically not empty β itβs a string with space characters. default doesnβt trigger.
β
Use strip before default to catch whitespace-only values:
{{ " " | strip | default: "fallback" }} β "fallback"
strip removes the spaces, producing "", which does trigger default.
β Forgetting default on a field used in arithmetic:
{%- assign score = health_score | plus: 0 -%}
If health_score is nil, this may error.
β Always default before converting:
{%- assign score = health_score | default: 0 | plus: 0 -%}
Chaining Filters β The Power of Pipes
The real power of text filters comes from chaining them together. Each filter receives the output of the previous one, so you can build a multi-step transformation pipeline.
Hereβs a realistic example β cleaning and formatting a company name:
{{ contact_account_name | default: "your company" | cast_titlecase | cast_apostrophe }}
Step by step:
contact_account_nameβ" ACME LLC "(raw CRM value with extra spaces)default: "your company"β" ACME LLC "(not nil, so no change)cast_titlecaseβ"Acme LLC"(proper casing β andcast_titlecasehandles stripping internally)cast_apostropheβ"Acme LLC's"(possessive added)
Another example β preparing a numeric value for display:
{{ arr | default: "0" | remove: "$" | remove: "," | plus: 0 }}
arrβ"$250,000"(raw CRM value)default: "0"β"$250,000"(not nil, so no change)remove: "$"β"250,000"remove: ","β"250000"plus: 0β250000(now a real number)
π‘ Reading filter chains: Always read left to right. Each pipe sends the current value to the next filter. If youβre ever confused about whatβs happening, break the chain into separate assign steps:
{%- assign step1 = arr | default: "0" -%}
{%- assign step2 = step1 | remove: "$" -%}
{%- assign step3 = step2 | remove: "," -%}
{%- assign arr_numeric = step3 | plus: 0 -%}
This produces the same result but makes each transformation visible and easy to debug.
Putting It All Together β Common Cast Patterns with Text Filters
Pattern 1: Safe, clean greeting
{%- assign name = contact_first_name | default: "there" | strip -%}
Hi {{ name }},
Pattern 2: Normalized comparison
{%- assign tier = product_tier | default: "" | strip | downcase -%}
{% if tier == "enterprise" %}
Enterprise content here.
{% endif %}
Pattern 3: Clean snippet comparison
{%- assign region = IsEMEA | strip -%}
{% if region == "yes" %}
EMEA-specific content.
{% endif %}
Pattern 4: Formatted company name with possessive
{{ contact_account_name | default: "your company" | cast_titlecase | cast_apostrophe }}
Pattern 5: Truncated preview with item count
{%- assign features = feature_list | split: "," -%}
Top features ({{ features | size }} total):
{% for feature in features limit: 3 %}
{{ forloop.index }}. {{ feature | strip }}
{% endfor %}
Pattern 6: Currency field cleanup
{%- assign arr_val = arr | default: "0" | remove: "$" | remove: "," | plus: 0 -%}
Try It Yourself β Module 4 Capstone Exercise
Exercise: You have the following CRM data:
contact_account_name=" JOHNSON & JOHNSON "feature_list="Advanced Analytics, Custom Reports, API Access, SSO, Data Export"contact_first_name= nil (missing)
Write Liquid that produces this output:
Hi there,
Johnson & Johnson is using 5 features. Here are the top 3:
1. Advanced Analytics
2. Custom Reports
3. API Access
Hint: Youβll need default, strip, cast_titlecase, split, size, a for loop with limit, and strip inside the loop.
Click to reveal the answer
```liquid {%- assign name = contact_first_name | default: "there" -%} {%- assign company = contact_account_name | strip | cast_titlecase -%} {%- assign features = feature_list | split: "," -%} Hi {{ name }}, {{ company }} is using {{ features | size }} features. Here are the top 3: {% for feature in features limit: 3 -%} {{ forloop.index }}. {{ feature | strip }} {% endfor %} ``` Breakdown: - `default: "there"` provides the fallback for the missing name - `strip` removes the leading/trailing spaces from the account name before `cast_titlecase` processes it - `split: ","` turns the comma-separated string into an array - `features | size` counts the items (5) - `limit: 3` stops the loop after 3 iterations - `| strip` inside the loop removes the leading space from each feature name (e.g., `" Custom Reports"` β `"Custom Reports"`)Whatβs Next
You now have a complete toolkit for transforming text in Cast. In Module 5, youβll learn the standard number filters β arithmetic, rounding, and the critical string-to-number conversion patterns that make comparisons and calculations work correctly.
π Official documentation:
- Standard Filters: https://school.cast.app/liquid/liquid-filters.html
- Custom Cast Filters: https://school.cast.app/liquid/custom-cast-filters.html
- Contact Variables: https://school.cast.app/fields-snippets-data-validation/contact-variables.html