Skip to content

Variables in flows

Keep a value for one run, the whole chat or the contact, read the contact's and the chat's own details, and work values out with the Set variable step.

A variable holds a value a flow uses later: an answer the customer typed, a value your system sent back, or something the flow worked out. You use it in text as {{name}}, test it in a Condition, or send it to your system.

This page covers where a variable's value is kept, the values every flow can read without declaring anything, and the Set variable step. To add a variable, see Variables in Build a flow.

Where a value is kept

When you add a variable, Keep the value for says how long it lasts and who else can read it:

ChoiceWhat it means
This run onlyThe value is gone when this run of the flow ends. Use it for working values. This is the default.
The whole chatEvery flow in the same chat can read the value, by the same name, until the chat is resolved, or until 7 days pass with no customer message and no flow step.
Save to the contactThe value is written to one of the contact's custom fields, so it stays with the contact in every chat, and your team sees it on the contact.

A value kept for the whole chat is shared by name. If a billing flow sets plan and a support flow that runs later in the same chat also declares plan for the whole chat, the support flow reads the billing flow's value. An agent's own message doesn't keep the chat's values alive; only the customer's messages and the flows' steps do. When the chat's values are gone, the next flow that writes one starts afresh.

Note: A flow reads the chat's values and the contact's fields when it starts, and again after every wait (a delay, or waiting for a reply). Between two of those, a value never changes under it. If two flows write the same value for the whole chat, the one that writes last wins.

Save to the contact

Choose the Contact field the value goes into. Only fields that can hold the variable's type are offered:

Variable typeContact field types
TextText, or a choice list (the value must be one of its options)
NumberNumber
True or falseTrue or false
Date and timeDate (saved as the date in your organisation's time zone)

A Contact, List or Object variable can't be saved to the contact. Two variables can't share one field. If the field is later deleted, or no longer fits the variable's type, the builder tells you when you save. Saving a value changes the field as any other change would, so a flow that starts when that field changes may start.

Who sees a value kept for the whole chat

Two settings apply to values kept for the whole chat only:

  • Hide from agents: the value isn't shown in the chat's side panel to anyone, whatever their role. Tick it for tokens, keys and internal ids. The builder suggests it when a name looks like one, such as crm_token or api_key.
  • Share with AI: an AI agent step in this flow gets the value as background information about the chat. The AI treats it as data, never as instructions. At most 4 KB of shared values go to the AI. Leave it off for anything private, or anything your AI provider shouldn't see.

To change where an existing variable is kept, open Settings for the variable in the Variables panel. Its name can't change.

Note: A test run is a real run on the test contact, so it reads and changes that contact's real chat values and fields. To try made-up values, simulate the flow instead.

Values every flow can read

You don't declare these. They're in the Insert a variable list under System values:

ValueWhat it reads
{{contact.name}}The contact's name
{{contact.id}}The contact's id
{{contact.phone}}The contact's number with the country code, like +15555550100
{{contact.wa_id}}The WhatsApp id: the same number's digits only, like 15555550100
{{contact.consent_state}}Whether the contact agreed to messages. In text only: see below
{{conversation.id}}The chat's id
{{conversation.phone_number_id}}Your WhatsApp number's Meta id
{{conversation.channel_number}}Your WhatsApp number, like +15555550199
{{conversation.opened_at}}When the chat opened

A flow with no contact, such as one On a schedule, has no contact values, and a step that needs one is refused.

Whether the contact agreed to messages can be written into a message, a header or a call's body, but a condition can't test it and the Set variable step can't use it. Sending always checks consent for you, whatever a flow read.

A custom field with the same key wins. If your organisation has a contact field keyed phone, {{contact.phone}} reads that field, not the contact's number. The picker says so where it offers the field. Once the draft saves, each step that reads one shows the warning in its settings and on its card; before the first save, the warning shows under the text that reads it. The same goes for id, wa_id and consent_state.

The variable picker

Every Insert a variable list, and every "comes from a variable" choice, lists everything a step can read, in groups:

  • This run, The whole chat and Saved to the contact: the variables you declared, by where they're kept.
  • Set by the trigger and steps: values a trigger or step sets for you, such as {{message_text}} or {{next_open_at}}.
  • The pick: in a flow with buttons or rows built from a list, what the customer picked: {{pick.item}}, its fields, {{pick.index}} and {{pick.id}}.
  • Contact fields: every custom field in your organisation.
  • System values: the values in the table above.

Type to search by name or group. A choice that needs a number only lists numbers.

Lists and objects in text

A List in {{…}} text shows its items separated by commas, like gold, silver. An Object shows as compact JSON. In an HTTP request step's body, a list or object variable is sent as JSON.

Work a value out: the Set variable step

Set variable, under Variables in Add a step, sets up to 10 declared variables at once, without calling anything. Each assignment has three parts:

  1. Set: the declared variable to change.
  2. To: what to set it to.
  3. The inputs for that choice. Each input comes from Text (which may contain {{variables}}), A variable, or A fixed number or true/false.
ToWhat it makes
A valueA copy of text, a number, true or false, or another variable
Values joined togetherText: 2 to 10 parts joined, with an optional Separator such as a space or ,
A number plus / minus / times / divided by a numberA number. Both inputs must be numbers
A value, or a fallback when it is emptyThe value when it has one, and the Fallback otherwise
A date, written outText, in one of eight formats, in a Time zone (your organisation's day zone unless you choose another)
Text in UPPER CASE / lower case / without spaces at the endsText
How many items, or charactersA number: a list's items, or a text's characters
The first item of a listThe list's first item. Empty when the list is empty
One item of a list, by positionThe item at a Position, counting from 0. Empty when the position is outside the list

The date formats are Date (2026-10-23), Long date (23 October 2026), Short date (23 Oct), Time, 24-hour (14:05), Time, 12-hour (2:05 PM), Date and time (2026-10-23 14:05), Day of the week (Friday) and Machine format (2026-10-23T14:05:00+05:30).

Assignments run in order, so a later one can read what an earlier one set. They're all or nothing: if one can't be done, none of the step's values are saved.

The builder checks types as you go. Text can't go into a Number variable, for example, and joined values always make text. An assignment that wouldn't save says why and stays unsaved until you fix it.

Exits: next; refused (optional): a value an input needs is empty (a fallback's value may be empty: that's what it's for); failed (optional): a result of the wrong type, a division by zero, a date that can't be read, or a value too large to keep.

Example: keep an API answer for the whole chat

For the API step itself — the call, the test request and the exits — see Call an API from a flow.

Your billing system answers a plan lookup with:

{"customer": {"plan": "gold", "renews_on": "2026-11-30T00:00:00Z"}, "invoices": [{"due": 120}, {"due": 80}]}
  1. Under Variables, add plan (Text, kept for The whole chat), renews_on (Date and time, This run only), invoices (List, This run only), renewal_text (Text, This run only) and invoice_count (Number, This run only).
  2. In an HTTP request step, copy customer.plan into {{plan}}, customer.renews_on into {{renews_on}}, and invoices[*].due into {{invoices}} (every invoice's amount, as a list).
  3. Add a Set variable step after its success exit with three assignments:
    • Set renewal_text to A date, written out, Date {{renews_on}}, Format Long date.
    • Set invoice_count to How many items, or characters, Value {{invoices}}.
    • Set plan to Text in UPPER CASE, Text {{plan}}.
  4. Send a message: Your {{plan}} plan renews on {{renewal_text}}. You have {{invoice_count}} open invoices. The customer reads "Your GOLD plan renews on 30 November 2026. You have 2 open invoices."

Because plan is kept for the whole chat, a support flow that runs later in the same chat, and declares plan for the whole chat too, can greet the customer by plan without calling your system again.

See what a run set

On a run's or a test run's steps, a step that set variables lists them, such as Set plan (whole chat) or Cleared due (this run). The values themselves aren't shown or kept in the run's history.

In a simulation, you can give the chat's values at the start under Whole-chat values at the start, and the simulation page shows Whole-chat values now: what it started with and what the flow set since.

See a chat's values in the inbox

In the inbox, the chat's side panel has a Flow values section: every value kept for the whole chat, with which flow set it and when, and a Test run badge on one a test run set. Values marked Hide from agents are left out. The section updates by itself when a flow changes a value, and says so when the chat's values have run out.

Still need help?

Write to us at [email protected] and tell us what you were trying to do. Already a customer? Sign in to IconEngage — the same articles are under Help in the app.