Skip to content

Variables & Constants


Variables in Bubblescript can be global and local, meaning they are available from anywhere in Bubblescript or they are only available in the current dialog. Some variables are made available by the system, others are created by the user in the scripts by assignment. All variables can be seen in the panel below the script editor.

Variables that start with user. are special in that they are saved inside the user record the bot keeps. Note that these are shared between all conversations between a user and the bot. Those user variables are also automatically added to the CSV export in the contacts section of the studio.

Global and local variables

Every variable that starts with a "_" is considered a local variable. This means that the variable only exists within the dialog or task it was created in. It's value is stored even if another dialog is invoked in the mean time, but the other dialog won't have access to that variable, the same is true for tasks. Local variables are great when they are combined with repeat loops and conditionals. They can have a name that represents what they stand for without having to worry that a global variable might be overwritten.

Predefined variables

Some variables are set (when triggered) by the runtime itself:

  • user — User-specific data. Data that is remembered inside user gets stored inside the CRM and is accessible across all of a user's conversations. Besides remembered data, the following fields are always available:

  • user.first_name

  • user.last_name
  • user.profile_picture
  • user.timezone
  • user.locale
  • user.extra

  • bot — Information about the current bot:

  • — Unique identifier for the bot

  • bot.title — Name of the bot
  • bot.purpose — The bot's description
  • bot.privacy_url — URL to the bot's privacy policy
  • bot.profile_picture — URL to the bot's profile picture
  • bot.locale — Primary locale the bot speaks (e.g. "en")
  • bot.extra_locales — List of additional locales that the bot can speak (e.g. ["de", "fi"])
  • bot.timezone — The default timezone the bot is configured for
  • bot.inserted_at — When the bot was first created
  • bot.tokens — List of bot-level integration tokens
  • bot.frontends — List of enabled channels for the bot (e.g. ["whatsapp", "phone"])

  • conversation — Information about the current conversation:

  • conversation.g — The channel-specific 'conversation ID'; on single-converation channels (e.g. Whatsapp) this will be "main".

  • conversation.tags — List of tags that are set on the conversation
  • conversation.frontend — The type of the channel, e.g. "whatsapp"
  • conversation.locale — The current locale that the bot speaks in the conversation
  • conversation.debugging — Whether or not the conversation is running in the studio
  • conversation.operator — When an operator participates in the conversation, this contains first_name, last_name, etc.
  • conversation.addr — String representing the unique address of the conversation
  • conversation.origin — For web chats, the URL of the page the conversation started on
  • conversation.referrer — For conversations that were redirected from another conversation, contains the redirect parameters (like .bot for the bot ID).

  • dialog — Contains information about the execution history and stack

  • dialog.history

  • dialog.stack

  • message — Data related to the user's last message

  • answer — The last response to an ask

  • location — The most recently received location pin


  • location.lon

  • attachment — The most recently received media attachment

  • attachment.type

  • attachment.url
  • attachment.caption
  • attachment.metadata

  • event — The most recently received event


  • event.payload

  • schedule_id — The id of the most recently scheduled emit

  • visitor — Visitor-specific data (only accessible within bots running in the chat widget with visitor-tracking enabled)
  • nudge — Set when a conversation was started from clicking a nudge

  • frontend — Channel-specific information about the connected channel. Only one of the channel-specific subfields will be set:

  • — An object with the following fields: sender_name, public_email, private_email, threading.

  • frontend.facebook — An object with the following fields: name, picture, about.

  • — An object with the following fields: number, beep, record.
  • frontend.telegram — An object with the following fields: username, info.
  • frontend.web_pwa — An object with the following fields: domains
  • frontend.web_widget — An object with the following fields: domains, visitors
  • frontend.whatsapp — An object with the following fields: phone, provider, hosting_type, reengagement_template, deflection_template, lock_reenagement

Don't set these reservered variables yourself as they will be overwritten!

Variable types

The variable types that can be used in Bubblescript are similar to the variables in Elixir, please visit the link for an in-depth explanation. Any reference in their documentation to the word "iex" is similar to a line typed in Bubblescript.


A string is text and is always typed in double quotes ("). If you want to use double qoutes in your string, you should escape them in the following manner: "this string contains \"double quotes\"".

Strings interpolation

Strings can be interpolated by adding #{variable_name} in the strings themselves. What this means is that the value in the variable will be added to the string. Think of this as the "find and replace" function in a text-editor. This is useful for creating pieces of text that function as templates for responses or questions.


dialog greeting do
    name = ask "What is your name?", expecting: @text
    say "Hi #{name}"

Accessing nested values

The following example shows how the value of a Map is displayed by using the key in string interpolation.

user = %{"name" => "Hank"}
say "Hello #{}"

The . notation used here is the same way a key of a Map is accessed.


A list can be seen as a sequence of things, where these things can be strings, maps, or other variables. To get the first item in a List you can use the bracket notation [0] Note: List like arrays in most programming languages start at 0 zero!

list = [1, 2, 3]
say list[0]         # 1
say length(list)    # 3

To iterate over the full array you can use repeat:

dialog iterate do
  list = [1, 2, 3]
  repeat element in list do
    if element == 3 do
      say "and.."
    say "item #{element}"


A Map is a key->value data structure that allows a value to be stored in with a key. If we would like to see the value, the key is our reference point with which we can find the value.

simple_map = %{"name" => "Bert"}

numbers_as_keys = %{1 => "one",
                    2 => "two"}

# Here we create a map that will describe a car

car = %{"brand" => nil,
        "engine" => %{}} # notice that the value of a map can also be another map.

Note that you can create these maps yourself as well:

  car.brand = "Volvo"
  car.engine.hp = 200

  # car == %{"brand" => %{"engine" => %{"hp" => 200}}}


If a key is not found in the map when you assign it in the map, it will be automatically be created for you. In the example above, when 200 is inserted in the key hp the preceding map engine will be created automatically.


Variables starting with an @ are treated as constant values. These can only be defined outside a dialog.

@constant "key"
@version 12
@message "Hello and welcome!"

dialog main do
  say @message
  say "My version is: " + @version

notice that you do not need to use an assign (=) character for assigning values into a constant!


= (assignment)

variable = ask "whats your name?"
variable = "string"
variable = 1
variable = [1,2,3]
variable = first [1,2,3]

addition (+)

The + operator has superpowers.

  • It performs addition on numbers: 1 + 3 == 3
  • It concatenates strings: "a" + "b" == "ab"
  • It can glue lists together: [1] + [2, 3] == [1, 2, 3]
  • It can even glue lists together when one element is not a list: 1 + [2, 3] == [1, 2, 3]
  • It merges maps: %{"a" => 2} == %{"a" => 1} + %{"a" => 2}
  • When it encounters nil on either side of the +, it ignores it: [1, 2] + nil == [1, 2]

substraction (-)

The - operator is superpowered as well.

  • It performs regular substraction: 3 - 2 == 1
  • When encountering strings which are numbers, it converts them to numbers: "100" - "10" == 90
  • It can be used to remove elements from a list: [1, 2] - [1] == [2]
  • It can be used to remove substrings from strings: "paap" - "aa" == "pp"

In all other cases, it raises an error, for instance when you try to substract a number from a string.

boolean operators

The following operators are supported:

a && b    # AND
a || b    # OR
!a        # NOT
a == b    # EQUALS
a != b    # NOT EQUALS
a <  b    # IS SMALLER
a >  b    # IS LARGER

pipe operator

The pipe operator, inherited from Elixir, takes the expression on the left and uses it as the first argument to the function call on the right.

# These two are equivalent:
flatten([1, [2], 3])
[1, [2], 3] |> flatten()

The pipe operator can be used for multiline expression. This can be especially useful when you're performing a sequence of steps. To give a contrived example:

uppercase_b =
  ["a", ["b"], "c"]
  |> Array.flatten()
  |> Array.item(1)
  |> String.upcase()

assert uppercase_b == "B"

Platform-specific constants

The following constants have special meaning, when they are defined.

  • @timeout - defines how long the script will be allowed to run after the last message that a user sent. After the conversation expires, the chat process is suspended until it is activated again (by a user message or an event sent to the bot). When the conversation resumes, the __resume__ dialog is executed and after that the conversation continues on the place where it was suspended.
  • @delay - defines the standard delay (in seconds) after the bot shows a message to the user
  • @typing_indicator - defines the standard delay (in seconds) how long the typing indicator should be displayed before any message is shown to the user.
  • @ask_timeout - defines how long to wait for a user to give an answer on a question (ask)
  • @duckling_reftime - When set to "start_of_day", all Duckling-related message triggers are calculated with a reference time from the start of the day instead of the current time.


@ask_timeout      :infinity
@timeout          "15m"
@delay            1
@typing_indicator 1

# Other time formats
@timeout "1h"
@timeout "60s"
@timeout "200ms"

Besides these globals that can be overwritten there are some read only globals that you MUST NOT ovewrite:

  • @intents - is a list of all intents defined in the intents files (read only)
  • @skills - is a list of the skills (modules) this bot has (read only)

Note: the intents and data files you creata also create constants that can conflict with these system contstants. So don't create an intent or data file with the name skills or intents

Intent constants

When you create new intents via the training panel or directly in the training yaml file they will be exposed in the code as constants. So the @yes constant refers to the yes intent.

Loading constants from a file

When adding a YAML or a JSON file in the DialoX studio, the contents of that file is exposed in a constant which is named after the JSON/YAML script file name.

Data files are a convenient way to keep data outside the bot script contents, but still embedded as part of the bot.

For instance, when you create a YAML file called people with the following contents:

- name: Arjan
  age: 38
- name: Pete
  age: 22
- name: Julie
  age: 32

The contents of the people file is now accessible in your bot script under the constant @people. It can be used like this:

repeat person in @people do
  say "Name: " +
  say "age: " + person.age

When a data file is defined in a folder, say, a data file named data/people, the slash in the filename will be transliterated into an underscore, so that in this case, the constant name becomes @data_people.

Read more about data files and content management

Constant accumulation

The accumulate top-level statement can be used to merge constants from different files together into a list. The use case of this is that sometimes there are various skills in a bot which all contribute to some list constant. This cannot be done using a normal constant because constants overwrite each other when they are defined in multiple files.

So by prepending the constant with the accumulate keyword, the value is forced to be a list and collected from all script files.

As an example, when you have in one file:

accumulate @list 1

And in another:

accumulate @list 2

The @list constant will contain the list [1, 2].