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

# Dynamic Prompts

> Use Liquid templating to add variables, logic, and A/B variation to your agent prompts

Beyond simple `{{parameter}}` substitution, agent prompts support [Liquid](https://liquidjs.com) templating. Liquid lets you go past dropping a value into a sentence: you can branch on conditions, loop over lists, transform values with filters, and even run randomized A/B tests across calls, all from inside the prompt editor, with no code.

If you only need to insert a value (a customer name, an order ID), stick with the plain `{{parameter}}` syntax described in [Prompting](/prompting). Reach for the Liquid features below when the prompt needs to *decide* something.

## How it works

Your prompt is re-rendered on **every turn** of the conversation, not once at the start. To keep a branch stable across the call, seed it from a value that's constant for the whole call. `call.started_at` is fixed for the call's lifetime, so anything derived from it resolves the same way on every turn.

(`now` is derived from `call.started_at`, so it is also constant for the call rather than advancing with wall-clock time.) Times are evaluated in **UTC**.

## Available variables

You can reference the following inside your prompt.

### Call parameters

Any value you pass when creating a call, via the [API](/calls) or a [campaign](/campaigns) CSV, is available at the top level by its name:

```liquid theme={null}
You are calling {{customer_name}} about order {{order_id}}.
Their email on file is {{customer_email}}.
```

### The `call` object

Metadata about the current call is always available under `call`:

| Variable           | Description                     | Example                    |
| ------------------ | ------------------------------- | -------------------------- |
| `call.call_id`     | Unique ID for this call         | `8f3c…`                    |
| `call.from_number` | The number the call is from     | `+15551234567`             |
| `call.to_number`   | The number the call is to       | `+15559876543`             |
| `call.direction`   | `inbound` or `outbound`         | `outbound`                 |
| `call.started_at`  | Call start time, ISO 8601 (UTC) | `2026-01-16T10:30:00.000Z` |

```liquid theme={null}
{% if call.direction == "inbound" %}
The customer called you. Greet them and ask how you can help.
{% else %}
You are calling the customer. Introduce yourself first.
{% endif %}
```

### `now`

`now` is the call start time pre-formatted as a human-readable string, ready to speak:

```liquid theme={null}
For reference, the current date and time is {{now}}.
```

```text theme={null}
For reference, the current date and time is Friday, January 16th, 2026 10:30:00 AM UTC.
```

<Note>
  Use `now` when you want to **tell the agent the date/time**. Use `call.started_at` when you want a **raw value to compute with**, such as math, comparisons, or seeding (see A/B testing below). `now` is already formatted into prose, so filters like `date` won't work on it.
</Note>

## Liquid basics

### Variables: `assign`

Compute a value once and reuse it throughout the prompt:

```liquid theme={null}
{% assign company = "Downtown Medical" %}
Thanks for calling {{company}}. This is {{agent_name}} from {{company}}.
```

Filters can only be used inside `{% assign %}` and `{{ output }}`, **not** inside an `{% if %}` or `{% case %}` condition. If you need to test a transformed value, assign it first, then compare the variable:

```liquid theme={null}
{% assign branch = call.started_at | date: "%s" | modulo: 2 %}
{% if branch == 0 %}…{% else %}…{% endif %}
```

### Conditionals: `if` / `elsif` / `else`

```liquid theme={null}
{% if account_tier == "premium" %}
Offer to connect them to a priority specialist.
{% elsif account_tier == "standard" %}
Help them directly with their request.
{% else %}
Ask which account they are calling about.
{% endif %}
```

### Multiple branches: `case` / `when`

Cleaner than a long `if`/`elsif` chain when you are switching on one value:

```liquid theme={null}
{% case region %}
{% when "US" %}Quote prices in US dollars.
{% when "UK" %}Quote prices in British pounds.
{% else %}Ask the customer which currency they prefer.
{% endcase %}
```

### Filters

Filters transform values with a `|`. A few useful ones:

```liquid theme={null}
{{customer_name | capitalize}}              → Jane
{{order_id | upcase}}                        → 7BB0A946
{{call.started_at | date: "%A"}}             → Friday
{{price | times: 1.08}}                       → apply 8% tax
```

All [standard Liquid filters](https://liquidjs.com/filters/overview.html) are available (`upcase`, `downcase`, `capitalize`, `date`, `plus`, `minus`, `times`, `modulo`, `append`, `default`, and more).

## A/B testing prompts across calls

A powerful use of Liquid is running **randomized variations** of a prompt without any code or statefulness. The pattern: derive a stable number from the call start time, then branch on it.

```liquid theme={null}
{% assign seed = call.started_at | date: "%s" %}
{% assign variant = seed | modulo: 3 %}

{% case variant %}
{% when 0 %}Open the call warmly: "Hi there! Thanks so much for calling."
{% when 1 %}Open the call briefly: "Hi, how can I help today?"
{% when 2 %}Open the call formally: "Good day. How may I assist you?"
{% endcase %}
```

How it works:

1. `call.started_at | date: "%s"` converts the call start time to a Unix timestamp (seconds): an ever-changing integer.
2. `| modulo: 3` reduces it to `0`, `1`, or `2`, spreading calls roughly evenly across three variants.
3. `case`/`when` selects the matching variant.

Because `call.started_at` is fixed for the life of the call, every part of the prompt that references `variant` resolves to the **same branch**: the agent stays consistent within a single call, while different calls land on different variants.

<Tip>
  **Always seed from `call.started_at`, not `now`.** `now` is a formatted prose string and won't run through the `date` filter. `call.started_at` is the raw timestamp the math needs.
</Tip>

### Scaling to many variants

The same pattern extends to as many branches as you like: just raise the modulo. This is how teams test 10–30 script variations (different openers, tones, or full personas) from a single agent:

```liquid theme={null}
{% assign branch = call.started_at | date: "%s" | modulo: 20 %}

# Active Persona

{% case branch %}
{% when 0 %}You are warm and cheerful. Use light filler words.
{% when 1 %}You are polite and reserved. Keep responses brief.
{% when 2 %}You are tired but helpful, at the end of a long shift.
{% comment %} …branches 3 through 19… {% endcomment %}
{% endcase %}
```

You can reuse the same `branch` variable in multiple `case` blocks throughout the prompt (opener, acknowledgments, sign-off), so a single call presents one coherent persona end to end.

## Best practices

* **Keep logic shallow.** A couple of branches makes a prompt adaptive; deeply nested conditionals make it hard to read and test. If a prompt needs many distinct flows, consider [flow-based agents](/agents) with a node per scenario instead.
* **Provide a fallback.** Always include an `{% else %}` (or a `{% when %}` default) so an unexpected value never leaves a blank section in the prompt.
* **Guard against missing values** with the `default` filter: `{{customer_name | default: "there"}}`.
* **Test each variant.** With A/B branches, place several test calls and confirm each branch reads correctly: a typo in one `when` only shows up when that branch is selected.
* **Watch for silent passthrough.** If your Liquid has a syntax error, the prompt is used **as written**: the raw `{% … %}` tags will appear in the agent's instructions instead of being evaluated. If you see template tags leaking into agent behavior, check your syntax.
* **Review the rendered prompt.** The surest way to verify your logic is to make a real call and inspect what the agent actually received.

## Where Liquid works

Liquid is evaluated in your agent's prompt: both the main instructions and the per-node prompts of [flow-based agents](/agents), so each node can branch on the same call data.
