Variables
What your app can tell the agent — traits from identify, variables set at start-up or while the app runs, a call's reason — how each reaches the prompt's placeholders, what the agent sees in a chat, in the voice bar, on a call either way and on a call Graine rang, the limits on each path, the reserved keys, and what happens when a set is too big.
The agent's prompt reads placeholders — {name}, {plan}, {call_reason} —
and your app fills them. A variable is a name and a short text value; the prompt
uses it wherever it names it, in every channel the user meets the agent on.
What your app can send
| Source | How | When it applies | Masked on the device |
|---|---|---|---|
| Traits | identify(traits) — every trait except the identifier | The next conversation | Yes |
| Variables at start-up | GraineConfig(variables:), the provider's variables, GraineAgent.load({ variables }) | Every conversation | No — your own constants |
| Variables while the app runs | setVariables(values) (not on the website); null under a key removes it | The next conversation | Yes |
| A call's own | startCall(reason:, variables:) | That call | Yes |
| Set by Graine on calls | who_called, call_reason | That call | — |
The identifier — the trait your Who is the user? setting names, user_id by
default — is never a variable: it identifies the user and nothing else.
Masking replaces PAN, Aadhaar, card and account numbers, phone numbers and emails
with a token ([PHONE], [EMAIL] …) before anything leaves the device; your own
formats can be added (addMaskRule).
Merged in this order, the later winning on a shared name: any default values
the dashboard holds for the agent, the variables at start-up, setVariables, the
traits — and, on a call, the call's own variables, call_reason, then
who_called.
How a variable reaches the prompt
- The prompt names it.
{plan}in the prompt (or the welcome message) reads the value sent underplan. List the agent's variables under its Custom Variables too: the Install tab's website snippet is written from that list, and your team sees what the prompt expects. - A variable nothing sets renders empty. Write sentences that read well
without it:
Hi {name}, welcome backreads "Hi , welcome back" for an anonymous user;Greet the user by name if you know it: {name}does not break. - Values are text. Numbers and booleans become their text (
2,true); nested objects are dropped on iOS, Android, Flutter and Kotlin Multiplatform, and sent as JSON text by React Native. - Reserved names render empty. A
{graine_…}placeholder never shows a value.
What the agent sees, channel by channel
| Channel | What carries the variables | Limits | Also set |
|---|---|---|---|
| Chat (every SDK and the website) | The signed ticket that opens the conversation | 12 variables; names cut to 40 characters, values to 200; over about 1 KB in all, the SDKs leave off the biggest first, one at a time, until the rest fit (0.9.0) — from a website, over 1 KB none travel | — |
| The voice bar, Standard call audio | The signed ticket | The same | — |
| The voice bar and the website's voice, WebRTC call audio (High quality) | The call itself | 40 variables; names cut to 64 characters, values to 300; then, when everything the call carries is over its budget (about 1.6 KB), the biggest values are dropped first until it fits | — |
| A call the user places (the call engine) | The signed ticket | who_called and call_reason first, then the call's own variables, then yours: 12 in all, 200 characters each; past about 1 KB the biggest are left off first, who_called and call_reason last | who_called = customer; call_reason = your reason |
| A call Graine rang (booked by the agent, the user or your team) | The signed ticket; the booking's reason added by Graine when the call connects | As above | who_called = scheduled; call_reason = the booking's reason |
| A call your own server rang | As above, with the push's variables | As above | who_called = agent; call_reason = the push's reason |
| Any of these three calls over WebRTC (0.9.0, with the SDK's WebRTC module) | The call itself: the same set the signed ticket would carry | As above — the SDK trims the set the same way before it leaves the phone | As for its direction |
The iOS, Android, Flutter and Kotlin Multiplatform SDKs (from 0.8.0) and React Native (from 0.43.0) send the variables of a chat and of a call only in the signed ticket; the address of a connection opened with a ticket does not repeat them. The website's voice still repeats them on that address too; the agent reads the ticket's, so what it sees is the same. A connection opened without a ticket — rare: only when one cannot be issued — carries them on its address instead.
A ring itself carries no reason and no variables: only the call's id, the call name and the agent. The reason stays with Graine until the user answers.
Keep the set small: a name, a plan, an order number — 12 at most, a few hundred characters in all. Long text (a history, a document) does not belong in variables: over 1 KB on the ticket, the SDKs leave off your biggest values first — so the long one is the first to go — and from a website none of them reach the agent in that chat.
Reserved keys
Every key starting with graine_ is Graine's own, written only by Graine's servers:
| Key | What it is |
|---|---|
graine_user_key | The one-way key memory and devices use for the user |
graine_install_ref | The install, as a one-way key |
graine_memory | Whether this user's conversations are remembered |
graine_devices | How many devices the user may use |
graine_tz | The device's time zone |
graine_call_id | The call a ring or a placed call belongs to |
graine_user_id, graine_user_field | The identifier and its field, for Call History |
Your app can never set them: a graine_… key in setVariables, in identify's
traits, in a call's variables or in load({ variables }) is dropped before the
conversation starts — on every path — so no app can claim to be a user it is not.
None of them is ever a prompt variable.
What you'll see if…
| You send | What happens | What to do |
|---|---|---|
| More than 12 variables (chat, Standard voice) | The rest do not travel; which 12 depends on the platform's order | Keep the set to 12, traits included |
| More than 12 on a call | who_called, call_reason and the call's own travel; yours fill what is left | Pass the call's essentials in startCall(variables:) |
| A value over 200 characters (300 on the voice bar's WebRTC call) | Cut at the limit | Shorten it |
| A name over 40 characters (64 on the voice bar's WebRTC call) | Cut at the limit | Shorter names |
| Over 1 KB in all, in a chat or a call | The SDKs leave off the biggest values first, one at a time, until the rest fit — who_called and call_reason last (0.9.0; before, none travelled). From a website, no variables at all in that conversation | Fewer, shorter values |
| Over the budget on the voice bar's WebRTC call | The biggest values dropped first, until it fits | Fewer, shorter values |
A graine_… key | Dropped; the agent never sees it | Use another name |
| An object or a list | Dropped (React Native: sent as JSON text) | Send text |
| A placeholder the prompt names but nothing sets | It renders empty | Write the prompt to read well without it |
Examples
The prompt side
How a prompt might use them — in the agent's prompt, in the dashboard:
Where the user's details come from: Identify the user · calls in both directions: the user calls, Graine rings.

