Skip to Content
📚 ReferenceVariable Syntax

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.

ReferenceWhat 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" }

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 stepFiles its answer underYou write
App action steps — Slack, Google Sheets, the rest of the catalogueret{{ 2.ret.email }}
HTTP Requestret{{ 2.ret.body }}
Tools — Split Text, HTML to text and the likeret{{ 2.ret }}
AI steps, the AI Agent includedresult{{ 2.result }}
Code editor — one level deeperresult.executionOutput{{ 2.result.executionOutput }}
List steps — Sort, Remove duplicates, Limit, Combineresults, resultCount{{ 2.results }}
Triggers, and Glow’s own flow steps — Filter, Repeater, Date, Human Reviewnothing — 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 to Widget A, the first
  • {{ 1.items.2.price }} resolves to 24.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:

PlaceholderResolves 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.

PlaceholderResolves 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.

ReferenceWhat 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:

PlaceholderResolves 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.

PlaceholderResolves 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.

  1. Click into any configurable field in the App drawer.
  2. Click the data icon at the edge of the field.
  3. A panel opens showing the available output of every previous step, as a tree with a preview of the last known value.
  4. 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.