> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voxworks.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Survey Variables and Piping

> Carry values through a survey: the Variables card, the Set variable action, piping earlier answers, variables and contact fields into prompts, the readiness checks on piped tokens, and every custom variable a survey call writes.

## Three kinds of value

A survey can speak three kinds of value inside its prompts, and writes a set of custom variables to every call:

| Token                              | What it is                                                                            | Example                               |
| ---------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------- |
| `{{survey.<question key>.result}}` | The recorded answer to an earlier question.                                           | `{{survey.q3.result}}` → *Labor*      |
| `{{survey.var.<variable key>}}`    | A **survey variable** — a value the interview carries, set by a rule.                 | `{{survey.var.first_pref}}` → *Labor* |
| `{{contact.<field>}}`              | A field from the contact being called: `first_name`, `last_name`, `phone` or `email`. | `{{contact.first_name}}` → *Sam*      |

All of them are spoken as text.

***

## Piping into prompts

In a question's **Voice prompt**, type `/` to open the picker: *"Type / to insert an earlier answer, a variable or a contact field."* It offers the survey's variables, every earlier question's result, and the four contact fields, and inserts the token for you.

For example, a follow-up that refers back to a first preference:

> You said `{{survey.q7.result}}` was your first choice. Which would be your second?

<Tip>Give any question you pipe a lower-case key made of letters, numbers and underscores — for example `q7` or `first_pref` rather than `Q7`. On the call, results are stored under the lower-case form of the key, so a lower-case key keeps the token and the stored answer identical.</Tip>

Tokens work in the **Voice prompt**, in **Alternative phrasings**, and in battery items' longer forms.

### What a piped answer sounds like

`{{survey.<key>.result}}` speaks the recorded answer:

| Question type         | Spoken as                          | Example                        |
| --------------------- | ---------------------------------- | ------------------------------ |
| Single choice, Rating | The chosen option's label          | *Very satisfied*               |
| Number                | The digits                         | *3941*                         |
| Long text             | The respondent's words             | *the parking near the station* |
| First name            | The name                           | *Sam*                          |
| Phone number          | The number in international format | *+61412345678*                 |

A question that was skipped, not reached, or asked later has no answer yet, so the token speaks as nothing — a sentence with a hole in it. Anything that is not one of the three forms above is not substituted at all and is **spoken out loud as the raw token**. [Readiness](/surveys/readiness) checks for both.

### Readiness checks on piped tokens

Each warning names the question and where the token is — its **prompt**, **alternative phrasing (n)** or **item “(key)” longer form (n)** — then one of:

| Warning                                                                                                                                                                        | Fix                                                                                                                                                                            |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| *"pipes `{{…}}`, and “x” is not a variable of this survey — the token speaks as an empty string."*                                                                             | Add the variable on the **Variables** card, or correct the key.                                                                                                                |
| *"pipes `{{…}}`, and no rule anchored on an earlier question sets “x” — the token speaks as an empty string."*                                                                 | Add a **Set variable** rule on a question asked before this one.                                                                                                               |
| *"pipes `{{…}}`, but every rule that sets “x” is anchored on a question that can be skipped — the token speaks as an empty string on a call that never asked it."*             | Set the variable somewhere every respondent passes, or reword the prompt so an empty value still makes sense.                                                                  |
| *"pipes `{{…}}`, which is none of `{{survey.<question>.result}}`, `{{survey.var.<variable>}}` or `{{contact.<field>}}` — nothing substitutes it, so the raw token is spoken."* | Use one of the three supported forms.                                                                                                                                          |
| *"pipes `{{…}}`, and “x” is not a question of this survey — the token speaks as an empty string."*                                                                             | Correct the question key.                                                                                                                                                      |
| *"pipes `{{…}}`, which is this question itself — the token speaks as an empty string."* / *"…which is asked later — …"*                                                        | Pipe only questions asked before this one.                                                                                                                                     |
| *"pipes `{{…}}`, but “x” can be skipped — the token speaks as an empty string on a call that never asked it."*                                                                 | The piped question is hidden or jumped over for some respondents. Reword the prompt so it still makes sense with an empty value, or pipe a question every respondent is asked. |

A contact field that is empty on the contact record also speaks as nothing, so write prompts that still read naturally without it.

***

## Survey variables

A survey variable holds a value that is not simply one question's answer — a first preference carried into several later prompts, a region derived from a postcode, or a flag set by a screener.

### The Variables card

On the [Logic tab](/surveys/logic), with nothing selected, the **Variables** card reads: *"A value the interview carries rather than one question — set it from a rule with “Set variable”, and speak it in a later prompt with `{{survey.var.<key>}}`."*

Click **Add variable**:

| Field         | Rules                                                                                                                                                                    |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Key           | *"Variable keys start with a letter and use letters, numbers or underscores."* Up to 64 characters. Must be unique: *"This survey already has a variable called (key)."* |
| Label         | *What it holds, in plain words.*                                                                                                                                         |
| **Data type** | text, boolean, integer, number, date, time, datetime, choice or json. Default text.                                                                                      |

Every survey variable is stored and spoken as text on a call, whatever its **Data type** — the data type describes the value for your own records. The confirmations are *Variable added*, *Variable updated* and *Variable deleted*. A variable no rule writes is tagged *no rule sets it*.

### Setting a variable

Use a [routing rule](/surveys/routing-rules) with the **Set variable** action. It writes either:

* **The answer to this question** — the anchor question's recorded answer, or
* **A fixed piece of text** — whatever you type (*The text this rule stores in the variable*).

Every variable starts each call empty. If several rules set the same variable, the one that runs last wins. A rule with a condition writes its value when the condition holds and **clears the variable** when it does not, so two conditional rules on the same variable do not combine — the later one decides the value on every call. Give each conditional value its own variable. A variable that a rule still sets cannot be deleted: *"(rules) still sets this variable. Change or delete that rule first."*

**Example — carrying a first preference.** A rule on `q7` (first preference), trigger **When an answer is submitted**, no condition → **Set variable** `first_pref` to *The answer to this question*.

A later prompt can then say *"Apart from `{{survey.var.first_pref}}`, which would you choose?"*.

***

## Custom variables a survey call writes

Every survey call writes its results to the call's custom variables under `survey.*`. All values are text unless noted.

### Per question

`<key>` is the question key in lower case, with anything other than letters and numbers turned into underscores — a question keyed `Q3` writes `survey.q3.result`.

| Variable                             | Use                                                                                                                                                                                                                                                                          | Type                           | Example                                                                   |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------- |
| `survey.<key>.result`                | The recorded answer: the option label, digits, the respondent's words, a name or a phone number. Empty if none. For a battery, a JSON map of item key to rating, where `NA` means the item was excluded and never asked and an empty value means it was asked but not rated. | Text (JSON text for a battery) | `Very satisfied`; `3941`; `{"your_own_life":"Positive","education":"NA"}` |
| `survey.<key>.status`                | How the question ended: `captured`, `skipped`, `invalid` or `abandoned` (busy or stop during the question). Empty if never reached.                                                                                                                                          | Text                           | `captured`                                                                |
| `survey.<key>.termination_requested` | Whether this answer ended the interview.                                                                                                                                                                                                                                     | Text, `true` or `false`        | `false`                                                                   |
| `survey.<key>.screened`              | Number questions only: the answer was recorded but failed the question's **Screen out** list.                                                                                                                                                                                | Text, `true` or `false`        | `true`                                                                    |
| `survey.<key>.object`                | The full question record — the answer plus details such as whether it was confirmed or spelled.                                                                                                                                                                              | JSON                           | `{…}`                                                                     |

### Per call

| Variable                                                | Use                                                            | Type                    | Example                    |
| ------------------------------------------------------- | -------------------------------------------------------------- | ----------------------- | -------------------------- |
| `survey.temp.outcome`                                   | The outcome code the call ended with. Starts as `in_progress`. | Text                    | `completed`                |
| `survey.temp.termination_reason`                        | A readable reason when the call ended early.                   | Text                    | `Declined at the greeting` |
| `survey.var.<key>`                                      | Each survey variable's final value.                            | Text                    | `NSW`                      |
| `survey.temp.call.is_mobile`, `.is_inbound`, `.is_test` | The call facts rules can read.                                 | Text, `true` or `false` | `true`                     |

### Gatekeeper variables

Written by the [Gatekeeper](/surveys/gatekeeper) on every call:

| Variable                          | Use                                                                                                                                                                                                               | Type | Example              |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -------------------- |
| `survey.gatekeeper.result`        | What happened at the front door: `agree`, `decline`, `not_now`, `wrong_person`, `voicemail`, `screener_no_connect` or `no_response`.                                                                              | Text | `agree`              |
| `survey.gatekeeper.status`        | The detailed disposition, for example `connected`, `declined`, `callback`, `wrong_person`, or a voicemail status such as `voicemail_sms` (see [Voicemail and SMS](/surveys/voicemail#how-voicemail-is-recorded)). | Text | `voicemail_sms`      |
| `survey.gatekeeper.reason`        | The disposition class.                                                                                                                                                                                            | Text | `callback`           |
| `survey.gatekeeper.answerer`      | Who answered: `unknown`, `target`, `screener` or `machine`.                                                                                                                                                       | Text | `target`             |
| `survey.gatekeeper.answerer_name` | A name the person who answered gave for themselves.                                                                                                                                                               | Text | `Sam`                |
| `survey.gatekeeper.entry_class`   | How the pickup sounded: `live`, `named`, `unclear`, `screener`, `machine` or `silent`. Empty on inbound calls.                                                                                                    | Text | `live`               |
| `survey.gatekeeper.callback_time` | A callback time in the respondent's own words.                                                                                                                                                                    | Text | `after six tomorrow` |
| `survey.gatekeeper.callback_slot` | The same time trimmed to a day and time of day.                                                                                                                                                                   | Text | `tomorrow morning`   |

The gatekeeper's own result is not shown in Results or in the CSV export; calls that end at the gatekeeper appear in the **Contact funnel** (see [Results](/surveys/results)).

### Contact fields

| Variable             | Use                                                                                                          | Type | Example        |
| -------------------- | ------------------------------------------------------------------------------------------------------------ | ---- | -------------- |
| `contact.first_name` | Written by a [First name](/surveys/question-types/first-name) question when it captures a name.              | Text | `Sam`          |
| `contact.phone`      | Written by a [Phone number](/surveys/question-types/phone-number) question, in international (E.164) format. | Text | `+61412345678` |

These are written to the call. To update the contact record in [Contacts](/contacts/overview), use the recorded answers from Results or the export.
