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

# Variables And Identity

> Templating, passing data in from your app, and how a conversation becomes a person in your CRM

Two separate things share one page because they are easy to confuse:

* **Variables** are what this conversation knows.
* **Identity** is who the conversation belongs to.

***

## Variables

### Where They Come From

| Source                  | Example                                                     |
| ----------------------- | ----------------------------------------------------------- |
| An **Ask** card         | The visitor's typed answer, saved in the variable you named |
| A **Set** card          | Values you write yourself, templated                        |
| An **API call** card    | Fields mapped out of the JSON response                      |
| A **Run code** card     | Whatever the `dict` you return contains                     |
| An **AI card function** | Whatever the `dict` it returns contains                     |
| Your app, on the URL    | `&vars={"plan":"Growth"}`                                   |

A variable name must be letters, digits and underscores, and must not start
with a digit.

### Using Them

Any authored text — a message, a button label, an API URL, a header, a body, a
Set value, an AI card's instructions — is templated:

```
Hi {{first_name}}, your order {{order_id}} is {{status}}.
```

| Form               | Reads from                                       |
| ------------------ | ------------------------------------------------ |
| `{{name}}`         | This conversation                                |
| `{{session.name}}` | The same thing, written explicitly               |
| `{{contact.name}}` | The **CRM contact record**, not the conversation |

An unknown name becomes an empty string rather than staying on screen as
`{{...}}` — a visitor seeing template syntax is worse than seeing a gap.

<Warning>
  **Visitor answers are escaped, authored text is not.** If you type `**bold**`
  into a card you mean it. A visitor who answered an Ask card with `**free**` did
  not — so their answer is escaped when it is substituted into your message. This
  is what stops anything a visitor types becoming live markup inside a message
  your account appears to have written.
</Warning>

### Reaching Them From Code

Inside an **AI card function**, variables arrive as `x_vars` and the contact
record as `x_contact` — see [The AI card](/widget/chat/ai-card#what-your-code-can-see).

Inside a **Run code** card they arrive as the `variables` argument:

```python theme={null}
async def run(variables):
    return {"is_returning": "yes" if variables.get("order_id") else "no"}
```

### Conversation vs Contact

A variable lives for one conversation. To keep something for next time, write it
onto the contact with an **Update contact** card — then it is readable as
`{{contact.plan}}` in any future conversation with the same person.

***

## Identity

### Passing It In

Two optional URL parameters, both worth adding if your app knows the answer.

| Parameter | Example                   | What it does                                                                               |
| --------- | ------------------------- | ------------------------------------------------------------------------------------------ |
| `uid`     | `&uid=user_8271`          | Ties the conversation to **the person**. They resume on a new device or after a reinstall. |
| `vars`    | `&vars={"plan":"Growth"}` | Seeds flow variables, so a card can say `{{plan}}` without asking. URL-encode the JSON.    |

```
https://widget.callkaro.ai/chat.html?w=wgt_abc123&uid=user_8271&vars=%7B%22plan%22%3A%22Growth%22%7D
```

Up to 40 variables, 64 characters per name, 500 per value. Strings, numbers and
booleans only.

### How The Contact Key Is Chosen

Every conversation gets a **contact key** — the thing your CRM sorts by. Three
tiers, best first:

<Steps>
  <Step title="A phone number">
    From `vars={"phone":"..."}`, or collected by a `phone` Ask card. This wins
    over everything, because keying on the phone number is what **merges this
    chat with the same person's calls and WhatsApp**.
  </Step>

  <Step title="Your uid, exactly as you sent it">
    Stored verbatim. If the uid is itself phone-shaped it is normalised to
    digits, so `+91 98765 43210` and `9876543210` are one contact — and that
    contact is the same one the person's calls are on.
  </Step>

  <Step title="A browser-minted visitor id">
    Generated by the page and kept in local storage. Only as durable as one
    browser's storage, but it is the difference between an anonymous visitor
    being the same person next week and being a stranger every visit.
  </Step>
</Steps>

If a `phone` Ask card collects a number **mid-conversation**, everything already
said is re-keyed onto that phone number — the transcript is not split in two.

<Warning>
  `uid` is an **unauthenticated claim**. Anyone who can open the widget can put any
  value in the URL, including a phone number that is not theirs — and be handed
  that contact's CRM record, which an AI card can see as `x_contact`.

  It is right for a widget embedded behind your own app's login, which is what it
  is for. It must **not** gate anything the person should not see, and it must not
  be a value that is itself a secret. Signed tokens are not supported yet.
</Warning>

### If You Pass Nothing

The visitor still gets a stable identity of their own, minted in the browser
and kept — so an anonymous visitor is still the same person next week, on that
device. Clearing site data, or a private window, makes them new again.

<Note>
  A visitor id is never exposed to your app and never leaves the browser it was
  made in.
</Note>

***

## Reading It Back

Open [Contacts](https://callkaro.ai/dashboard/contacts) and filter the channel
to **Widget**. Each contact shows the transcript, and the variables the flow
collected alongside it — so an order id is readable without scrolling the
conversation.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Install in your app" icon="code" href="/widget/chat/install">
    Where the URL parameters go
  </Card>

  <Card title="The AI card" icon="sparkles" href="/widget/chat/ai-card">
    `x_vars`, `x_contact`, `x_secrets`
  </Card>
</CardGroup>
