Skip to main content

Overview

Dynamic variables allow prompt templates to be personalized at runtime using data from multiple sources. Variables use Mustache-style {{variable_name}} syntax and are resolved from a priority-ordered chain of sources before any prompt is rendered.
Implementation status (2026-10-04). Parts of this page describe a design that was never built. They are kept, and marked not implemented, because their reasoning informs the planned verified-variables work. See docs/agentic-development/CHORES.md C-210.
  • Implemented: variables in POST /bots/:id/chat and POST /bots/:id/conversations (and the public POST /public/agents/:slug/conversations); the pre-chat visitor form; agent-level and system defaults; the precedence merge; rendering.
  • Not implemented: signed context tokens. contextToken is accepted by the conversation-create schemas and forwarded by packages/chat-core, but nothing issues, verifies or reads one, and there is no POST /bots/:id/context-token endpoint.
  • Not implemented: setting sensitive variables. There is no POST .../conversations/:conversationId/variables endpoint, and nothing calls conversationVariablesRepository.setSensitiveVariables, so the encrypted sensitive_variables store is read during rendering but never written.
  • Not implemented: var_ query parameters on chat links, and the widget’s data-variables / data-context-token attributes. Nothing in apps/web or embed.js reads them.
Variable values that do arrive are supplied by the visitor or the API caller and are not verified; do not use them for anything that must be trusted.

Variable Syntax

  • Variable names are case-sensitive
  • Unresolved variables are replaced with an empty string
  • Unresolved variables are logged as warnings for debugging
  • Nested/escaped braces are handled gracefully

Sources and Precedence

Variables are merged from highest to lowest priority (higher priority overwrites lower for the same key):

Passing Variables

Include variables in the chat request body:
  • First request (no conversationId): variables stored as initial_variables and variables
  • Subsequent requests: new variables merged into variables (existing keys overwritten)

Sensitive Variables (not implemented)

Design only — not implemented (C-210). The conversation_variables.sensitive_variables column and its decryption on read exist, but neither write path below was built: there is no POST .../variables endpoint and no context-token issuer or verifier. The design is kept for the planned verified-variables work.
Sensitive variables are server-set and never returned in any client-facing API response. They are stored encrypted in conversation_variables.sensitive_variables using AES-256-GCM.

Setting via POST Endpoint (not implemented)

Design: call from your backend before or during the conversation:

Setting via Signed Context Token (not implemented)

Design: generate a signed JWT from your backend:
Response: { "token": "eyJ..." }
  • Frontend receives opaque token, passes as context_token in conversation create or chat request
  • Bot service decodes JWT server-side, extracts variables
  • Keys listed in sensitive_keys are stored encrypted; others stored as regular variables
  • Token has expiry — validated before use
Use case: Host backend pre-generates context for an embedded widget session. The frontend never sees the sensitive values, only the opaque token.

Resolution Flow

Prompt Rendering Engine

Shared utility in packages/shared/src/prompt-renderer.ts:
  • Pure function, no side effects
  • Used by bot service for all prompt types
  • Handles nested/escaped braces gracefully
  • Returns list of unresolved variables for logging

Per-Message Variable Overrides

Variables can be updated mid-conversation by including variables in any chat request:
New variables are merged into the existing conversation_variables.variables record, enabling dynamic context updates as the conversation progresses.

Security Considerations

Follow these security rules for all variable handling.
  • Never expose sensitive variable keys in client-side code or HTML. (The intended remedy, signed context tokens, is not implemented — C-210. Until it is, there is no safe channel for sensitive values: keep them out of variables.)
  • Variables are not verified: a value arrives as the visitor or API caller sent it. Never use one to decide anything that must be trusted, such as a customer tier that unlocks behaviour.
  • Prompt injection: Malicious variable values could attempt to override LLM behavior. Variables should be clearly delimited (e.g., wrapped in quotes or XML tags) when inserted into LLM prompts.
  • Context token expiry (design, not implemented): a token should carry a reasonable expires_in (e.g., 3600 seconds) and be rejected once expired.
  • Sensitive variables (design, write path not implemented): encrypted at rest, never returned in GET responses, only accessible server-side during prompt rendering.
  • Query param variables (not implemented): Only use for non-sensitive data — query params are logged and visible in browser history.