Variable Reference Syntax
Every field in Glow that accepts dynamic values supports {{ }} placeholders. When the workflow runs, Glow replaces each placeholder with the actual value from that run.
This page is the complete reference for what you can put inside the braces. Every form, in one table — the rest of the page explains each one.
| Reference | What it gives you |
|---|---|
{{ 3.field }} | A field from step 3’s output |
{{ 1.customer.address.city }} | A field inside a record |
{{ 1.items.0.name }} | The first item of a list — dots only, never [0] |
{{ 5.$full_result }} | A step’s entire output object |
{{ item }} / {{ item.field }} | Current item in “Run for each item” |
{{ item.$index }} / {{ item.$total }} | Position and size of the current batch |
{{ 5.results }} | Everything a looping step produced (successes only) |
{{ 5.items }} | Every item with its position, status and error |
{{ 5.stats }} | A looping step’s counts: total, succeeded, failed, skipped |
{{ $item }} / {{ $itemIndex }} | Current item inside a Filter’s rules |
{{ $now }} / {{ $today }} | Current UTC datetime / date |
{{ $var.KEY }} | Team variable |
{{ $secret.KEY }} | Team secret (decrypted at run time) |
{{ $file.<id> }} | Team file |
{{ $webhook.1.url }} | Deployed URL of the webhook at step 1 |
{{ $workflow_url }} | Canvas URL of the running workflow |
The {{ }} syntax
Wrap any reference in double curly braces:
{{ 3.email }}A placeholder is one of two things:
- A step reference: a step number, followed by a path into that step’s output.
- A system variable: a
$-prefixed name such as{{ $now }}or{{ $secret.API_KEY }}.
Whitespace inside the braces is ignored, so {{3.email}} and {{ 3.email }} are equivalent.
Steps are referenced by number, not by name. Renaming a step on the canvas
does not change how you reference it. {{ 3.email }} always means “the
output of step 3”. There is no {{ trigger.… }} or {{ myStepName.… }}
form.
Referencing step output
Each step on the canvas has a number shown on the step itself. Use that number, then drill into the output with dot notation.
{{ 1.email }}
{{ 2.ret.email }}Given this output from step 1:
{
"email": "[email protected]",
"name": "Ada Lovelace"
}{{ 1.email }}resolves to[email protected]{{ 1.name }}resolves toAda Lovelace
The trigger is a step like any other, so you reach what arrived at it the same way. What a webhook received sits at the top level, so a POST of {"email": "…"} to a trigger numbered 3 gives you {{ 3.email }}. There is no wrapper to reach through. For the whole payload rather than one field, use {{ 3.$full_result }}.
The examples on this page write the trigger as 1 for readability. Read the real number off the step on your own canvas — see where the numbers come from below.
The path after the step number depends on which step it is. There is no single wrapper every step uses, so this is the table to check before you type a path by hand:
| The step | Files its answer under | You write |
|---|---|---|
| App action steps — Slack, Google Sheets, the rest of the catalogue | ret | {{ 2.ret.email }} |
| HTTP Request | ret | {{ 2.ret.body }} |
| Tools — Split Text, HTML to text and the like | ret | {{ 2.ret }} |
| AI steps, the AI Agent included | result | {{ 2.result }} |
| Code editor — one level deeper | result.executionOutput | {{ 2.result.executionOutput }} |
| List steps — Sort, Remove duplicates, Limit, Combine | results, resultCount | {{ 2.results }} |
| Triggers, and Glow’s own flow steps — Filter, Repeater, Date, Human Review | nothing — fields sit at the top level | {{ 1.email }} |
The last row is the one that catches people. A trigger is not an app step:
an app action runs and files its answer under ret, while a trigger’s payload
is stored as the result itself. So the same field is {{ 2.ret.email }} from a
Slack action and {{ 1.email }} from the trigger that started the run.
Pick values from the data icon rather than typing a path from memory, and check the step’s Output Data on a test run before you build against it.
A reference that finds nothing stops the run
Whether the step number is wrong or the path after it is, the step fails with the same message: “Placeholder 5.email didn’t find data”. Open the run in Executions and expand the step to read it.
The failure is deliberate. A reference that resolved to nothing would send an empty field to whatever comes next. You would find out from the destination rather than from Glow.
A wrong number is the easier of the two to reach for. Picking values from the data icon avoids both.
The number is the step’s name, not its position
A step’s number is fixed when the step is created and stays with it for life. It is not “the Nth step from the top”, and it does not change when you delete a step, reorder the canvas, or move the step somewhere else.
Numbers are never reused. Delete step 4 and the next step you add takes a new number rather than filling the gap. That is deliberate: if numbers were reclaimed, every {{ 4.… }} reference elsewhere in the workflow would quietly start pointing at a different step.
So the numbers on a working canvas are often not 1, 2, 3 in a row, and the first step is not always 1. That is normal. Read each number off the step itself, or insert references from the data icon and never type one.
Nested fields
Dot notation chains as deep as the data structure requires. There is no depth limit.
{{ 1.customer.address.city }}Picking an item out of a list
Reach into a list the same way you reach into a record — with a dot — but using
the item’s position instead of a name. Counting starts at zero, so the first
item is 0:
{{ 1.items.0.name }}
{{ 1.items.2.price }}Given:
{
"items": [
{ "name": "Widget A", "price": 9.99 },
{ "name": "Widget B", "price": 14.99 },
{ "name": "Widget C", "price": 24.99 }
]
}{{ 1.items.0.name }}resolves toWidget A, the first{{ 1.items.2.price }}resolves to24.99, the third
Square brackets do not work. {{ 1.items[0].name }} is read as a
field literally named items[0], which does not exist. The step fails with a
message about not finding the data, pointing you at your upstream step rather
than at the syntax. Use dots throughout. Picking a value from the data
selector always produces the correct
form.
To process every item rather than a specific one, use Run for each item instead of indexing.
The whole output object
To pass a step’s entire output rather than one field, use $full_result:
{{ 5.$full_result }}Objects and arrays are serialised to JSON when inserted into a text field. This is the usual way to hand a complete payload to an AI step or an HTTP request body.
Loop item variables
Inside a step running in Run for each item mode, the current item is bound to item:
| Placeholder | Resolves to |
|---|---|
{{ item }} | The current item itself |
{{ item.email }} | A field of the current item |
{{ item.$index }} | Zero-based position of the current item |
{{ item.$total }} | Total number of items in the batch |
Position and size sit under item. Write {{ item.$index }}, not a bare {{ $index }}. Glow does not recognise the bare form and passes it through as literal text, so the characters {{ $index }} arrive at the receiving service.
Reading an earlier looping step’s result for this item
When two steps loop over the same list, {{ N.item }} gives you what step N produced for the item being processed right now. So “the record step 5 created for this same lead” stays correct as the batch works through the list.
| Placeholder | Resolves to |
|---|---|
{{ 5.item }} | What step 5 produced for this item |
{{ 5.item.email }} | A field of it |
{{ 5.item.$index }} | Position of this item in the batch |
{{ 5.item.$total }} | How many items there are |
That is different from {{ N.results }}, which is the whole collected list. Because results holds successes only, its positions stop matching your input list as soon as any item fails. Use {{ N.item }} when you need the result that belongs to the current item, and {{ N.results }} when you want the collection as a whole.
What a looping step collects
When the loop finishes, it passes on three references. This is the same set for Run for each item and for the Repeater step.
| Reference | What it holds |
|---|---|
{{ N.results }} | Successful results only, in the order of your input list |
{{ N.items }} | Every item with its position, status and error |
{{ N.stats }} | total, succeeded, failed, skipped |
stats is what a summary message wants: “Processed 47 of 50” needs no counting on your side.
results and items answer different questions. results is the collection to hand to the next step, and it holds successes only — so when some passes fail it is shorter than the list you put in, and its third entry is not necessarily your third item. items keeps one entry per item instead, each carrying that item’s position, whether it succeeded, and the error if it did not. Reach for items when you need results lined up against your input, or when you need to see what failed.
Filter rules use a different item variable
Inside a Filter step’s rules, the current item is $item, with the dollar sign:
| Placeholder | Resolves to |
|---|---|
{{ $item }} | The whole item being tested |
{{ $item.status }} | A field of it |
{{ $itemIndex }} | Its position in the list, from 0 |
The two forms are not interchangeable. Filter uses $item; “Run for each
item” uses item, with no dollar sign. Each one is left untouched by the
other mechanism, so a {{ item }} written into a Filter rule compares dead
text rather than the item you meant.
System variables
These resolve without referencing any step.
| Placeholder | Resolves to |
|---|---|
{{ $now }} | Current UTC date and time at the moment the step runs |
{{ $today }} | Current UTC date |
{{ $workflow_url }} | Absolute canvas URL of the running workflow |
{{ $workflow_footer }} | A ready-made Markdown backlink to the workflow |
{{ $user.name }} | Name of the person who created the workflow |
{{ $user.email }} | Email of the person who created the workflow |
$user.name and $user.email describe the workflow’s creator, not whoever pressed Run. They suit a signature line or a reply-to address. If the creator’s profile is missing that field, the step fails and says so, rather than sending an empty value on.
$workflow_url and $workflow_footer are useful in generated output. A Slack message or email can link straight back to the workflow that produced it.
Team variables and secrets
Reference workspace-level values configured in Secrets & Variables:
{{ $var.REGION }}
{{ $secret.STRIPE_API_KEY }}$var.injects a plain team variable.$secret.injects a decrypted secret at run time without placing the value on the canvas. If the exact secret value appears in a stored step result or error, standard run processing replaces it with[REDACTED]. Store tokens as Glow Secrets rather than pasting them directly into step fields.
Keys are upper-cased before they are looked up, so {{ $var.region }} and {{ $var.REGION }} mean the same thing. Name your variables and secrets in upper case to match.
Files
Reference a file stored in File Management by its id:
{{ $file.<id> }}The id is on the file’s row in Files.
What you get back depends on the file. A text-like file is inserted as its contents, so {{ $file.<id> }} in an AI Prompt hands the model the text itself. A binary file (a PDF, an image, a spreadsheet) is inserted as a short-lived download URL instead. That is what you want for a step that fetches or forwards the file, not for one expecting to read it. Test with the kind of file you will use in production, not with a .txt stand-in.
Webhook URLs
Reference the deployed endpoint URL of a webhook trigger elsewhere in the same workflow:
{{ $webhook.1.url }}Where 1 is the step number of the webhook trigger.
This works on the generic Webhook trigger only. App triggers that receive their own callbacks do not expose a URL this way.
While the workflow is still a draft the endpoint does not exist yet, so the variable resolves to the text [URL generated upon activation]. That is expected. It lets you map the reference downstream before going live. Activate the workflow and the real URL appears in its place.
Using the Visual Workflow data panel
You do not need to type placeholders from memory, or work out step numbers yourself.
- Click into any configurable field in the App drawer.
- Click the data icon at the edge of the field.
- A panel opens showing the available output of every previous step, as a tree with a preview of the last known value.
- Click a field to insert the correct reference at your cursor.
The selector writes the same {{ }} syntax described on this page. It is faster and avoids typos. Typing by hand is useful when you already know the path or are editing a reference inline.
The selector can only show data it has seen. Run a step once (or send a test payload to your webhook) so Glow has a sample of its output to offer you.
Examples
Referencing a webhook payload
A webhook trigger — written here as step 1 — receives a form submission. To use the submitted address in an email step:
{{ 1.email }}The payload the webhook received is the step’s output, so a field named email in the request body is {{ 1.email }}. There is no body wrapper to go through.
Inside an AI Prompt
Placeholders work inline with plain text:
Summarize this email from {{ 1.sender }}: {{ 1.content }}The AI step receives only the text you write, so any data you do not reference is invisible to the model.
In a Condition
Step 3 returns a lead score and you want to route high scorers. Set the Condition’s data reference to:
{{ 3.score }}Then set the operator to is greater than and the value to 80.
In an HTTP request
Placeholders work in URLs, headers, and request bodies:
https://api.example.com/users/{{ 1.userId }}If userId resolves to 42, the request goes to https://api.example.com/users/42.
Injecting a secret into a header
Authorization: Bearer {{ $secret.STRIPE_API_KEY }}What’s Next?
- Data Transformation: Tidy strings, calculate numbers, format dates, and parse domains on dynamic tokens.
- Workflow Data: Learn how data moves across canvas steps and how to inspect payloads.
- Secrets & Variables: Store reusable values and encrypted credentials across your workspace.