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.
{{ "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 inrawopts 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_expandgroup_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.sha256andhmac_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. Usejsonwhen 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
Authorization: Basic {{ "user:password" | base64encode }}
Pad an invoice number
INV-{{ invoiceNumber | padStart: 8, "0" }}
→ INV-00001042
Add 14 days to a contract date
{{ trigger.body.signedAt | dateOffset: "P14D" | date: "%Y-%m-%d" }}
Camelize a slug for a JS API call
{ "{{ name | camelize }}": true }
Build a clean JSON body
{
"title": "{{ task.title | encodeJsonValue }}",
"url": "{{ task.url | url_encode }}"
}
Format a percentage
{{ 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.
camelizecapitalizes the first letter. You getUserProfile, notuserProfile. It splits on_and/, and turns/into::. For other casing rules, use the Change Capitalization utility action instead.encodeJsonValuestrips 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.
Related guides
- Automations Execution. How rendering and retries work end-to-end
- HTTP Request Action. The most common place to use
base64encodeandurl_encode - Webhook Trigger. Receive payloads to filter through these expressions
- Utility Actions. Get Multiple Values (JSONPath), Transform Array Into String, and Find and Replace Text for transformations filters do not cover
- Structured Output. Typed agent responses you can pipe into filters