Overview
Every text field in a Taskade automation is a LiquidJS template. Anywhere you can type a value, you can also pipe values through filters that transform them inline — encode a string for JSON, pad an order number with zeros, shift a date forward by 30 days, or camelize a slug for an API call.
Taskade ships a curated set of filters: 9 custom Taskade filters for the transformations real automations need, plus 17 whitelisted standard LiquidJS filters. Anything else throws a clear error rather than running surprising code on your data.
TL;DR: Wrap any value in
{{ variable | filterName: arg }}. Pair with the HTTP Request, Webhook, or any Action to clean values right where you use them.
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.
{{ "[email protected] " | downcase | strip }}
→ [email protected]
Custom Taskade filters
These nine filters ship with every automation. They cover the gaps standard LiquidJS leaves — base64, padding, date 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 | btoa(value) — encode to base64 |
{{ "hello" | base64encode }} → aGVsbG8= |
base64decode |
String | atob(value) — decode from base64 |
{{ "aGVsbG8=" | base64decode }} → hello |
padStart |
String | String.padStart(length, element) |
{{ "42" | padStart: 6, "0" }} → 000042 |
padEnd |
String | String.padEnd(length, element) |
{{ "abc" | padEnd: 6, "-" }} → abc--- |
encodeJsonValue |
String | JSON-safe escaping. JSON.stringify(value) then strip the outer quotes — for safely embedding values inside hand-written JSON. |
{{ "He said \"hi\"" | encodeJsonValue }} → He said \"hi\" |
power |
Math | Math.pow(value, exponent) |
{{ 2 | power: 10 }} → 1024 |
log |
Math | Math.log10(value) |
{{ 1000 | log }} → 3 |
dateOffset |
Date | Add an ISO 8601 duration to a date. | {{ "2026-01-01" | dateOffset: "P30D" }} → 2026-01-31 |
ISO 8601 durations for dateOffset
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.
Whitelisted standard filters
LiquidJS ships ~40 default filters. Taskade enables 17 of them — the safe, useful ones. Everything else throws `Filter '<name>' is disabled` so flows fail loudly instead of running unexpected logic.
| Category | Filter | Example |
|---|---|---|
| String | upcase |
{{ "hello" | upcase }} → HELLO |
| String | downcase |
{{ "HELLO" | downcase }} → hello |
| String | strip |
{{ " hi " | strip }} → hi |
| String | url_encode |
{{ "a b&c" | url_encode }} → a%20b%26c |
| String | 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_string |
{{ created | date_to_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 | modulo |
{{ 10 | modulo: 3 }} → 1 |
| Math | abs |
{{ -7 | abs }} → 7 |
| Math | ceil |
{{ 4.2 | ceil }} → 5 |
| Math | floor |
{{ 4.8 | floor }} → 4 |
Anything outside this list — replace, split, slice, truncate, escape, and similar — is intentionally disabled. Reach for the Utility Actions (JSON Extract, Transform Array, Text Replace) when you need that kind of work.
Common recipes
Concrete patterns you can lift straight into a flow.
Base64 a Basic Auth header for an HTTP Request
Authorization: Basic {{ "user:password" | base64encode }}
Pad an invoice number for downstream systems
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 when one field has quotes
{
"title": "{{ task.title | encodeJsonValue }}",
"url": "{{ task.url | url_encode }}"
}
Format a percentage from raw counts
{{ 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 }}will fail;{{ "foo" \| upcase }}is the one that runs.
Gotchas
A few behaviors that catch flow 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.
camelizefollows Shopify, not standard JS. It capitalizes the first letter (UserProfile), splits on_and/, and turns/into::. If you want lower-camelCase or different separators, use JSON Extract 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.- Disabled filters throw immediately. A flow that uses
replacewill fail on render, not at runtime — you'll see it in the Runs tab on the first execution. - A fresh engine per render. Filters can't share state between renders. Each automation step gets its own Liquid engine.
Plan availability
Filters are available on every plan that can author automations.
| Plan | LiquidJS filters |
|---|---|
| Free, Starter | ✅ Full access inside any automation |
| Pro, Business, Max, Enterprise | ✅ Full access inside any automation |
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 — JSON Extract, Transform Array, and Text Replace for transformations filters don't cover
- Structured Output — Typed agent responses you can pipe into filters
