Liquid tag list

Updated

This page contains a list of the liquid tags, variables, and filters available to you in Customer.io. Use the search bar below to look for a specific tag. If you’re new to liquid, you can learn more about it in our guide about personalizing messages.

 You're looking at the latest Liquid documentation

If your account was created on or after Nov 28, 2023, you are using our latest liquid version for all messages. If your account was created before this date, go to How to upgrade your liquid version for more info.

The two versions are largely similar, but you'll find a list of differences on our Liquid Upgrade page.

Looking for something specific?

  • Customer.io Tags

    These are values generated by, or stored within, Customer.io. Reference these values to import information for a person. Many of the .id values are useful as UTM parameters in links, so you can log where your traffic is coming from or attribute customer actions to messages.

  • campaign.id

    “Your campaign’s numerical ID. This can be found in your campaign URL. For example, the campaign ID here is 2000: https://fly.customer.io/env/12345/v2/campaigns/2000/overview.

    For newsletters, your campaign.id is the value after newsletters in your URL. For example, the newsletter’s campaign.id here is 1 https://fly.customer.io/env/109950/composer/newsletters/1/templates/21.”

    Syntax
    {{campaign.id}}
    
  • campaign.name

    The name that you assigned your campaign or newsletter. For example: “Q2 Anvil Onboarding Campaign [Coyotes]”.

    Syntax
    {{campaign.name}}
    
  • campaign.subscription_topic_ids

    This returns the topic assigned in subscription preferences settings for Campaigns, API Triggered Broadcasts and Newsletters.

    Syntax
    {{campaign.subscription_topic_ids}}
    
  • campaign.type

    This returns the type of trigger for your campaign: behavioral (segment-triggered), transactional (event-triggered), form, date, object, or relationship. For messages sent through our Transactional API, this returns transactional_message. It also returns triggered_broadcast for an API-triggered broadcast or newsletter accordingly.

    Syntax
    {{campaign.type}}
    
  • content

    Use in layouts to indicate where code added via the email editor will be included. You might use this in a template for a transactional message or API-triggered broadcast where you will provide content from the API directly.

    Example
    {{content}}
    
  • delivery_id

    A URL-compatible base64 string that identifies an instance of a message created for a person. This is set to unsent in test send and composer previews, and generated when the message is drafted or sent.

    Syntax
    {{delivery_id}}
    
  • event_id

    The id of the event being previewed for the selected sample profile. It throws an error if the event has not been sent recently (within the last ~30 days).

    Syntax
    {{event_id}}
    
  • event_name

    The name of the event that triggers a campaign. If you send an event with different casings - for instance, MyEvent and myevent - Customer.io will output the event name that corresponds with the profile. This throws an error if the event has not been sent recently (within the last ~30 days).

    Syntax
    {{event_name}}
    
  • layout.id

    The numerical ID associated with the email layout you’ve used.

    Syntax
    {{layout.id}}
    
  • layout.name

    The name assigned to the email layout you’re using.

    Syntax
    {{layout.name}}
    
  • manage_subscription_preferences_url

    Renders a unique unsubscribe link for a customer and their email-address. This link takes a user to your subscription center where they can manage all of their preferences.

    Syntax
    {% manage_subscription_preferences_url %}
    
  • message.id

    The numerical ID for a message action in the workflow. For example, an SMS action might have a {{message.id}} of 200. Note that this identifies the action in your workflow, not the individual delivery instances. Every SMS delivery generated from the action would have a different {{delivery_id}}.

    For newsletters, the message.id is the value after templates in your URL. For example, the message.id here is 21 https://fly.customer.io/env/109950/composer/newsletters/1/templates/21.

    Syntax
    {{message.id}}
    
  • message.journey_id

    The ID for the path a person went through in a Campaign or API Triggered Broadcast workflow. You can use this value to trace message metrics back to a person’s path through a journey using the journey.id value sent in our Reporting Webhooks.

    Syntax
    {{message.journey_id}}
    
  • message.name

    The name you give your message in the workflow, like “Welcome to ACME!”

    Syntax
    {{message.name}}
    
  • message.preheader

    For email messages only, if your message has a preheader value set, this tag echos it.

    Syntax
    {{message.preheader}}
    
  • message.subject

    If your message has a subject, or the message subject is different from the message name, this tag echos it.

    Syntax
    {{message.subject}}
    
  • message.subscription_topic_ids

    This returns the topic assigned in subscription preferences settings for Campaigns, API-triggered Broadcasts and Newsletters. If there is a message-level override of the topic (Campaigns and API-triggered Broadcasts only), it will return that topic over the setting at the Campaign or APITB level.

    Syntax
    {{message.subscription_topic_ids}}
    
  • message.type

    This refers to the type of a particular workflow action. Possible values are: email_action, delay_seconds_action, delay_time_window_action, split_randomized_action, webhook_action, twilio_action, slack_action, attribute_update_action, filter_match_delay_action, grace_period_action, push_action, conditional_wait_action, conditional_branch_action, multi_split_branch_action, random_cohort_branch_action, exit_action, static_seg_update_action, collection_query_action, create_event_action, multi_lang_branch_action, batch_update_action, in_app_action.

    Syntax
    {{message.type}}
    
  • subscription_topic_name

    Renders the name of the subscription topic assigned to a broadcast or campaign. If the topic is overriden for a message, this will render the message-level topic. Add a language parameter to translate the name, like lang='pt'. If the language doesn’t match a translation in your subscription center, customers will see the default language.

    Syntax
    {% subscription_topic_name %}
    
  • unsubscribe

    Renders the word unsubscribe and links to the customer’s unique unsubscribe URL.

    Syntax
    {% unsubscribe %}
    
  • unsubscribe_url

    Renders a unique unsubscribe link for a customer and their email-address.

    Syntax
    {% unsubscribe_url %}
    
  • view_in_browser_url

    Our default link that generates a web version of your email, personalized for each recipient. In general, these URLs look something like: http://e.customeriomail.com/deliveries/....

    Syntax
    {% view_in_browser_url %}
    
  • Variables and Assignment

    There are common variables you can reference within messages and elsewhere. These may be variables associated with a person, the event triggering a message workflow, or variables that you assign within your message from other values.

  • assign

    Assign a value to a variable.

    Syntax
    {% assign var_name = 'value' %} 
    
    Input
    {% assign favorite_food = 'apples' %} 
    
    Output
    {{ favorite_food }}
    
  • capture

    Captures contents and assigns them to a variable.

    Input
    {% capture about_me %}I am 28 and my favorite food is pasta.{% endcapture %}
    
    Output
    {{ about_me }}
    
  • customer attributes

    You reference customer attributes—data associated directly with a person in Customer.io—in the customer scope. You may want to use customer attributes with an if conditional so you have text to fallback to if a customer doesn’t have the attribute in question. You must use default rather than checking for empty strings using == blank or != blank.

    Syntax
    {{customer.<attribute_name>}}
    
    Example
    {% if customer.first_name %}
      Hello {{ customer.first_name }}!
    {% else %}
      Hello to our nameless but valued customer!
    {% endif %}
    
  • event properties

    If you trigger a campaign using an event, you can reference properties from the event that triggers your campaign in the event scope. You may want to use event properties with an if conditional, so that you have text to fallback to if an event doesn’t have the property in question or your property doesn’t contain the value you expect. You must use default rather than checking for empty strings using == blank or != blank.

    Syntax
    {{event.<property>}}
    
    Example
    {% if event.type == "purchase" %}
      Thanks for your purchase!
    {% else %}
      Thanks for using our service!
    {%endif%}
    
  • trigger properties

    You can reference properties from the data object when you trigger a transactional message or API-trigger a broadcast using the trigger scope. This provides a convenient way to pass event data into transactional and broadcast templates. You may want to use trigger properties with an if conditional, so that you have text to fallback to if your trigger data is incomplete or contains values you don’t expect. You must use default rather than checking for empty strings using == blank or != blank.

    Syntax
    {{trigger.<data.property>}}
    
    Example
    {% if trigger.first_name %}
      Hi {{trigger.first_name | capitalize}}
    {% else %}
      Hi Buddy
    {%endif%}
    
  • Logical Operators

    Logical operators determine the basic rules for evaluating true or false statements. You can also use and and or operators to combine logic statements to evaluate multiple conditions.

  • and

    Evaluate a statement as true when both conditions are true.

    Syntax
    {% if condition1 and condition2 %}
      // do something if both condition1 and condition 2 are true
    {% endif %}
    
    Example
    {% if customer.name == "bugs bunny" and event.episode_start == true %}
      What's up doc?
    {% else %}
      That's all folks!
    {% endif %}
    
  • Does not equal (!=)

    Use != to check that two values are not equal to each other.

    Example
    {% if customer.name != "daffy duck" %}
      Duck season!
    {% else %}
      Wabbit season!
    {%endif%}
    
  • equals (==)

    Use == to check if two values are equal to each other.

    Example
    {% if customer.name == "daffy duck" %}
      Wabbit season!
    {% else %}
      Duck season!
    {%endif%}
    
  • Greater than and Greater than or equal to (>, >=)

    Use > to match when one value is greater than another. Use >= to match when one value is greater than or equal to another.

    Syntax
    {% if val1 > val2 %}
      {% comment %}do something if val1 is greater than val2{% endcomment %}
    {% endif %}
    
    Example
    {% if customer.acct_age_years > 1 %}
      Thanks for being with us these past years
    {% else %}
      Thanks for spending the last year with us!
    {% endif %}
    
  • Less than and less than or equal to (<, <=)

    Use < to match when one value is less than another. Use <= to match when one value is less than or equal to another.

    Syntax
    {% if val1 < val2 %}
      {% comment %}do something if val1 is less than val2{% endcomment %}
    {% endif %}
    
    Example
    {% if customer.purchases < 5 %}
      Thanks for your support
    {% else %}
      Thanks for spending the last year with us!
    {% endif %}
    
  • or

    Evaluate a statement as true when either of two conditions are true.

    Syntax
    {% if condition1 or condition2 %}
      {% comment %}do something if either condition1 and condition 2 are true{% endcomment %}
    {% endif %}
    
    Example
    {% if customer.name == "bugs bunny" or customer.group == "looney toons" %}
      That's all folks!
    {% else %}
      See you later!
    {% endif %}
    
  • Loops and Conditionals

    Loop through an array of items or set conditions determining the content that you want to show.

  • case

    Creates a set of conditions depending on a variable’s specific value—like a set of if, if-else, else conditions.

    For example, you might use this to display different text depending on if a customer lives in a specific country.

    Syntax
    {% case condition %}
      {% when "value1" %}
        text when condition is value1.
      {% when "value2" or "value3" %}
        text when condition is value2 or value3
      {% else %}
        text when condition does not match other conditions
    {% endcase %}
    
  • for loop

    Repeatedly executes a block of code, most commonly to perform an operation for each item in an array. You might use a for loop in a message to provide a receipt of purchases (assuming an array of items in a purchase). Find more information about for loops and iteration here. For instance, you can use a break tag - {% break %} - to exit a loop.

    Syntax
    {% for item in array %}
      {{ item }}
    {% endfor %}
    
    {% comment %} You can use a break tag so the loop stops iterating. {% endcomment %}
    {% for i in (1..5) %}
      {% if i == 4 %}
        {% break %}
      {% else %}
        {{ i }}
      {% endif %}
    {% endfor %}
    
    Example
    {% comment %} You can output each item of the array. {% endcomment %}
    {% for member in members_of_band %}
      {{member}}
    {% endfor %}
    
    {% comment %} If the items are objects, you can output properties from each object. {% endcomment %}
    {% for product in event.products %}
      - {{ product.title }} x {{ product.price }}
    {% endfor %}
    
  • if

    Executes a block of code if a condition is met. We execute the first true condition. Use elsif to add multiple ‘if’ conditions and else for the block of code you want to execute if all conditions are false. Use the default filter to specify a fallback for when a variable does not exist instead of an if statement. Find more information about conditional liquid here.

    Example
    {% if customer.lastEventType == "sports" %}
      You last attended a sports event, so we thought you might like to try out our leagues! Fill out our interest form below.
    {% elsif customer.lastEventType == "theater" %}
      You attended a theater event, so we thought you might like to try out our after show parties! Fill out our interest form below.
    {% elsif customer.lastEventType %} 
      {% comment %} If the attribute exists and does not equal sports or theater, then this will render.{% endcomment %}
      You last attended {{customer.lastEventType}}; we'd love to hear what other offerings you'd like from us in the form below.
    {% else %} 
      {% comment %} If the attribute does not exist, this will render. {% endcomment %}
      Let us know your interests in the form below so we can better serve you!
    {% endif %}
    
  • unless

    Like an if conditional, but reversed: this tag executes a block of code if your condition is not met.

    Example
    {% unless product.name == "cool beans" %}
      The beans are not cool.
    {% endunless %}
    
  • Timestamps and Dates

    Use these tags to get and manipulate dates and times.

  • add_day

    Adds a day, or multiple days, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | add_day: <int_days> }}
    
    Example
    {{ 1477430251 | add_day: 7 }}
    
  • add_month

    Adds a month, or multiple months, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | add_month: <int_months> }}
    
    Example
    {{ 1477430251 | add_month: 7 }}
    
  • add_year

    Adds a year, or multiple years, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | add_year: <int_years> }}
    
    Example
    {{ 1477430251 | add_year: 4 }}
    
  • countdown

    Creates a countdown timer in your message, helping you alert your audience to how soon an event they’re interested in is set to happen. Countdown timers take several parameters. At the minimum, a countdown must include the font size, the foreground (font) color, the background color, and the time you want to count down to. You can only set this to count down from a static timestamp; you cannot set the time to count down based on a customer’s attribute, for instance.

    The countdown timer cannot contain more than 60 frames. This limits the size of the animated GIF in your messages. So, if the resolution is set to seconds, the counter will stop after 60 seconds from when the person opens their message. The countdown image reloads when a person opens the message again, so the counter will always be relevant to the user’s current time, but it cannot count indefinitely.

    Parameterrequiredformatdefaultdescription
    pointintegerThe font size for the timer
    timeISO 8601 timestampThe date and time you want to countdown to in the format YYYY-MM-DD hh:mm:ss (GMT). Remember to close the time in quotes, as the value includes a space. This field does not accept liquid variables.
    fghex colorThe foreground (font) hexidecimal color
    bghex colorThe background hexidecimal color
    apngbooleanfalseDetermines whether to show your countdown as a gif (default) or animated PNG. Note that some browsers/email clients don’t support apng images.
    fontstringinter, robotoThe font family for your timer
    weightstringnormalThe font weight, takes normal CSS font-weight values.
    localelanguage codeenThe language you want to display: en (English), ru (Russian), jp (Japanese), zh (Chinese), pt (Portugese), es (Spanish), and fr (French)
    loopingbooleanfalseDetermines whether the countdown timer should restart after it finishes
    resolutionone of S, M, H, DSDetermines how often the timer counts down—by the second, minute, hour, or day.
    framesinteger1Number of seconds you want to show, based on the resolution, where seconds: 60, minutes: 2, hours: 1, days: 1

    Example
    {% countdown point:64 font:roboto weight:light fg:000000 bg:f2f6f9 time:"2022-07-04 12:00:00 (GMT)" locale:en looping:true resolution:S frames:2 %}
    
    countdown-timer.png
    countdown-timer.png
  • date

    Format a date. Use the LiquidJS reference for more information about date filters including overriding the timezone. For a full list of regions, see our Supported timezone formats. You can also offset the timezone in minutes (360 = -6:00 hrs and -360 = +6:00 hrs).

    Input
    {{ 1483272000 | date: '%H:%M, %a, %b %d, %Y' }}
    {{ 1483272000 | date: '%a., %-m/%d at %I:%M %P %Z' }}
    {{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", "Asia/Colombo" }}
    {{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", 360 }}
    
    Output
    12:00, Sun, Jan 01, 2017
    Sun., 1/01 at 12:00 pm UTC
    1991-01-01T04:30:00
    1990-12-31T17:00:00
    
  • date_to_long_string

    Converts a date-time to include the full name of the month. You can convert this to ordinal time by adding ‘ordinal’, and you can follow that with ‘US’ if you’d like to lead with the month. By default, this displays the date in DD, M full name, YYYY.

    Input
    {{ site.time | date_to_long_string }}
    {{ site.time | date_to_long_string: "ordinal" }}
    {{ site.time | date_to_long_string: "ordinal", "US" }}
    
    Output
    07 November 2008
    7th November 2008
    November 7th, 2008
    
  • date_to_rfc822

    Converts a date-time into the RFC-822 format used for RSS feeds.

    Input
    {{ site.time | date_to_rfc822 }}
    
    Output
    Mon, 07 Nov 2008 13:07:54 -0800
    
  • date_to_string

    Converts a date-time to ordinal time. Add ‘US’ to lead with the month. By default, this displays the date in DD, M abbreviated, YYYY.

    Input
    {{ site.time | date_to_string }}
    {{ site.time | date_to_string: "ordinal" }}
    {{ site.time | date_to_string: "ordinal", "US" }}
    
    Output
    07 Nov 2008
    07th Nov 2008
    Nov 7th, 2008
    
  • date_to_xmlschema

    Converts a date-time into ISO 8601, a format expected by XML schema.

    Input
    {{ site.time | date_to_xmlschema }}
    
    Output
    2008-11-07T13:07:54-08:00
    
  • event_timestamp

    The UNIX timestamp when a particular event was performed. This time is different from the now tag! This throws an error if the event has not been sent recently (within the last ~30 days).

    Syntax
    {{event_timestamp}}
    
  • now

    The current time in UTC. You must format time with date.

    To modify date or time with add or subtract filters you must convert now into a unix timestamp first using date: '%s'. If you use our built in add_day, add_month, or add_year filters, you must convert the timestamp to an integer first. You can do this by using the plus filter to add 0 as shown in the second example below.

    Example
    {{ 'now' | date: '%I:%M %p %B %d, %Y' }}
    {{ 'now' | date: '%s' | plus: 0 | add_day: 1 | date: '%I:%M %p %B %d, %Y'}}
    
    Output
    08:28 AM May 11, 2021
    08:28 AM May 12, 2021
    
  • subtract_day

    Subtracts a day, or multiple days, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | subtract_day: <int_days> }}
    
    Example
    {{ 1477430251 | subtract_day: 7 }}
    
  • subtract_month

    Subtracts a month, or multiple months, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | subtract_month: <int_months> }}
    
    Example
    {{ 1477430251 | subtract_month: 2 }}
    
  • subtract_year

    Subtracts a year, or multiple years, to a given timestamp.

    Syntax
    {{ <unix_timestamp> | subtract_year: <int_years> }}
    
    Example
    {{ 1477430251 | subtract_year: 4 }}
    
  • Array Filters

    Liquid used to filter and manipulate arrays (lists of values). If your event or another incoming value is an array, you may iterate over the array with a for loop or grab items at a particular index of the array, to display information for your audience.

  • compact

    Removes nil (empty) values from an array.

    Input
    {{ "mick, keith, nil, Charlie" | compact }} 
    
    Output
    mick, keith, Charlie
    
  • concat

    Concatenates arrays, joining them end to end. Accepts a single object or an array of objects. The resulting array contains all of the elements of both original arrays. concat does not remove duplicate entries unless you also use the uniq filter.

    Input
    {% assign stones = "mick, keith, ronnie, charlie" | split: ", " %} 
    {% assign beatles = "john, paul, george, ringo" | split: ", " %} 
    {% assign rolling_beatles = stones | concat: beatles %} 
    {{ rolling_beatles | join: ", " }}
    
    Output
    mick, keith, ronnie, charlie, john, paul, george, ringo
    
  • cycle

    In a ‘for’ loop, this tag loops through and outputs strings in the order they were passed.

    Input
    <ul>{% assign characters = "coyote,bugs,tweety" | split: "," %} 
      {% for character in characters %} 
      <li class="{% cycle 'odd', 'even' %}">{{ character }}</li> 
      {% endfor %}
    </ul> 
    
    Output
    <ul> 
      <li class='odd'>coyote</li>
      <li class='even'>bugs</li> 
      <li class='odd'>tweety</li> 
    </ul>
    
  • find

    Returns the first object in an array for which the queried attribute has the given value or returns nil if no item in the array satisfies the given criteria.

    Input
    {{ customer.purchases | find: "type", "kitchen" | json }}
    
    Output
    {"date":"1726589206","title":"utensils","type":"kitchen"}
    
  • find_exp

    Returns the first object in an array for which the given expression evaluates to true or returns nil if no item in the array satisfies the evaluated expression.

    Input
    {{ members | find_exp: "item", "item.graduation_year == 2014" | json }}
    
    Output
    {"graduation_year":2014,"name":"John"}
    
  • first

    Returns the first element of the array.

    Input
    acme.characters = ["Wile E Coyote", "Road Runner"]
    {{ acme.characters | first }}
    
    Output
    Wile E Coyote
    
  • group_by

    Groups an array’s items by a given property.

    Input
    {% assign groups = customer.purchases | group_by: "type" %}
    
    {% for group in groups %}
    
      {{group.name | capitalize}}
    
      {% for item in group.items %}
    
        - {{ item.title }}
    
      {% endfor %}
    
    {% endfor %}
    
    Output
    Bathroom
    - shower curtain
    - body soap
    Kitchen
    - forks
    - spoons
    - knives
    
  • group_by_exp

    Groups an array’s items using a Liquid expression.

    Input
    {% assign groups = customer.purchases | group_by_exp: "item", "item.type contains 'kitchen'" %} 
    
    {% for group in groups %}
    
      {% if group.name == true %}
    
        You bought some kitchen supplies from us in the past year:
    
          {% for item in group.items %}
    
          - {{item.title}}
    
          {% endfor %}
    
      {% endif %}
    
    {% endfor %}
    
    Output
    You bought some kitchen supplies from us in the past year:
    - forks
    - spoons
    - knives
    
  • join

    Joins the elements of an array with the character passed as the parameter.

    Input
    acme.characters = ["Wile E Coyote", "Road Runner"] 
    {{ acme.characters | join: ', ' }}
    
    Output
    Wile E Coyote, Road Runner
    
  • json_array_uniq

    Evaluates an array of JSON objects and outputs an array containing all the unique objects based only on the value of the passed-in key name. Use the filter to_json if a string is the desired output.

    Input
    {{ customer.arrayOfColorObjects | concat: customer.arrayOfColorObjectsWithDuplicationsAndNew | json_array_uniq: 'name' | to_json }}
    
    Output
    [{"color":"brown","name":"coyote"},{"color":"black","name":"bugs"},{"color":"yellow","name":"tweety"},{"color":"black","name":"daffy"}]
    
  • last

    Returns the last element of the array.

    Input
    acme.characters = ["Wile E Coyote", "Road Runner"]
    {{ acme.characters | last }}
    
    Output
    Road Runner
    
  • limit

    Return a set number of values from an array or string.

    Input
    {% assign beatles = "john, paul, george, ringo" | split: ", " %} 
    {{ beatles | limit: 2 | join: ", " }}
    
    Output
    john, paul
    
  • map

    Creates an array of values by extracting the values of a property in an object. You can output your new characters in a ‘for’ loop.

    Input
    Array of objects: [{"name":"coyote"},{"name":"bugs"},{"name":"tweety"}]"
    {% assign names = customer.characters | map: 'name' %}
    
    Output
    coyote, bugs, tweety
    
  • pop

    Removes the last element from the array.

    Input
    {% assign fruits = "apples, oranges, peaches" | split: ", " %}
    
    {% assign everything = fruits | pop %}
    
    {% for item in everything %}
    - {{ item }}
    {% endfor %}
    
    Output
    - apples
    - oranges
    
  • push

    Adds an element to an array.

    Input
    {% assign fruits = "apples, oranges" | split: ", " %}
    
    {% assign everything = fruits | push: "peaches" %}
    
    {% for item in everything %}
    - {{ item }}
    {% endfor %}
    
    Output
    - apples
    - oranges
    - peaches
    
  • remove

    Remove an element from an array. The array can contain objects of any type.

    Input
    {% assign pl = collection.products | remove: collection.products[0] %}
    - {{ collection.products.size }}
    - {{ pl.size }}
    
    Output
    - 2 
    - 1
    
  • reverse

    Reverses the order of the items in an array.

    Input
    {% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}
    
    {{ my_array | reverse | join: ", " }}
    
    Output
    plums, peaches, oranges, apples
    
  • shift

    Removes the first element from the array.

    Input
    {% assign fruits = "apples, oranges, peaches" | split: ", " %}
    
    {% assign everything = fruits | shift %}
    
    {% for item in everything %}
    - {{ item }}
    {% endfor %}
    
    Output
    - oranges
    - peaches
    
  • size

    Returns the number of characters (the size) of a string (in characters) or the number of elements in an array.

    Input
    {{ "That's all, folks!" | size }}
    
    Output
    18
    
  • sort

    Sorts the elements of an array by an attribute of an element in that array. Usually used with a ‘for’ loop. The order of the sorted array is case-sensitive! This filter will not reorder any list/array that contains null values. See Sorting looped data for an advanced example.

    Input
    {% assign beatles = "paul, john, ringo, george" | split: ", " %}
    
    {{ beatles | sort | join: ", " }}
    
    Output
    george, john, paul, ringo
    
  • sort_natural

    Sort the items in an array in case-insensitive order.

    Input
    {{ "mick, keith, Charlie, Ronnie" | sort_natural }}
    
    Output
    Charlie, keith, mick, Ronnie
    
  • sum

    The sum filter aggregates numbers. Every value is cast to a number. Unlike with legacy liquid, sum does not concatenate numbers, strings, or booleans. You can specify an object property to sum, as shown in the third example below.

    Input
    {% assign nums = '1,2,3' | split: ',' %}
    {{ nums | sum }}
    
    {% assign letters = 'a,b,c' | split: ',' %}
    {{ letters | sum }}
    
    {{ cart.products | sum: 'total_number' }} {% comment %} where `total_number` includes milk,cheese,eggs {% endcomment %}
    
    {{ purchase.products | sum }} {% comment %} where `products` includes true,false {% endcomment %}
    
    Output
    6
    0
    3
    1 {% comment %} counts the number of trues, would also aggregate numbers alongside booleans {% endcomment %}
    
  • uniq

    Removes duplicate elements in an array.

    Input
    {% assign my_array = '"lions", "tigers", "bears", "bears", "lions"' %}
    {{ my_array | uniq | join: ", " }} 
    
    Output
    lions, tigers, bears
    
  • unshift

    Adds an element to the beginning of the array.

    Input
    {% assign fruits = "oranges, peaches" | split: ", " %}
    
    {% assign everything = fruits | unshift: "apples" %}
    
    {% for item in everything %}
    - {{ item }}
    {% endfor %}
    
    Output
    - apples
    - oranges
    - peaches
    
  • where

    Creates an array including only the objects with a given property value, or any “truthy” value by default.

    Input
    All Players:
    {% for player in collection.players %} 
      - {{ player.last_name }} 
    {% endfor %} 
    
    Baseball Players:
    {% assign baseball_players = collection.players | where: "sport", "baseball" %} 
    {% for player in baseball_players %} 
      - {{ player.last_name }} 
    {% endfor %}
    
    ----------------------------
    
    All products:
    {% for product in collection.products %}
    - {{ product.title }}
    {% endfor %}
    
    {% assign available_products = collection.products | where: "available" %}
    
    Available products:
    {% for product in available_products %}
    - {{ product.title }}
    {% endfor %}
    
  • where_exp

    Selects all the objects in an array where the expression is true. You provide two items separated by a comma: the key you want to match on and the value you want to match.

    Input
    All products:
    {% for product in customer.products %}
    - {{ product.title }}
    {% endfor %}
    
    {% assign kitchen_products = customer.products | where_exp: "item", "item.size > 30 and item.type == 'kitchen'" %}
    
    Kitchen products:
    {% for product in kitchen_products %}
    - {{ product.title }}
    {% endfor %}
    
  • where_not

    Creates an array of items that do not match a given property value, or any “falsey” value by default. When using where_not, you provide two items separated by a comma: the key you want to match on and the value you want to match.

    Input
    All players: 
    {% for player in collection.players %} 
      - {{ player.last_name }} 
    {% endfor %} 
    
    Not baseball players: 
    {% assign not_baseball_players = collection.players | where_not: "sport", "baseball" %} 
    {% for player in not_baseball_players %} 
      - {{ player.last_name }} 
    {% endfor %}
    
    Output
    All players: 
      - Posey 
      - Maradona 
      - Montana 
      - Gretzky 
      - Jordan 
    
    Not baseball players: 
      - Maradona 
      - Montana 
      - Gretzky 
      - Jordan 
    
  • Number and Currency Filters

    These are tags and filters that manipulate incoming number, integer, and timestamp values.

    Some tags, like the currency and format_number, take an optional localization parameter, formatting the output for a specific locale. These tags use the format {{ 10 | currency: "en-us" }}, which would output $10.00.

  • A list of locales and currency codes

    We support the following localization values:

    af, ar, az, be, bg, bn, bs, ca, cs, cy, da, de-AT, de-CH, de-DE, de, dz, el-CY, el, en-AU, en-CA, en-CY, 
    en-GB, en-IE, en-IN, en-NZ, en-TT, en-US, en-ZA, en, eo, es-419, es-AR, es-CL, es-CO, es-CR, es-EC, es-ES, 
    es-MX, es-NI, es-PA, es-PE, es-US, es-VE, es, et, eu, fa, fi, fr-CA, fr-CH, fr-FR, fr, gl, gsw-CH, he, 
    hi-IN, hi, hr, hu, id, is, it-CH, it, ja-JP, ja, ka, kk, km, kn, ko, lb, lo, lt, lv, mg, mk, ml, mn, mr-IN, 
    ms, na, nb, ne, ng, nl, nn, oc, or, pa, pl, pt-BR, pt, rm, ro, ru, sc, sd, sk, sl, sn, sq, sr, st, sv-FI, 
    sv-SE, sv, sw, ta, te, th, tl, tn, tr, tt, ug, uk, ur, uz, vi, wo, za, zh-CN, zh-HK, zh-Hant-MO, zh-MO, 
    zh-TW, ao, cd, ci, cm, eg, gh, ke, ls, ly, ma, mu, mw, mz, sz, tz, zm
    

    We support the following currency codes:

    'AED','AFN','ALL','AMD','ANG','AOA','ARS','AUD','AWG','AZN','BAM','BBD','BDT','BGN','BHD','BIF','BMD',
    'BND','BOB','BRL','BSD','BTN','BWP','BYN','BZD','CAD','CDF','CHF','CLP','CNY','COP','CRC','CUC','CUP',
    'CVE','CZK','DJF','DKK','DOP','DZD','EGP','ERN','ETB','EUR','FJD','FKP','GBP','GEL','GHS','GIP','GMD',
    'GNF','GTQ','GYD','HKD','HNL','HRK','HTG','HUF','IDR','ILS','INR','IQD','IRR','ISK','JMD','JOD','JPY',
    'KES','KGS','KHR','KMF','KPW','KRW','KWD','KYD','KZT','LAK','LBP','LKR','LRD','LSL','LYD','MAD','MDL',
    'MGA','MKD','MMK','MNT','MOP','MRU','MUR','MVR','MWK','MXN','MYR','MZN','NAD','NGN','NIO','NOK','NPR',
    'NZD','OMR','PAB','PEN','PGK','PHP','PKR','PLN','PYG','QAR','RON','RSD','RUB','RWF','SAR','SBD','SCR',
    'SDG','SEK','SGD','SHP','SLE','SLL','SOS','SRD','SSP','STN','SVC','SYP','SZL','THB','TJS','TMT','TND',
    'TOP','TRY','TTD','TWD','TZS','UAH','UGX','USD','UYU','UZS','VES','VND','VUV','WST','XAF','XCD','XDR',
    'XOF','XPF','XSU','YER','ZAR','ZMW','ZWL'
    

  • abs

    Returns the absolute value of a number.

    Input
    {{ 3.14 | abs }}
    
    Output
    3.14
    
  • ceil

    Rounds a number up to the nearest integer.

    Input
    {{ 3.14 | ceil }}
    
    Output
    4
    
  • currency

    Converts an integer to currency. This filter accepts two arguments for currency and locale. When no arguments are passed to the filter, the currency code defaults to USD. When only a locale is passed, we base the currency on the closest match to the locale. See above for a list of specific locales and currencies. We only accept a currency code after a locale is specified.

    Input
    {% comment %} no arguments: {% endcomment %} 
      {{ 1234567.896 | currency }} 
    {% comment %} only locale: {% endcomment %}
      {{ 1234567.896 | currency: 'en-GB' }} 
    {% comment %} locale and currency code: {% endcomment %}
      {{ 1234567.896 | currency: 'en', 'EUR' }}
    
    Output
    $1,234,567.90
    £1,234,567.90
    €1,234,567.90
    
  • floor

    Rounds a number down to the nearest integer.

    Input
    {{ 3.14 | floor }}
    
    Output
    3
    
  • format_number

    Format a number with a delimiter. This filter also takes an optional localization parameter to format a number for a specific locale.

    NOTE: This replaces the former number_with_delimeter filter.

    Input
    {{ 10000 | format_number }}
    {{ 123456.78 | format_number: "fr" }} 
    
    Output
    10,000
    123 456,78
    
  • random

    Generates a random number between 0 and an integer you specify.

    Example
    {% random 100 %}
    
  • round

    Rounds a number up or down to the nearest integer, or to a decimal place you specify.

    Input
    {{ 4.32 | round }} 
    {{ 4.32 | round: 1 }}
    
    Output
    4
    4.3
    
  • rounded_currency

    Rounds a number to the nearest whole integer and formats it to a currency. Accepts both a locale and currency code. We only accept a currency code after a locale is specified. See above for a list of specific locales and currencies.

    Input
    {% comment %} no arguments: {% endcomment %}
      {{ 1234567.896 | rounded_currency }} 
    {% comment %} only locale: {% endcomment %}
      {{ 1234567.896 | rounded_currency: 'en-GB' }} 
    {% comment %} locale and currency code: {% endcomment %}
      {{ 1234567.896 | rounded_currency: 'en', 'EUR' }} 
    
    Output
    $1,234,568
    £1,234,568
    €1,234,568
    
  • Math Filters

    Filters that perform math operations on incoming number or integer values. With the legacy liquid version, if you encounter an error with negatives while using math filters, wrap the negative numbers in quotes.

  • at_least

    Limits a number to a minimum value.

    Input
    {{ 41 | at_least: 42 }}
    
    Output
    42
    
  • at_most

    Limits a number to a maximum value.

    Input
    {{ 100 | at_most: 99 }}
    
    Output
    99
    
  • divided_by

    Divides a number by another number.

    Input
    {{ 10 | divided_by: 2.5 }}
    {{ 10 | divided_by: 4 }}
    {{ 10 | divided_by: 4.0 }}
    
    Output
    4
    2.5
    2.5
    
  • minus

    Subtracts a number from another number.

    Input
    {{ 10 | minus: 1 }}
    
    Output
    9
    
  • modulo

    Returns the remainder of division. The output will always be a positive number, even when there’s a negative number as input.

    Input
    {{ 3 | modulo: 2 }}
    
    Output
    1
    
  • plus

    Adds a number to another.

    Input
    {{ 10 | plus: 1 }}
    
    Output
    11
    
  • times

    Multiplies a number by another number.

    Input
    {{ 5 | times: 2 }}
    {{ 10 | times: 2.5 }}
    
    Output
    10
    25
    
  • String Filters

    The following filters manipulate strings in templates. You might use these to truncate or set the case of strings you reference from other places, to humanize your messages for recipients.

  • append

    Adds a string to the end of another string.

    Input
    {{ "What's all the hubbub, " | append: "bub?" }}
    
    Output
    What's all the hubbub, bub?
    
  • array_to_sentence_string

    Converts a list of data into a commma-delineated list. Use in tandem with the split filter.

    Input
    {{ customer.groceries | split:"," | array_to_sentence_string }}
    {{ customer.groceries | split:"," | array_to_sentence_string: "or" }}
    
    Output
    cherry, kiwi, and passion fruit
    cherry, kiwi, or passion fruit
    
  • base64

    Base64-encodes a string.

    Input
    {{ 'Hello, world!' | base64 }}
    
    Output
    SGVsbG8sIHdvcmxkIQ==
    
  • base64_decode

    Decode a base64-encoded string.

    Input
    {{ "Zm9vLmJhcg==" | base64_decode }}
    
    Output
    foo.bar
    
  • base64_encode

    Base64-encode a value.

    Input
    {{ "foo.bar" | base64_encode }}
    
    Output
    Zm9vLmJhcg==
    
  • base64_url_safe_decode

    Decode a string from URL-safe Base64.

    Input
    {{ "Zm9vLmJhcg" | base64_url_safe_decode }}
    
    Output
    foo
    
  • base64_url_safe_encode

    Encode a string into URL-safe Base64. To produce URL-safe Base64, this filter uses - and _ in place of + and /.

    Input
    {{ "foo" | base64_url_safe_encode }}
    
    Output
    Zm9vLmJhcg
    
  • capitalize

    Capitalize the first character in a string.

    Input
    {{ "hello world" | capitalize }}
    
    Output
    Hello world
    
  • cgi_escape

    CGI escapes a string for use in a URL.

    Input
    {{ "overview: account" | cgi_escape }}
    
    Output
    overview%3A+account
    
  • contains

    Finds a substring inside a string, or the presence of a string in an array of strings. This filter only works with strings; you cannot use it to search for an object in an array of object.

    Syntax
    {% if product.description contains 'lorem ipsum' %}
      You might also be interested in Fillerama or Office Ipsum.
    {% endif %}
    
  • downcase

    Converts a string to lower case.

    Syntax
    {{ 'STRING' | downcase }}
    
    Input
    {{ "ACME" | downcase }}
    
    Output
    acme
    
  • escape

    Escaping a string removes special characters. To encode a URL, use url_encode instead.

    Input
    {{ "win+help@customer.io" | escape }}
    
  • escape_once

    Escapes or encodes a string, but doesn’t include already-escaped characters.

    Input
    {{ "1 < 2 & 3" | escape_once }}
    
    Output
    1 < 2 & 3
    
  • hex_base64

    Returns a base64 encoding of a hex digest, like ones returned by the hmac_sha256 filter.

    Input
    {{ "Customer.io" | hmac_sha256: "some_key" | hex_base64 }}
    
    Output
    bd23cyOCFrzicxM7w/ahKoJPQd0YTQlFLwXHZZ2ufVc=
    
  • hmac_sha1

    Converts a string into an hmac_sha1 hash.

    Input
    {{ "Customer.io" | hmac_sha1: "some_key" }}
    
    Output
    2bdf556c9a75766f258d1e2824f6d0e31d1beedc
    
  • hmac_sha256

    Converts a string into an hmac_sha256 hash.

    Input
    {{ "Customer.io" | hmac_sha256: "some_key" }}
    
    Output
    6dddb773238216bce273133bc3f6a12a824f41dd184d09452f05c7659dae7d57
    
  • lstrip

    Strips all whitespace, including tabs, spaces, and newlines, from the left side of a string.

    Input
    text{{ " Customer.io " | lstrip }}text
    
    Output
    textCustomer.io text
    
  • md5

    Converts a string into an md5 hash.

    Input
    {{ "Customer.io" | md5 }}
    
    Output
    d52b6a207bf5255c05b1d0056230617e
    
  • newline_to_br

    Replaces newline with an HTML line break. input: See this example for output.

    Input
    <br />
    Customer.io<br />
    liquid<br />
    
  • normalize_whitespace

    Replaces any occurrence of whitespace with a single space.

    Input
    {{ "a \n b" | normalize_whitespace }}
    
    Output
    a b
    
  • number_of_words

    Counts the number of words in text. Learn about counting Chinese-Japanese-Korean characters.

    Input
    {{ "Welcome to Customer.io!" | number_of_words }}
    
    Output
    3
    
  • pluralize

    Outputs the singular or plural version of a string based on the value of a number. The first parameter is the singular string and the second parameter is the plural string.

    Syntax
    {{ int-val | pluralize 'singular', 'plural'}}
    
    Input
    {{ event.item_count | pluralize: 'item', 'items' }}
    
    Output
    3 items
    
  • prepend

    Adds a string to the beginning of another string.

    Input
    {{ "Sufferin' succotash!" | prepend: "Sylvester: " }}
    
    Output
    Sylvester: Sufferin' succotash!
    
  • remove_first

    Removes the first occurrence of a value from a string.

    Input
    {{ "folks that's all, folks!" | remove_first: "folks" }}
    
    Output
    that's all folks!
    
  • remove_last

    Remove the last occurence of a string within a substring.

    Input
    {{ "foobarbar" | remove_last: "bar" }}
    
    Output
    foobar
    
  • remove

    Removes a value from a string.

    Input
    {{ "And that's all, folks!" | remove: ", folks" }}
    
    Output
    And that's all!
    
  • replace

    Find and replace values within a string. The first argument represents the value you want to replace, and the second argument is the replacement.

    Syntax
    {{ "String you want to replace values in" | replace: "find-str", "replace-str" }}
    
    Input
    {{ "Coyotes never catch roadrunners!" | replace: "never", "always" }}
    
    Output
    Coyotes always catch roadrunners!
    
  • replace_first

    Find and replace the first match in a string. The first argument represents the value you want to replace, and the second argument is the replacement.

    Syntax
    {{ "String you want to replace values in" | replace_first: "find-str", "replace-str" }}
    
    Input
    {{ "roller rocket roller skates" | replace_first: "roller", "awesome" }}
    
    Output
    awesome rocket roller skates
    
  • replace_last

    Replace the last occurence of a string within a substring.

    Input
    {{ "foobarbar" | replace_last: "bar", "foo" }}
    
    Output
    foobarfoo
    
  • rstrip

    Strips all whitespace, including tabs, spaces, and newlines, from the right side of a string.

    Input
    text{{ " Customer.io " | rstrip }}text
    
    Output
    text Customer.iotext
    
  • sha1

    Converts a string into a sha1 hash.

    Input
    {{ "Customer.io" | sha1 }}
    
    Output
    c197ff0ae0a41983362f35ca972c544061c54d4c
    
  • sha256

    Converts a string into a sha256 hash.

    Input
    {{ "Customer.io" | sha256 }}
    
    Output
    6dddb773238216bce273133bc3f6a12a824f41dd184d09452f05c7659dae7d57
    
  • slice

    Returns the character located at the index specified in the first argument. You can also provide a second argument indicating the length of the string you want to return (if you want to return multiple characters).

    If the first argument is a negative number, the index is begins from the end of the string.

    Syntax
    {{ "string" | slice: <req, index of char>, <optional, length of result> }}
    
    Input
    {{ "Customer.io" | slice: 3 }}
    {{ "Customer.io" | slice: 3, 3 }}
    {{ "Customer.io" | slice: '-4', 3 }}
    
    Output
    t
    tom
    r.i
    
  • slugify

    Converts a string into a lowercase URL slug. Set the mode to specify how characters and spaces should be converted. Then set a boolean value of true if you want to retain the original casing of the string. By default, the slugify filter replaces spaces and non-alphanumeric characters with dashes and lowercases all letters.

    modereplaces
    “none”no characters
    “raw”spaces
    “default”spaces and non-alphanumeric characters
    “pretty”spaces and non-alphanumeric characters except for ._~!$&’()+,;=@
    “ascii”spaces, non-alphanumeric, and non-ASCII characters
    “latin”like default, except Latin characters are first transliterated (e.g. àèïòü to aeiou)

    Input
    {{ "The _config.yml file" | slugify }}
    
    {{ "The _config.yml file" | slugify: "pretty" }}
    
    {{ "The _cönfig.yml file" | slugify: "ascii" }}
    
    {{ "The cönfig.yml file" | slugify: "latin" }}
    
    {{ "The cönfig.yml file" | slugify: "latin", true }}
    
    Output
    the-config-yml-file
    
    the-_config.yml-file
    
    the-c-nfig-yml-file
    
    the-config-yml-file
    
    The-config-yml-file
    
  • split

    Divides an input string into an array using a separator you define. This filter is often used with a for loop.

    Input
    {% assign rolling_stones = "Mick, Keith, Ronnie, Charlie" | split: ", " %}
    
    {% for member in rolling_stones %}
      {{ member }}
    {% endfor %}
    
  • strip

    Strips all whitespace, including tabs, spaces, and newlines, from the left and right side of a string.

    Input
    text{{ " Customer.io " | strip }}text
    
    Output
    Customer.io
    
  • strip_html

    Removes HTML characters from a string.

    Input
    {{ "Eh, what's <i>up</i>, <b>Doc</b>?" | strip_html }}
    
    Output
    Eh, what's up, Doc?
    
  • strip_newlines

    Removes line breaks (\n) from a string.

    Example
    {{ product.description | strip_newlines }}
    
  • titlecase

    Converts a string to title case.

    Syntax
    {{ 'string' | titlecase }}
    
    Input
    {{ "rocket roller skates" | titlecase }}
    
    Output
    Rocket Roller Skates
    
  • truncate

    Shortens a string to the specified number of characters, adding an ellipsis if the string is longer than the value provided.

    Input
    {{ "I knew I shoulda taken that left turn at Albuquerque." | truncate: 20 }}
    
    Output
    I knew I shoulda ...
    
  • truncatewords

    Shortens a string to a specified number of words, rather than characters, and adds an ellipsis if the string contains more words than the value provided.

    Input
    {{ "I knew I shoulda taken that left turn at Albuquerque." | truncatewords: 8 }}
    
    Output
    I knew I shoulda taken that left turn...
    
  • upcase

    Converts a string to upper case.

    Syntax
    {{ 'string' | upcase }}
    
    Input
    {{ 'acme' | upcase }}
    
    Output
    ACME
    
  • uri_escape

    This filter percent encodes special characters in a URI that are not reserved.

    Input
    {{ "https://example.com/?q=foo, \bar?" | uri_escape }}
    
    Output
    https://example.com/?q=foo,%20%08ar?
    
  • url_decode

    Decodes a string that has been encoded as a URL or has been modified by url_encode.

    Input
    {{ "%27Customer.io+is+great%27" | url_decode }}
    
    Output
    Customer.io is great
    
  • url_encode

    Escapes/encodes URL-unsafe characters in a string.

    Input
    {{ "cool.person@example.com" | url_encode }}
    
    Output
    cool.person%40example.com
    
  • xml_escape

    Escapes text for use in XML. If you use this filter in HTML messages (i.e. not webhooks), the final output may differ due to HTML processing.

    Input
    {{ "Have you seen \'Learn the basics: video guide\'?" | xml_escape }}
    
    Output
    Have you read &#39;James &amp; the Giant Peach&#39;?
    
  • Miscellaneous

    These are tags that you can use to escape liquid rendering or escape rendering all together.

  • comment

    This tag doesn’t show its contents, providing a way for you to leave notes inside templates for other members of your organization.

    Syntax
    {% comment %} Don't display me! {% endcomment %}
    
  • default

    Set a default value when one does not exist. You cannot use ==/!= operators for nil/empty check. You must use default rather than checking for empty strings using == blank or != blank.

    Input
    {{ product_color | default: "red" }}
    {{ product_price | default: 2.99 }}
    
    Output
    red
    2.99
    
  • from_json

    This filter lets you create values from JSON. from_json parses string-encoded (or ‘stringified’) JSON so you can reference its values with liquid. Note that you don’t need this filter for the JSON-encoded values of people, events, or objects; they are already automatically parsed.

    Example
    {% assign var = '{"key": "value", "number": 123, "boolean": true}' | from_json %}
    {{ var.key }}
    {{ var.number }}
    {{ var.boolean }}
    
    Input
    {% assign fruit = '{"type": "kiwi", "quantity": 2, "sweet": true}' | from_json %}
    {{ fruit.type }}
    {{ fruit.quantity }}
    {{ fruit.sweet }}
    
    {% assign greeting = '[{"greeting": "hello" }, {"greeting": "hey" }, {"greeting": "hi" }, {"greeting": "howdy" }]' | from_json %}
    {{ intro[0].greeting }}
    {{ intro[1].greeting }}
    {{ intro[2].greeting }}
    {{ intro[3].greeting }}
    
    Output
    kiwi
    2
    true
    
    hello
    hey
    hi
    howdy
    
  • generate_uuid

    Generate a UUID.

    Example
    {% generate_uuid %}
    
  • json

    Converts values to a JSON-encoded string (same as using jsonify). An additional space parameter can be specified to format/prettify the JSON.

    Input
    {% assign arr = "foo bar coo" | split: " " %}
    {{ arr | json: 4 }}
    
    Output
    [
      "foo",
      "bar",
      "coo"
    ]
    
  • raw

    Temporarily disables Liquid processing. You might use this to escape tag processing if you use a conflicting syntax or you want to show raw liquid syntax in your message."

    Example
    {% raw %}
      {{This}} is displayed exactly as typed.
    {% endraw %}
    
  • to_json

    Outputs the json representation of the input. For example, {{ customer | to_json }} sends all your customer data into a JSON variable.

    Example
    {{ customer | to_json }}
    
  • whitespace control

    You can remove whitespace before and/or after a tag using hyphens.

    Input
    {% assign username = "Charlie" %}
    Hello, {{ username -}} !
    
    Output
    Hello, Charlie!
    
Copied to clipboard!
Version