Automation

Filters: Transform Values Inline in Automations

Updated 2026-09-02·12 min read

Overview

Every text field in a Taskade automation can hold {{ variables }}. Pipe a value through filters right where you use it: tidy Alice@Example.COM into alice@example.com, pad an order as INV-00001042, or push a due date 30 days out. No extra step, and no code.

Taskade ships its own filters for the transformations real automations need. A reviewed set of the standard text, date, math, and list filters runs alongside them. Standard filters outside that set stay switched off, and each one throws a clear error instead of running surprising code on your data.

TL;DR: Wrap any value in {{ variable | filterName: arg }} to clean it up right where you use it. Taskade filters cover base64, padding, date formats, and date math, and a reviewed set of standard text, date, math, and list filters works alongside them. Whole records arrive as readable JSON. Pair with HTTP Request or any action.

How filters fit into the loop

A filter runs after the variable resolves but before the rendered value is handed to the action. Everything happens inline in a single render pass.

Filters chain left-to-right with |. The output of one filter becomes the input of the next.

Liquid
{{ "Alice@Example.com " | downcase | strip }}
→ alice@example.com

Pass whole records between steps

Drop a whole record or list into a field and it now arrives as readable JSON. Write {{ trigger.task }} into an Ask AI prompt and the model receives the task's actual fields. Earlier it received the literal text [object Object], and a list of records ran together as [object Object][object Object] with nothing separating them.

You write You used to get You get now
{{ trigger.task }} [object Object] {"id":"t_1","title":"Ship v2"}
{{ trigger.tasks }} [object Object][object Object] [{"id":"t_1"},{"id":"t_2"}]
{{ trigger.counts }} 12 [1,2]
{{ trigger.title }} Ship v2 Ship v2 (unchanged)

Plain text and numbers render exactly as they always did, and an empty value still renders as nothing at all.

What this does not change

This is a formatting improvement on the way out of a field, not a conversion that reshapes your data. Four things to keep in mind:

  • Filters still run first. {{ order | json }} and every other chain behaves as before. A chain that ends in raw opts out of the JSON form entirely.
  • Conditions compare the real value. Your Filter and Branch steps, and any {% if %}, still test the underlying value rather than this JSON text. Existing automations keep their behavior.
  • A record that refers back to itself falls back. A value that cannot be written as JSON renders in the old plain-text form instead of failing the run.
  • Very large records still have a ceiling. Repeating a huge record many times inside one field can exceed what a single render can build. The step then fails with a memory message instead of a quiet truncation.

When the next step only needs one field, name that field or use Get Multiple Values (JSONPath). Handing a model an entire record costs more tokens than handing it the two values it reads.

Custom Taskade filters

These filters ship with every automation. They cover what the standard filters leave out: base64, padding, date formatting and shifting, JSON-safe escaping, and a Shopify-style camelize.

Filter Category What it does Example
camelize String Shopify-style camelCase. Splits on _ and / (slashes become ::). Capitalizes first letter. {{ "user_profile" | camelize }} → UserProfile
base64encode String Encode text to base64, for an authorization header {{ "hello" | base64encode }} → aGVsbG8=
base64decode String Decode base64 back to text {{ "aGVsbG8=" | base64decode }} → hello
padStart String Pad to a fixed width from the left {{ "42" | padStart: 6, "0" }} → 000042
padEnd String Pad to a fixed width from the right {{ "abc" | padEnd: 6, "-" }} → abc---
encodeJsonValue String Escape quotes and line breaks so a value is safe to drop inside JSON you wrote by hand {{ "He said \"hi\"" | encodeJsonValue }} → He said \"hi\"
power Math Raise a number to a power {{ 2 | power: 10 }} → 1024
log Math Base-10 logarithm {{ 1000 | log }} → 3
dateOffset Date Add an ISO 8601 duration to a date. {{ "2026-01-01" | dateOffset: "P30D" }} → 2026-01-31
dateFormat Date Reformat a date using a named preset or your own pattern. {{ "2026-08-24" | dateFormat: "dd/MM/yyyy" }} → 24/08/2026

dateFormat presets

Pass one of the five preset names, or any pattern of your own such as dd/MM/yyyy.

Preset You get
date Calendar date only
time Hours and minutes
datetime Date plus hours and minutes
iso Machine-readable form, matching the precision the value came in with
long Spelled-out month, day, year, and time

The Format picker beside a date variable writes these same preset names for you, so you rarely have to type one by hand. A value the filter cannot read as a date passes through unchanged rather than failing the step.

dateOffset duration strings

dateOffset accepts any ISO 8601 duration string. Use these as a starting point:

Duration Meaning
P1D + 1 day
P7D + 1 week
P30D + 30 days
P1M + 1 month
P1Y + 1 year
PT1H + 1 hour
PT30M + 30 minutes
-P1D − 1 day (negate with leading -)

Combine into compound durations: P1Y2M3DT4H5M = 1 year 2 months 3 days 4 hours 5 minutes.

Standard filters

The filter syntax is Liquid, and Taskade runs the open-source LiquidJS implementation of it. Reach for a LiquidJS filter reference rather than a general Liquid one, because the two ship different filter sets. Either way, a reference is not a promise that every filter you read about runs here.

Taskade enables a reviewed set of the standard filters, and anything outside that set stays switched off. Before you build on a filter you found elsewhere, check What stays switched off below and try it in the Runs tab.

Text, date, math, array, and object filters all work, so replace, split, truncate, join, size, sort, default, and json are available to you alongside the Taskade filters above. The list below is a sample of the ones you reach for most, not the full set.

Category Filter Example
Text upcase {{ "hello" | upcase }} → HELLO
Text downcase {{ "HELLO" | downcase }} → hello
Text strip {{ " hi " | strip }} → hi
Text replace {{ "a-b" | replace: "-", " " }} → a b
Text truncate {{ "long title here" | truncate: 9 }} → long t...
Text url_encode {{ "a b&c" | url_encode }} → a%20b%26c
Text url_decode {{ "a%20b" | url_decode }} → a b
Date date {{ created | date: "%Y-%m-%d" }} → 2026-05-13
Date date_to_long_string {{ created | date_to_long_string }} → 13 May 2026
Date date_to_xmlschema {{ created | date_to_xmlschema }} → 2026-05-13T00:00:00Z
Math plus {{ 5 | plus: 3 }} → 8
Math minus {{ 5 | minus: 3 }} → 2
Math times {{ 5 | times: 3 }} → 15
Math divided_by {{ 10 | divided_by: 4 }} → 2.5
Math round {{ 4.56 | round: 1 }} → 4.6
Math ceil {{ 4.2 | ceil }} → 5
Math floor {{ 4.8 | floor }} → 4
List size {{ items | size }} → 3
List join {{ names | join: ", " }} → Ana, Ben
List first {{ items | first }} → the first entry
List map {{ orders | map: "total" }} → only the totals
Value default {{ nickname | default: "there" }} → there when empty
Value json {{ order | json }} → the record as JSON text

What stays switched off

A standard filter outside the reviewed set throws `Filter '<name>' is disabled` so an automation fails loudly instead of doing something surprising. These are the ones worth knowing about:

  • Filters that take an expression as their argument, such as where_exp and group_by_exp. Their argument is evaluated as template code, so a value from a trigger can turn into logic.
  • sample, which picks at random. The same inputs can render differently on a retry, which makes a run impossible to debug.
  • sha256 and hmac_sha256, which sign and hash rather than shape data. Signing also tempts you to type a secret key into the automation itself.
  • inspect, a debugging view with its own placeholder markers. Use json when you want to see a whole value.

When a filter chain is not the right tool, reach for the Utility Actions. Get Multiple Values (JSONPath) handles deep or filtered lookups. Lookup Table maps codes to labels. The text actions handle multi-step cleanup.

Common recipes

Concrete patterns you can lift straight into an automation.

Base64 a Basic Auth header

Liquid
Authorization: Basic {{ "user:password" | base64encode }}

Pad an invoice number

Liquid
INV-{{ invoiceNumber | padStart: 8, "0" }}
→ INV-00001042

Add 14 days to a contract date

Liquid
{{ trigger.body.signedAt | dateOffset: "P14D" | date: "%Y-%m-%d" }}

Camelize a slug for a JS API call

Liquid
{ "{{ name | camelize }}": true }

Build a clean JSON body

Liquid
{
  "title": "{{ task.title | encodeJsonValue }}",
  "url": "{{ task.url | url_encode }}"
}

Format a percentage

Liquid
{{ completed | times: 100 | divided_by: total | ceil }}%

Where you can use filters

Filters work inside any rendered field. Wherever you can type @variable or {{ }}, you can also append a filter pipeline.

Surface Filters work here?
HTTP Request body / headers / URL ✅
Webhook action payload ✅
Send Email body ✅
Create Task title / description ✅
Custom Field updates ✅
Branch conditions (right side of comparison) ✅
Loop iteration variables ✅

💡 Tip: Filters are case-sensitive. {{ "foo" \| Upcase }} fails. {{ "foo" \| upcase }} is the one that runs.

Gotchas

A few behaviors that catch automation authors off guard:

  • Graceful fallback on type mismatch. If you pipe a number into a string-only filter, you get the original value back, not an error. Test in the Runs tab before relying on the output.
  • camelize capitalizes the first letter. You get UserProfile, not userProfile. It splits on _ and /, and turns / into ::. For other casing rules, use the Change Capitalization utility action instead.
  • encodeJsonValue strips the outer quotes. That makes it safe to embed inside a hand-written JSON string. If you want a fully-quoted JSON value, the surrounding " chars are on you.
  • A disabled filter fails the step, it does not skip. You see the message in the Runs tab on the first execution.
  • Nothing carries over between renders. Each automation step renders on its own, so a filter cannot pass state to a later step. Use a step's output for that.

Plan availability

Filters are part of the automation editor, so every plan that can build an automation gets the full set. There is no separate upgrade for them. Some connectors and triggers do have their own plan requirements, which the step tells you when you add it.


Was this helpful?