Context
Two separate props carry information about the current user to Qafka — context and endUserData — and they behave very differently. Picking the wrong one either leaks data to the AI that shouldn’t reach it, or withholds data the AI needs to answer well.
context — what the AI sees
context is a free-form key/value object that travels with every message. Every key in it is visible to the AI — it’s flattened into the system prompt as key: value lines, and it’s also available to tool parameters with source: 'context'.
<Qafka
projectId="proj_abc123"
endUserId={currentUser?.id ?? 'anonymous'}
context={{
firstName: 'Ada',
selectedStoreId: '123',
activeSession: { active: false },
userRole: 'premium',
}}
contextDescription="User is on the settings screen"
/>Use it for runtime facts the assistant may use to personalize answers: the signed-in user’s first name, their selected store or branch, account state, an active promotion’s progress — whatever the AI should know about this user right now.
With context, the AI can:
- Answer relative questions accurately — “What’s in my cart?”, “Why was I charged?” — need the AI to know cart state, current screen, viewed item, etc.
- Match the right tool — tools can require context keys to be eligible (e.g. a “Cancel reservation” tool only fires if
reservationIdis in context). - Personalize tone & depth —
userRole: 'premium'shapes responses without you writing branching logic.
contextDescription
One human-readable sentence describing the screen the user is currently on. It’s kept separate from context because it describes the user’s location, not a fact about them — the prompt places it above the context lines.
contextDescription="User is viewing a product detail page"Send an explicit empty value, not a missing key
When a value has no meaningful state, send an explicit “empty” shape rather than omitting the key entirely. An absent key gives the AI nothing to reason about, so it answers “I don’t know” instead of “you have no active session” — e.g. send activeSession: { active: false } rather than leaving activeSession out.
endUserData — what the AI never sees
endUserData is structured profile data for operator dashboards and tool action templates — reachable via {{endUser.data.<key>}} in the dashboard, and never forwarded to the LLM prompt unless a tool’s Description references it with {{endUser.*}}. Identity data the AI should not see belongs here, not in context.
<Qafka
projectId="proj_abc123"
endUserId={currentUser.id}
endUserData={{ email: currentUser.email, plan: currentUser.plan }}
/>endUserId itself follows the same rule: it groups conversations, action logs, and analytics per user, but is never forwarded to the LLM prompt unless a tool’s Description references it with {{endUser.*}} — dashboards and tool action templates reach it via {{endUser.id}}.
endUserData is limited to 8KB serialized; exceeding the limit drops the field from the request (with a console.error) — chat and tracking keep working, just without that data reaching {{endUser.data.*}}.
Deciding where something goes
| Question | Answer | Goes in |
|---|---|---|
| Should the AI read this when composing a reply? | Yes | context |
| Is it identity/PII that dashboards or tool actions need, but the AI should never see? | Yes | endUserData |
| Is it a secret (password, token, API key, full card number)? | Never send it in either | — |
Privacy & Storage
context is stored with the conversation in the Qafka backend. That means:
- Anything you put in
contextis stored as long as the conversation is stored and is visible in the dashboard’s conversation viewer. - It can be retrieved later for analytics, debugging, and conversation replay.
Don’t put in context:
- Passwords, session tokens, OAuth tokens, API keys
- Full credit card numbers, CVVs, bank account numbers
- National ID numbers, passport numbers, SSNs
- Plain-text personal data you wouldn’t want in your analytics database (full home address, medical conditions, etc.)
- Any data your privacy policy or compliance regime doesn’t permit you to log
Put identity data the AI doesn’t need to see in endUserData instead — it follows the same storage/retention path but is never forwarded to the LLM prompt unless a tool’s Description references it with {{endUser.*}}.
Safe to put in context:
- Internal IDs (
productId,orderId) — useful for tool calls, low risk - Non-PII flags and roles (
userRole: 'premium',isFirstSession: true) - App state (
currentScreen,cart.itemCount,selectedFilter) - Locale, theme preference, feature flags
Locale
locale is a separate prop — a BCP 47 locale (e.g. "tr", "en-US") forwarded to the backend so the assistant answers in that language unless the project’s own instructions demand another one. It’s explicit only: the SDK never reads the device locale for it, and it does not change the SDK’s own UI strings.
<Qafka
// projectId, endUserId, …
locale="tr"
/>Best Practices
- Keep keys stable across messages. Use the same key names (
currentScreen, notscreenonce andcurrentScreenlater) — the AI learns to depend on them. - Update context when state changes, not on every render. The widget only re-sends what’s in
contextat message-send time. - Use
contextDescriptionfor non-obvious keys —selectedStoreId: "store-42"means nothing to the AI; “user is browsing the Downtown store” does. (Note: sub-project routing is its own top-levelsubProjectIdprop, not acontextkey — see Sub-Projects.) - Prefer flat structure for tool matching. Tools usually filter on top-level keys —
{ storeId: 'x' }is easier than{ user: { store: { id: 'x' } } }. - Pass IDs, resolve server-side. Send
productId: '123', not the full product object — a tool you configure can look up the product details if it needs them.