---
title: "Filters"
slug: "liquid-tags-filters"
updated: 2026-04-10T09:06:39Z
published: 2026-04-10T09:06:39Z
canonical: "academy.insiderone.com/liquid-tags-filters"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://academy.insiderone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Filters

Filters are used to modify or format a variable's value at the point of output. They are applied using the pipe operator (|) and are supported only within {{ }} output blocks or {% assign %} statements.

## String Filters

upcase / downcase

```plaintext
{{ "hello" | upcase }}     →  HELLO
{{ "HELLO" | downcase }}   →  hello
{{ name | upcase }} →  ALICE    (when name is "Alice")
```

capitalize: Uppercases the first character of the string. It does not change the case of any other characters.

```plaintext
{{ "hello world" | capitalize }}   →  Hello world
{{ "HELLO" | capitalize }}         →  HELLO
```

capitalize does not lowercase the rest of the string. If the input is already uppercase, only the first character is guaranteed to be uppercase. The rest stays as-is. For example, "JOHN DOE" stays "JOHN DOE".

To produce title case (e.g., "Alice Smith" from "alice smith"), capitalize each part separately.

```plaintext
{% assign fn = name | capitalize %}
{% assign ln = surname | capitalize %}
{{ fn }} {{ ln }}
→  Alice Smith   (when name is "alice" and surname is "smith")
```

append / prepend

Add text to the end or beginning of a string.

```plaintext
{{ "photo" | append: ".jpg" }}       →  photo.jpg
{{ name | append: " Bey" }}          →  Alice Bey
{{ "World" | prepend: "Hello " }}    →  Hello World
{{ city | prepend: "City: " }}       →  City: Istanbul
```

strip / lstrip / rstrip

Remove whitespace from both sides, from the left only, or from the right only.

```plaintext
{{ "  hello  " | strip }}    →  hello
{{ "  hello  " | lstrip }}   →  hello
{{ "  hello  " | rstrip }}   →    hello
```

replace / replace_first

```plaintext
{{ "aaa" | replace: "a", "b" }}              →  bbb
{{ email | replace: "@", " [at] " }}         →  user [at] example.com
{{ "aaa" | replace_first: "a", "b" }}        →  baa
```

remove / remove_first

```plaintext
{{ "hello world" | remove: "o" }}            →  hell wrld
{{ "hello world" | remove_first: "o" }}      →  hell world
```

truncate: Shortens to a maximum total length. The ellipsis is included in that count.

```plaintext
{{ "This is a long sentence" | truncate: 10 }}          →  This is...
{{ "This is a long sentence" | truncate: 15 }}          →  This is a lo...
{{ "This is a long sentence" | truncate: 5 }}           →  Th...
{{ "This is a long sentence" | truncate: 10, "" }}      →  This is a
```

The default ellipsis is ... (3 characters). truncate: 10 = up to 7 content characters + ... = 10 total.

truncatewords: Shortens to a maximum number of words.

```plaintext
{{ "One two three four five" | truncatewords: 3 }}        →  One two three...
{{ "One two three four five" | truncatewords: 3, "" }}    →  One two three
```

split: Splits a string into a list using a separator.

```plaintext
{{ "a,b,c" | split: "," | first }}          →  a
{{ "a,b,c" | split: "," | last }}           →  c
{{ "a,b,c" | split: "," | join: " - " }}    →  a - b - c
{{ "a,b,c" | split: "," | size }}           →  3
```

slice: Extracts a substring by position. Negative index counts from the end.

```plaintext
{{ "hello" | slice: 0, 3 }}    →  hel
{{ "hello" | slice: -3, 3 }}   →  llo
```

slice works on strings only. It cannot be used to extract sub-arrays from a list.

size: Number of characters in a string, or number of items in a list.

```plaintext
{{ "hello" | size }}    →  5
{{ items | size }}      →  number of items in the list
```

escape / escape_once: Converts HTML special characters to entities.

```plaintext
{{ "<b>bold</b>" | escape }}          →  &lt;b&gt;bold&lt;/b&gt;
{{ "&lt;b&gt;" | escape_once }}       →  &lt;b&gt;   (not double-escaped)
```

url_encode / url_decode

```plaintext
{{ "hello world" | url_encode }}      →  hello+world
{{ "hello+world" | url_decode }}      →  hello world
```

strip_html: Removes all HTML tags.

```plaintext
{{ "<b>Bold</b> and <i>italic</i>" | strip_html }}   →  Bold and italic
```

strip_newlines / newline_to_br

```plaintext
{{ multiline_text | strip_newlines }}   →  line1line2
{{ multiline_text | newline_to_br }}    →  line1<br />line2
```

newline_to_br produces <br /> (**XHTML** style), not <br>.

## Number filters

plus / minus / times / divided_by

```plaintext
{{ 10 | plus: 5 }}           →  15
{{ 10 | minus: 3 }}          →  7
{{ 5 | times: 3 }}           →  15
{{ 10 | divided_by: 3.0 }}   →  3.333...
{{ 10 | divided_by: 3 }}     →  3   ← integer division
{{ 100 | times: 1.18 }}      →  118
```

When the **divisor** is a whole number, divided_by performs integer division and drops the decimal. Use a decimal divisor (3.0) to get a decimal result. The input type does not matter. Only the divisor controls whether the result is **integer** or a **decimal**.

modulo

```plaintext
{{ 10 | modulo: 3 }}   →  1
```

abs

```plaintext
{{ -50 | abs }}   →  50
```

ceil / floor / round

```plaintext
{{ 4.1 | ceil }}       →  5
{{ 4.9 | floor }}      →  4
{{ 4.56 | round }}     →  5
{{ 4.56 | round: 1 }}  →  4.6
{{ 4.56 | round: 2 }}  →  4.56
```

at_least / at_most: Clamps a value to a minimum or maximum.

```plaintext
{{ 3 | at_least: 5 }}     →  5    (below minimum, returns minimum)
{{ 8 | at_least: 5 }}     →  8    (above minimum, returns itself)
{{ 10 | at_most: 5 }}     →  5    (above maximum, returns maximum)
{{ 3 | at_most: 5 }}      →  3    (below maximum, returns itself)
```

Combine to clamp a value within a range.

```plaintext
{{ score | at_least: 0 | at_most: 100 }}
→ always returns a value between 0 and 100
```

number_format: Formats a number with custom thousand and decimal separators. This is an Insider-specific filter.

```plaintext
{{ price | number_format: "dot, comma" }}          →  1.234,56    (Turkish/German)
{{ price | number_format: "comma, dot" }}           →  1,234.56    (US/UK)
{{ price | number_format: "space, comma" }}         →  1 234,56    (French/Norwegian)
{{ price | number_format: "apostrophe, dot" }}      →  1'234.56    (Swiss)
{{ count | number_format: "comma" }}                →  1,234       (no decimals)
```

money_format: Formats a numeric value as currency with an optional currency symbol and separator style. This is an Insider-specific filter.

Use this filter to render raw numeric profile attributes such as wallet balances, credit amounts, or order totals as formatted money strings in email templates. The first optional argument sets the currency symbol, and the second optional argument sets the separator style. When no arguments are passed, the output uses the default currency style.

You can position this similarly to Shopify’s money filter concept, but Insider’s money_format is custom and more explicit because it supports a custom symbol, separator style, and symbol position.

```plaintext
//Assuming data = 5000000 (integer)
{{ data | money_format }}                        →  $5,000,000.00    (default)
{{ data | money_format: "$" }}                   →  $5,000,000.00
{{ data | money_format: "€", "dot, comma" }}     →  €5.000.000,00
{{ data | money_format: "£", "comma, dot" }}     →  £5,000,000.00
```

> [!WARNING]
> money_format rounds to **2 decimal places**, it does not truncate. Values like 11.999 become $12.00, and 0.001 becomes $0.00. If you need truncation instead of rounding, use **floor** before the filter.

```plaintext
{% assign truncated = price | times: 100 | floor | divided_by: 100.0 %}

{{ truncated | money_format: "$" }}
```

**Example: Round up**

```plaintext
{{ 11.999 | money_format: "$" }}    →  $12.00

{{ 99.999 | money_format: "€" }}    →  €100.00
```

The input is 11.999, but the output is $12.00 because money_format rounds to 2 decimal places, it does not truncate.

**Example: Round down**

```plaintext
{{ 0.001 | money_format: "$" }}     →  $0.00

{{ 0.004 | money_format: "€" }}     →  €0.00
```

Small fractions below 0.005 round down to .00 and effectively disappear.

### Separator keywords

| Keyword | Character |
| --- | --- |
| comma | , |
| dot | . |
| space |  |
| apostrophe | ‘ |

**Two separators** **(thousands, decimal):** The output always shows exactly 2 decimal places.

```plaintext
{{ 1234 | number_format: "dot, comma" }}     →  1.234,00
{{ 1234.5 | number_format: "dot, comma" }}   →  1.234,50
{{ 1234.567 | number_format: "dot, comma" }} →  1.234,57   (rounded)
```

**One separator (thousands only):** Decimal handling depends on the input value.

If the input is an **integer** (no fractional part), **no decimals** are shown.

```plaintext
{{ 1234 | number_format: "comma" }}    →  1,234
```

If the input already has a fractional part, 2 decimal places are shown using the default decimal separator (.).

```plaintext
{{ 1234.5 | number_format: "comma" }}  →  1,234.50
```

If the value is not a number, number_format returns an empty string silently.

## Array filters

first / last

```plaintext
{{ items | first }}
{{ items | last }}
{{ "a,b,c" | split: "," | first }}   →  a
```

join

```plaintext
{{ items | join: ", " }}    →  apple, banana, cherry
{{ items | join: " | " }}   →  apple | banana | cherry
```

sort / sort_natural

```plaintext
{{ tags | sort }}
{{ products | sort: "price" }}
{{ names | sort_natural }}              (case-insensitive)
```

reverse

```plaintext
{{ items | reverse }}
```

uniq

```plaintext
{{ "a,b,a,c,b" | split: "," | uniq | join: "," }}   →  a,b,c
```

map: Pulls a single top-level field from a list of objects:

```plaintext
{{ products | map: "name" }}           →  ShirtPantsShoes
{{ orders | map: "total" }}
```

Only top-level fields are supported, e.g., "name", not "category.name".

where: Filters a list keeping only items where a top-level field matches a value.

```plaintext
{{ products | where: "active", true }}
{{ orders | where: "status", "shipped" }}
{{ products | where: "featured" }}      (keeps items where featured is truthy)
```

Only top-level fields are supported, e.g., "status", not "order.status".

compact: Removes nil values from a list.

```plaintext
{{ items | compact }}
```

concat: Merges two lists.

```plaintext
{% assign all = list_a | concat: list_b %}
```

## Date and time filters

time_format: Formats a date using Moment.js-style tokens. This is an Insider-specific filter.

```plaintext
{{ birthday | time_format: "DD MMMM YYYY" }}            →  15 March 1992
{{ c_membership_date | time_format: "DD/MM/YYYY" }}     →  15/01/2022
{{ c_membership_date | time_format: "YYYY-MM-DD HH:mm:ss" }}
{{ c_membership_date | time_format: "dddd, DD MMMM YYYY" }}   →  Monday, 15 January 2024
```

### Accepted input formats

| Format | Example |
| --- | --- |
| RFC3339 | 2024-01-15T10:30:00Z |
| RFC3339 with offset | 2024-01-15T10:30:00+03:00 |
| ISO datetime | 2024-01-15T10:30:00 |
| Datetime | 2024-01-15 10:30:00 |
| Date only | 2024-01-15 |
| Unix timestamp | 1705315800 |

### Format token reference

| Token | Output | Example |
| --- | --- | --- |
| YYYY | 4-digit year | 2024 |
| YY | 2-digit year | 24 |
| MMMM | Full month name | January |
| MMM | Short month name | Jan |
| MM | Month, zero-padded | 01 |
| M | Month, no padding | 1 |
| DD | Day, zero-padded | 05 |
| D | Day, no padding | 5 |
| dddd | Full weekday name | Monday |
| ddd | Short weekday name | Mon |
| HH | Hour 24h, zero-padded | 14 |
| hh | Hour 12h, zero-padded | 02 |
| mm | Minutes, zero-padded | 05 |
| ss | Seconds, zero-padded | 30 |
| A | AM / PM | PM |
| X | Unix timestamp (seconds) | 1705315800 |
| Z | UTC offset | +03:00 |

Month and weekday names are always in English. If the input cannot be parsed, time_format returns an empty string silently, and no error is thrown. Formats using dots (15.01.2024) are **not** **recognized**.

timezone

Convert a date to a different time zone before formatting. Always apply time zone before time_format, so you format the already-converted time in the target time zone.

```plaintext
{{ birthday | timezone: "Europe/Istanbul" | time_format: "DD MMMM YYYY" }}
{{ c_membership_date | timezone: "America/New_York" | time_format: "hh:mm A" }}
{{ c_membership_date | timezone: "UTC" | time_format: "YYYY-MM-DD HH:mm:ss" }}
```

### Common IANA timezone names

| Name | Location |
| --- | --- |
| Europe/Istanbul | Turkey (UTC+3) |
| UTC | Universal Time |
| America/New_York | US East |
| America/Chicago | US Central |
| America/Los_Angeles | US West |
| America/Sao_Paulo | Brazil |
| Europe/London | UK |
| Europe/Berlin | Germany |
| Europe/Paris | France |
| Asia/Dubai | UAE |
| Asia/Tokyo | Japan |
| Asia/Singapore | Singapore |
| Asia/Kolkata | India |
| Australia/Sydney | Australia East |

- Use the full IANA name. "Istanbul", "TR", and "+03:00" are **not** **valid** and will cause an error.
- Unlike time_format, an invalid time zone name breaks the template. It does not silently return empty.
- Using time zone without chaining time_format produces a raw internal time representation, but not a human-readable one.

date

Standard liquid date filter using Ruby strftime format codes.

```plaintext
{{ birthday | date: "%Y-%m-%d" }}     →  1992-03-15
{{ birthday | date: "%d/%m/%Y" }}     →  15/03/1992
{{ birthday | date: "%B %d, %Y" }}    →  March 15, 1992
{{ "now" | date: "%Y-%m-%d" }}        →  today's date
```

Prefer time_format over date. It accepts more input formats and uses the more familiar Moment.js token style.

## Tips

- Filters cannot be applied directly within conditional tags. To evaluate a filtered value in a condition, first assign the result to an intermediate variable using {% assign %}, then reference that variable in the {% if %} statement.
- When multiple filters are chained, they are evaluated left to right. Each filter receives the output of the preceding one as its input.

```plaintext
{{ name | strip | upcase | default: "GUEST" }}
```

Filters that operate on field names, including map, where, and sort, are restricted to top-level fields only (e.g., "name"). Nested dot notation, such as "category.name", is not supported and will produce empty results.
