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

# Variables

> Store and access data across conversation turns using the conv.state object in functions.

<Info>
  **This page requires Python familiarity.** Variables are set and read in Python functions.
</Info>

Variables are defined by setting a property on the `conv.state` object within a function. You can choose a name for your variable and update its value to anything you want like so:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
conv.state.my_variable = 1
conv.state.my_other_variable = {
    "property": "value"
}
```

These variables will retain their state between turns of the conversation and can be referenced in subsequent tool calls like so:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
if conv.state.my_variable == 10:
    return "Well done you hit 10"
```

### Reading variables that haven't been set

Reading a `conv.state` variable that was never assigned returns Python `None` – it does **not** raise `AttributeError` or `KeyError`. Both attribute and dictionary access are supported and equivalent:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
conv.state.foo            # None if never set
conv.state["foo"]         # None if never set
conv.state.get("foo")     # None if never set (with optional default)
```

This enables a few common patterns:

**Defensive defaults with `or`** – use when any falsy value should be replaced:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
attempts = conv.state.verification_attempts or 0
intent = conv.state.call_intent or "other"
```

Note: `or` cannot distinguish "never set" from a stored falsy value (`0`, `""`, `False`, `None`).

**Explicit unset check with `is None`** – use when the variable is intentionally initialized to `None` in the [start tool](/tools/start-tool) as a marker that no value has been collected yet:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def start_function(conv: Conversation):
    conv.state.booking_time = None   # explicit "not yet collected" marker
    conv.state.customer_id = None

# later, in a flow step
if conv.state.booking_time is None:
    return "What time would you like to book?"
```

**Strict "key was assigned at all" check with `in`** – use when you must distinguish "never assigned" from a stored `None`:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
if "booking_time" in conv.state:
    ...
```

Initializing variables to `None` (or a sensible default like `""` or `0`) in `start_function` is recommended whenever a variable is referenced in a [prompt template](#prompt-templating) or read in a flow step before it is guaranteed to be set, so template references and conditional checks always resolve predictably.

### Built-in state keys

The `conv.state` object comes pre-populated with system-managed keys. These are set automatically by the platform and available in every conversation:

| Key                     | Type        | Description                                                                             |
| ----------------------- | ----------- | --------------------------------------------------------------------------------------- |
| `from_`                 | str         | Caller's phone number (note the trailing underscore – `from` is a Python reserved word) |
| `to`                    | str         | Called number (callee)                                                                  |
| `call_sid`              | str         | Unique call session identifier                                                          |
| `asr_lang_code`         | str         | Active ASR language code (e.g., `"en-US"`)                                              |
| `tts_lang_code`         | str         | Active TTS language code (e.g., `"en-US"`)                                              |
| `shared_id`             | str         | Shared identifier for correlating conversations across systems                          |
| `handoff`               | object      | Handoff configuration object (destination, reason, SIP method)                          |
| `disable_recordings`    | bool        | Whether call recording is disabled                                                      |
| `stop_recording`        | bool        | Whether recording has been stopped mid-call                                             |
| `use_tts_for_responses` | bool        | Whether to use TTS instead of pre-recorded audio                                        |
| `asr_provider`          | str or dict | Override the default ASR provider                                                       |
| `asr_config`            | dict        | Custom ASR configuration                                                                |
| `listen_for_sms`        | bool        | Whether SMS listening is enabled (default `False`)                                      |

<Warning>
  `handoff_reason` and `handoff_number` are deprecated. Use the `handoff` object instead, which supports structured SIP configurations (REFER, INVITE, BYE).
</Warning>

You can read these values in any function:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
log.info(f"Caller: {conv.state.from_}, Callee: {conv.state.to}")
log.info(f"ASR language: {conv.state.asr_lang_code}")
```

### Prompt templating

Variables can be used inside tool calls and injected dynamically into prompts shown to the LLM. To inject a variable's value
into your prompt, use the syntax `$variable_name`. The system will replace this placeholder with the variable's value wherever it matches.

**Example:**

In your start function, you can write:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from datetime import datetime

def start_function(conv: Conversation):
    conv.state.current_date = datetime.now().strftime("%B %d, %Y")
```

**...then in your prompting:**

The current date is `$current_date`.

**...becomes:**

The current date is September 06, 2024.

When using variable templating, ensure the stored value is readable by the LLM. Complex objects like dictionaries or datetime
will be stringified automatically.

### Environment configuration

You can use the `conv.env` property to define environment-specific functions and activate test features in sandbox or
pre-release environments.

For example:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
if conv.env == "sandbox":
    # enable early feedback flow
    pass
elif conv.env == "pre-release":
    # activate staging tools
    pass
elif conv.env == "live":
    # run production features
    pass
```

### Dynamic updates

The value templated into the prompt is always kept up to date, so any updates will be reflected in the next turn sent to the LLM.

**Example:**

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from datetime import datetime

def set_fake_date(conv: Conversation):
    conv.state.current_date = datetime(1995, 3, 22).date().strftime("%B %d, %Y")
```

After running this function, the resulting prompt would display:

The current date is March 22, 1995.

...in the next turn.

### Deleting a variable

To delete a variable, remove it from the state within a function:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
del conv.state['variable_name']
```

## Variables in the Conversations API

All `conv.state` variables – both built-in keys and custom variables your agent writes – are returned in the `state` field of the [Conversations API](/api-reference/conversations/introduction) response. This means you can retrieve any state variable programmatically after a call ends.

For details on the API response structure, see the [Conversations API overview](/api-reference/conversations/introduction#response-structure).

## Related pages

<CardGroup cols={3}>
  <Card title="conv object" icon="code" href="/tools/classes/conv-object">
    Full reference for conv.state and other conversation properties.
  </Card>

  <Card title="Start tool" icon="play" href="/tools/start-tool">
    Initialize state variables before the greeting plays.
  </Card>

  <Card title="Flows" icon="diagram-project" href="/flows/introduction">
    Use variables to pass data across flow steps.
  </Card>
</CardGroup>
