Templates put live values into workflow step parameters. Anythink resolves them immediately before each step runs.
{{ $anythink.trigger.data.email }}
Syntax
- A template is an expression inside
{{ }}. Spaces inside the braces are ignored.
- A value can contain several templates and plain text:
"Order {{ $anythink.trigger.id }} for {{ $anythink.trigger.data.email }}".
- When a whole parameter is a single path, the braces are optional:
"loop_over": "$anythink.steps.find_orders.data".
- The only filter is
default, which supplies a value when the path doesn't exist:
{{ $anythink.trigger.data.nickname | default: "there" }}
Variables
| Expression |
Value |
$anythink.trigger.id |
The id the job started with: the record id for entity events, entity_id for manual and API calls, empty for schedules |
$anythink.trigger.data |
The trigger data. See Triggers and scheduling for what each trigger provides. |
$anythink.trigger.data.<field> |
One field. Paths can go deeper: address.city, items[0].sku. |
$anythink.steps.<key> |
The output of an earlier step with that key |
$anythink.steps.<key>.data[0].<field> |
A field from the first item of a step's data list |
$anythink.steps.<key>.data[*].<field> |
That field from every item, as a list |
$anythink.secrets.<name> |
A project secret, decrypted. Always text. |
$anythink.now |
The current time in UTC, such as 2026-09-14T08:30:00.000Z |
<field> with no prefix |
A field of the current item, inside steps that repeat per item (see below) |
Following relationships from trigger data
Trigger data paths follow relationships. If an order has a customer relationship, {{ $anythink.trigger.data.customer.email }} loads the related customer and reads its email. A field named customer_id is followed the same way.
Relationship lookups work on trigger data for entity events, not on step outputs.
The current item
Some steps repeat for each item in a list. Inside them, the item's fields are available without a prefix:
| Step |
Repeats for |
| Create data, Upsert data |
Each item in loop_over |
| Update data with filters |
Each matched record |
| Send a push notification |
Each item of the step referenced with data[*] |
{
"entity_name": "invoices",
"loop_over": "{{ $anythink.steps.due_orders.data }}",
"payload": "{ \"order_id\": \"{{ id }}\", \"amount\": \"{{ total }}\", \"issued_at\": \"{{ $anythink.now }}\" }"
}
Types
In JSON parameters such as payload and body, a template keeps the value's type when it is the entire JSON value:
{ "total": "{{ $anythink.trigger.data.total }}" } → { "total": 129.5 }
{ "tags": "{{ $anythink.trigger.data.tags }}" } → { "tags": ["gift", "express"] }
When a template is part of longer text, the value is written as text. Lists and objects become compact JSON, and booleans are written True or False:
{ "summary": "Total {{ $anythink.trigger.data.total }}" } → { "summary": "Total 129.5" }
In parameters that aren't JSON — URLs, header values, filter values, email addresses and ids — the result is plain text.
Note: Write payloads as valid JSON, with each template in quotes. Anythink only escapes values and keeps their types when the payload parses as JSON before templates are filled in. An unquoted template such as { "total": {{ total }} } isn't valid JSON, so a value containing quotes or a new line can break the payload.
Note: Once a JSON payload contains a template, its other numbers are re-read as standard numbers. Very large ids (beyond 2^53) can lose precision. Send them as text.
Missing and empty values
| Situation |
Result |
| The path, step or list item doesn't exist |
The template is left as written, braces included |
The path doesn't exist and has default |
The default |
| The value exists but is null |
null when the template is the whole JSON value; empty text inside longer text |
| The secret doesn't exist |
The step fails with "Failed to retrieve secret with key…" |
Unresolved templates stay in the output, so a typo shows up in the saved record or the step log rather than silently producing an empty value. Send an email and Send a push notification refuse to send anything that still contains {{.
A Read data step that returns no records leaves $anythink.steps.<key>.data[0].<field> unresolved, and an unresolved path compares as text in a Condition. To branch on whether anything was found, return a count from Run a script (return { count: $anythink.steps.find_orders.data.length };) and compare that count in the Condition.
Where templates apply
| Step |
Templated |
Not templated |
| Read data |
Filter values |
Entity, fields, sort, limit, filter fields |
| Create data, Upsert data |
payload, loop_over, rls_user_group_id |
entity_name, match_on |
| Update data |
payload, ids, filter values, rls_user_group_id |
entity_name, rls_mode |
| Delete data |
Filter values |
entity_name |
| Condition |
field and value |
logical_operator |
| Call an API |
url, header values, body |
method, header names, results_path |
| Send an email |
to, from, payload, attachment ids |
template_type |
| Send a push notification |
Title, body, image, click action, category, data values, audience ids |
template_type, buttons |
| File handler |
Entity, record id, field, source URL, file name, folder, existing file id |
operation, link_mode |
| Integration |
Text values in inputs, connection_id, credential_field_path |
provider, operation |
| Run a script |
Not templated. Use the $anythink object in the script. |
|
Trigger filters don't use templates.
Next steps