Graine AI

Send your user's details to the agent

Map your app's fields — a name, an age, a plan — to the placeholders in the agent's prompt, and send them from iOS, Android, Flutter, React Native, Kotlin Multiplatform or a website: at sign-in, for one call, or fixed at launch. Which value wins, the limits, what never to send, and how to check what the agent received. The same prompt variables a server sends on an API call.

An agent's prompt can name details about the person it is talking to — {name_user}, {age}, {plan} — and your app fills them in. Each value travels under the placeholder's own name: the agent reads {age} from the value your app sent as age. These are prompt variables, the same thing a server sends as variables when it places a call through the API (side by side below).

Placeholders and the names your app sends

Whoever writes the agent's prompt chooses the names: {callee_name}, {name_user} and {first_name} all work. The placeholders can sit in the prompt, the welcome message and a flow agent's steps. On the agent's page, Agent Configuration shows each one, in braces, where it is used. Here the author chose {callee_name}, {age}, {plan} and {care_team} for the prompt, and {callee_name} again in the Greeting Message:

Agent Configuration on the agent's page: the prompt's line Who you are talking to, with the placeholders callee_name, age, plan and care_team, each in braces; and the Greeting Message, which opens Hi callee_name, I'm Asha, your care coach, with callee_name in braces

  • Letters, digits and underscores, starting with a letter: name_user, age, plan_name. A placeholder with a hyphen, a space or a dot in it is not filled from your app's values.
  • Matched exactly, upper and lower case included: a value sent as name_user fills {name_user}, never {Name_User} or {nameUser}.
  • A few names are Graine's. On a call Graine fills who_called and call_reason (which value wins), and names starting with graine_ are reserved. Pick any other name for your own details.
  • Nothing is renamed for you. The SDK sends each key exactly as your code wrote it, so your code is where your app's fields meet the agent's names:
In your appThe agent's placeholderWhat your app sends
The user's first name{name_user}name_user: "Asha"
Their date of birth{age}age: 34 — worked out in your app; the prompt asks for an age, not a date
Their subscription tier{plan}plan: "Gold"
The order the user is calling about{order_id}order_id: "A-1042", with that call only

In the examples below, user.ageInYears stands for your own code that works the age out from the date of birth.

A placeholder nothing fills is left empty, so write sentences that read well without the value:

The user's first name, if known: {name_user}. Their age, if known: {age}.
Their plan: {plan}. Use their first name once, in your first reply.

A welcome message of Hi {name_user}, welcome back! greets someone who is not signed in with "Hi , welcome back!".

In the demo app

The demo app, set up as a care coach, shows the signed-in patient on its Profile. At sign-in its code sends the name as callee_name and the age as age with setVariables, and calls identify with the Patient ID — the identifier — and the name, age, plan and care team as traits:

The demo app's Profile on an Android phone, signed in as Arjun Mehta: Patient ID MRN-000982, age 52, care team Dr. Sameer Joshi, plan Heart health; below, the switch that lets the agent remember conversations, and Call activity

When Arjun starts a conversation, the agent greets him by name.

The demo's Profile also lists Variables Asha receives: exactly what the SDK will send with the next chat, voice conversation or call, read back with currentVariables(). Its form adds any variable by name and value with setVariables, the way an API call carries variables. Here, signed in as Riya, {favourite_food} was added from the form, and the next call carried it:

The demo app's Profile, section Variables Asha receives: age 34, callee_name Riya Sharma, care_team Dr. Kavya Rao, favourite_food Paneer tikka with a Remove button, name Riya Sharma and plan Diabetes care; below, a form with Name and Value fields and an Add variable button

What it needs in the dashboard

WhereSettingValue
Agent → Custom VariablesThe placeholders the agent readsname_user, age, plan — the names your app will send
Agent → the prompt and the Greeting Message (a flow agent: its Welcome message and steps)Where each value goes{name_user}, {age} in the sentences that use them
Agent → Memory → SettingsWho is the user?The trait that identifies the user, user_id by default. It is never a prompt variable: a placeholder of that name stays empty

What to do, in order

  1. At launch, set what is the same for every user in the config's variables: your app's name, a region. These are your own constants and are sent without masking.
  2. After sign-in, send the user's details with setVariables, under the agent's names — beside identify, which tells Graine who the user is. Do both again at every launch once your sign-in is restored: the SDK keeps these values in memory, not on the device.
  3. When a detail changes — a new plan — call setVariables with that key alone. Values are merged: the other keys stay, and null under a key removes it.
  4. For one call, pass its own variables to startCall. They apply to that call only and win over everything your app set. If you get the call ready with prepareCall when the screen appears, pass it the same reason and variables: a prepared call is used only when both match.
  5. On sign-out, clear them: setVariables(null) removes every value your app set while it ran, and identify(null) signs the user out and drops their traits. The next conversation knows nothing about them.

Variables are read when a chat, a voice session or a call starts. A value set during one reaches the next.

The code, platform by platform

Each example maps the user's first name to {name_user}, their age to {age} and their plan to {plan}, adds one variable for a single call, and clears everything on sign-out.

import GraineInApp
 
// At launch: the same for every user
GraineInApp.configure(GraineConfig(
    baseUrl: "https://www.graine.ai",
    publishableKey: "pk_live_…",
    variables: ["app_name": "Acme Health"]
))
 
// After sign-in, and at every launch once the sign-in is restored
func userSignedIn(_ user: User) {
    let graine = GraineInApp.shared
    graine.identify(["user_id": user.id])             // who the user is; never a prompt variable
    graine.setVariables([
        "name_user": user.firstName,                   // fills {name_user}
        "age": user.ageInYears,                        // fills {age}; 34 arrives as "34"
        "plan": user.plan,                             // fills {plan}
    ])
}
 
// A detail changed: only this key changes
GraineInApp.shared.setVariables(["plan": "Gold"])
 
// One call's own variable
GraineInApp.shared.calls.prepareCall(reason: "billing", variables: ["order_id": order.id])   // optional, when the screen appears
GraineInApp.shared.calls.startCall(reason: "billing", variables: ["order_id": order.id])     // on the tap
 
// On sign-out
func userSignedOut() {
    GraineInApp.shared.setVariables(nil)               // every value set while the app ran
    GraineInApp.shared.identify(nil)                   // the user and their traits
}
 
// What the next conversation will carry, masked as it leaves the device
print(GraineInApp.shared.currentVariables())          // ["app_name": "Acme Health", "name_user": "Asha", "age": "34", "plan": "Gold"]

setVariables(_:) takes [String: Any?]?; startCall(reason:variables:agent:) and prepareCall(reason:variables:agent:) take [String: Any]. In an app with several agents, setVariables is the agent's own: call it on GraineInApp.named("support") too if that agent's prompt reads the same names.

Which value wins

When two sources send the same name, the later one in this list wins:

  1. Default values the dashboard holds for the agent.
  2. The config's variables — the provider's on React Native, load()'s on a website.
  3. setVariables.
  4. The traits from identify, all but the identifier.
  5. On a call: the call's own variables.
  6. On a call: call_reason, which is your reason when you pass one.
  7. On a call: who_called, set by Graine. Nothing replaces it.

Send each detail through one of them: a trait beats a setVariables value of the same name.

What identify adds

identify tells Graine who the user is, and its traits reach the agent too:

  • Every trait but the identifier becomes a prompt variable, masked on the device: identify with user_id and name_user fills {name_user}.
  • The identifier — the trait the agent's Who is the user? setting names, user_id by default — is never a prompt variable. It tells Graine who the user is (for memory, their devices and the calls Graine rings), and Call History shows it. A {user_id} placeholder stays empty when user_id is the identifier.
  • A new identify replaces the traits; setVariables merges into what is set.
  • One user for the whole app. identify on any agent reaches every agent; setVariables and the config's variables are each agent's own. A website shows one agent at a time: its setVariables values are the page's and carry over to the next agent, while load()'s variables are each agent's.

So: identify for who the user is, and for details every agent may use; setVariables for the names one agent's prompt reads.

Limits

Design for these — they hold for a chat, the voice bar on Standard audio and every call:

  • 12 variables at most, from every source together. On a call, who_called and call_reason are two of the 12.
  • Names up to 40 characters, values up to 200. Longer ones are cut.
  • About 1 KB in all, counted in bytes: a letter in Devanagari takes three. Over that, the SDKs leave out the biggest values first until the rest fit — on a call, who_called and call_reason last. From a website, none of them reach the agent in that conversation.
  • Values are text. A number or true/false arrives as text (34, true). An object or a list is dropped; React Native and the website send a trait's as JSON text.

The voice bar over WebRTC takes more. Every channel's limits, and what happens to a set that is too big: Variables.

What never to send

  • Secrets: passwords, access tokens, API keys, session ids. A variable is text in the agent's prompt — the agent can repeat it — and your team sees it in Call History.
  • The identifier, anywhere but identify. Sent with setVariables or in the config, it reaches the prompt like any other value.
  • Personal numbers the agent does not need. What your app sends while it runs — setVariables, traits and a call's variables — is masked on the device: an email address, a card number, a PAN or Aadhaar number or an Indian mobile number reaches the agent as [EMAIL], [CARD], [PAN], [AADHAAR] or [PHONE]. Your own formats can be added: Masking your own formats. The config's variables are your own constants and are not masked.
  • Long text — a history, a document. It is cut at 200 characters, and it is the first value left out when the set is too big.
  • Names starting with graine_. They are Graine's own; your app's are dropped before the conversation starts.

Check what the agent received

  • Before a conversation: currentVariables() — on React Native, client.getVariables() — returns the merged set the next conversation will carry, masked as it leaves the device. A call adds its own variables, call_reason and who_called on top.
  • After it: open the conversation in Call History. Contact & Campaign Data lists the variables it carried, by name, with underscores shown as spaces (name user, age).
  • The prompt it ran on: Execution Logs → Instructions shows the agent's prompt with its placeholders. Check each one's spelling against the names your app sends.

Arjun's call from the demo app, in Call History. His Patient ID names the conversation at the top; it is the identifier, so it is not among the variables. Contact & Campaign Data holds what the app sent — callee_name, age, plan, care_team and name — then the call's own entry_point, call_reason (the reason the app passed) and who_called, which Graine sets:

Call History, the panel of one call: Patient ID · MRN-000982 — Arjun Mehta at the top; Contact & Campaign Data with callee name Arjun Mehta, age 52, plan Heart health, care team Dr. Sameer Joshi, name Arjun Mehta, entry point home, call reason patient_question and who called customer; below, Technical Details and Execution logs

The same as the API

A server that places a phone call puts the user's details in variables; an app sends the same names through its SDK. The agent and its prompt do not change: {name_user} is filled from name_user whichever sent it, and a value nobody sent is left empty either way.

# A server: POST /v2/calls
curl -X POST "https://api.graine.ai/v2/calls" \
  -H "Authorization: Bearer $GRAINE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "6c6f4cc3-f56c-479d-8422-7f76694daa29",
    "to_number": "+14155550123",
    "variables": { "name_user": "Asha", "age": "34", "order_id": "A-1042" }
  }'
// An app: the user's details once, and the call's own when it starts
// (Kotlin Multiplatform; every SDK works the same way)
Graine.setVariables(mapOf("name_user" to "Asha", "age" to 34))
Graine.calls.startCall(reason = "billing", variables = mapOf("order_id" to "A-1042"))
A server, through the APIAn app, through the SDK
The user's detailsvariables, on every requestsetVariables and the traits from identify, once — every conversation after carries them
One call's ownvariables, on that requeststartCall's variables
ValuesStringsText, numbers or true/false, all sent as text

The API's side: Place a call · Quickstart → Place the call.

Troubleshooting

What you seeWhyFix
The agent says "Hi ," or skips a detailNo value reached it under that exact nameCompare the placeholder with your key, case included; check currentVariables() before the conversation starts
A value set during a conversation is not usedVariables are read when a conversation startsIt reaches the next chat, voice session or call
The previous user's details after a sign-outThey were not clearedsetVariables(null) and identify(null) on sign-out
The details are gone after the app restartsThe SDK keeps them in memorySet them again at launch, where you restore the sign-in
{user_id} stays emptyuser_id is the identifier, which never reaches the promptUse another trait, such as name_user
The agent reads [PHONE] or [EMAIL]The value looked like a phone number or an email address, and was masked on the deviceSend only what the agent needs
Only some variables arriveMore than 12, or over about 1 KB in allFewer, shorter values; on a website, over 1 KB none arrive
A call does not have your app's variables (React Native, Flutter)Calls are not attachedGraineCalls.attach(client) on React Native, GraineCalls.instance.attach() on Flutter, once
Another agent does not have themsetVariables is each agent's ownSet them on every agent whose prompt reads them

Every channel, its limits and the reserved names: Variables · who the user is: Identify the user · calls: the user calls the agent, Graine rings.

On this page