Skip to Content
CraftBot Docs v1 — internal preview
ReferenceExpressions

Expressions

Variables and small expressions are usable in any field that supports interpolation: message bodies, headers, URLs, request bodies, Set Variable values, and Condition rules.

Variable interpolation

Wrap a variable name in {{ }} inside any text field:

Hi {{customer_name}}, your reference is {{policy_number}}.
  • Names are case-sensitive.
  • A bare name (no scope prefix) reads from conversation scope by default.
  • Unresolved variables render as the empty string and emit an unknown_variable_referenced event the recipe author can spot in session telemetry.
  • Maximum path depth: 4 segments ({{a.b.c.d}} is fine; deeper paths raise a parse error).

Variable scopes

Four-tier scope model:

ScopeSyntaxNotes
Recipe{{r.name}} or {{recipe_var.name}}Scratch values inside the current recipe activation. Flushed on sub-flow return.
Conversation{{name}} (default)Shared across sub-flows within the session. Persists for the life of the conversation.
User (contact){{contact.name}}Maps to chat_contacts.custom_attributes. Persists across conversations.
Config{{config.name}}Tenant config values; read-only at runtime.

System variables are resolved synthetically:

ReferenceValue
{{user.name}}, {{user.phone}}, {{user.email}}Contact attributes.
{{conversation.id}}Current conversation id.
{{recipe.id}}, {{recipe.version_id}}Running recipe identifiers.
{{language}}Session language (e.g. en / ar).

Filters

Filters transform the resolved value using pipe syntax {{name | filter}} or {{name | filter: 'arg'}}. Multiple filters chain left-to-right.

FilterPurposeExample
lowerLowercase a string.{{country | lower}}
upperUppercase a string.{{code | upper}}
trimStrip surrounding whitespace.{{input | trim}}
default: 'X'Fall back to the argument when the value is null, undefined, or empty.{{nickname | default: 'friend'}}
date: 'YYYY-MM-DD'Format a date / ISO timestamp using YYYY MM DD HH mm ss placeholders (UTC).{{appointment_at | date: 'YYYY-MM-DD HH:mm'}}

Unknown filters pass the value through unchanged.

Condition operators (runtime)

The Condition node compares a left-side variable to a right-side variable or literal. The runtime supports six operators:

OperatorMeaning
=Equals (type-coercing — strings compare to numbers, booleans normalize).
!=Not equals.
>Numeric greater than. Non-numeric values evaluate to false.
<Numeric less than.
containsSubstring match for strings; element membership for arrays.
is_emptyTrue when the value is null, undefined, an empty string, or an empty array.

Drift notice. The Condition node config drawer currently lists ten operators (==, !=, >, >=, <, <=, contains, starts_with, is_empty, is_not_empty). Picking ==, >=, <=, starts_with, or is_not_empty in the drawer silently evaluates to false at runtime — those five are not wired. Stick to the six operators in the table above until the drift is resolved. Tracked as PF-6 in the postponed-fixes log.

Type coercion

  • Equality (= / !=) coerces strings to numbers when either side is numeric, and to booleans when either side is boolean. Otherwise the comparison is string-equal.
  • Numeric comparisons (> / <) cast both sides via Number(...) and return false if either side is NaN.
  • contains requires the left side to be a string or array.
  • is_empty covers null, undefined, empty string, and empty array.

Limits

  • Expressions are evaluated synchronously at node-fire time.
  • Maximum path depth on a dotted reference: 4 segments.
  • No loops, no arithmetic expressions, no inline function calls — this is a value-shaping language, not a programming language. For computed values, set them upstream with a Set Variable node fed by an API or Smart Plug response.
Last updated on