Userlike Bot Language Tutorial
Introduction
Chatbots can assist your team and take over boring and repetitive tasks such as gathering contact information, allowing your operators to focus on helping customers. They can also be useful as a way to answer simple questions after hours.
At Userlike, we believe in the power of human-to-human contact, but recognize the value service-bots can bring to messaging. This is why we offer the possibility to either integrate your own chatbot with our API or to create rule-based bot flows written in the Userlike Bot Language (UBL, covered in this tutorial).
This tutorial walks you through all the details for setting up your own bots within Userlike.
Topic | Description |
---|---|
What is UBL? | Find out what the Userlike Bot Language is and how it's written |
How to set up a chatbot | How to configure your chatbot to work with our API |
Nodes | Learn about message and input types in the Userlike Bot Language |
Commands & actions | Learn about the commands that can be executed by your bot |
Session context | How information is stored and retrieved |
Examples | Some examples that illustrate how you can create your own conversation flows with UBL |
What is UBL?
The Userlike Bot Language (UBL) allows you to write bot scripts that can be used in your Widget and channels using a simple, minimal syntax.
YAML
UBL scripts are written with the YAML language. If you are not familiar with the YAML syntax, we suggest you read up on it first, as the rest of this tutorial assumes basic knowledge of YAML formatting and data types.
The basic layout of a UBL script looks as follows (each line is annotated with an explanatory comment):
Your UBL file should always start with a `config` key containing essential configuration information for your script. `config` should contain an `abort` and a `skip` parameter. The keywords you define here will be used to trigger the abort sequence, which allows the contact to immediately quit the bot flow, or to skip input steps you‘ve defined as optional.
Script linting and validation
Once you've written a script you are happy with, you can upload it to Userlike and use it with your chatbots (further information in section below).
**Please make sure to use spaces for indentation**, as tabs will be rejected during validation when uploading your script.
Testing your script
After uploading the script to Userlike, you are ready to test it. To do so, go to a page that contains the Widget you‘ve associated your chatbot with and start a conversation. Test all conversation paths and see if the conversation flow works as expected. If you discover something that needs adjustments, just open your `.yml` file in your favorite text editor, make adjustments and upload it again to test your changes.
Chatbot setup in Userlike
In Userlike, bots are a special type of operator. You can create a new chatbot by going to Unified Messaging Team Chatbots in your Dashboard. Click on **Add chatbot** to create a new chatbot.

Approach modes
There are four approach modes that you can select for your chatbot, depending on how you want to use it to provide service to your contacts:
- **Service time**: The bot is online only outside of the services times defined in the Widget.
- **Backup**: The bot is always online, but only takes conversations when no human operators are available for live conversations.
- **Human**: The bot is always online and takes chats like any other operator.
- **Firewall**: The bot is always online and receives all incoming conversations (eg. to pre-categorize and forward them)
Bot conversation timeout
Define a time with no reply from both contact and bot after which the conversation is considered inactive. Once this happens, the bot can perform one of the following actions:
- **End conversation** and move it to **All conversations**
- **Unassign conversation** and move it to the Inbox, where any operator in your group can see and answer it.
- **Forward conversation** to an available human operator from the same group.
Note that bot conversations don’t show up in your Inbox as long as they’re active. Your operators will only be able to see them once they end, are unassigned or forwarded.
Script upload
You can upload your script by clicking on the "Upload script" button. **Please upload a valid YAML file with the extension .yml**.

Nodes
You can use a number of possible elements to define the flow of a conversation with your bot. Nodes are conversation elements. Different types of nodes can be used to gather and validate data, display information and even talk to external APIs to send or retrieve information from third-party systems.
Message node
This is the simplest node type. The message node can be used to display text or send links to the contact. It also supports variable expansion, so it can be used to address the contact with their name, for example. Variables are expanded by wrapping them in double curly braces.
Example of a message node:
Media node
This is the node type displays media types like images and videos.
Example of a media node:
Button node
This is the node type to display buttons with clickable links. It also supports variable expansion, so it can be used to address the contact with their name, for example. Variables are expanded by wrapping them in double curly braces.
Example of a button node:
Input node: Text
There are different types of input nodes which represent the different ways you can collect information from your contacts. The text input node is a simple way to get data from your contact by asking them to enter text into the messenger input. The text input node has several parameters that can be used to make input required or handle invalid input. For example:
Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt the contact for input with. |
type |
text |
Defines the input node as being of the type text |
optional |
boolean |
Whether the input step can be skipped or not by not providing a value, or when the skip keyword is triggered. |
key |
string |
The variable name the input text should be saved to. |
when |
skip / valid / exists |
Determines what should happen when the condition defined by the value is met. |
Example of a text input node in which we'll also introduce the **exists** parameter (which will be explained further in this tutorial):
The exists logic
As we've seen in the example above, we have the ability to check for the existence of a value and trigger an action accordingly.
The `exists` parameter itself needs the argument **where**, which can have a value of either `contact` or `context`, depending on where the information is stored.
Here's an example of how an **exists** check would be performed on the contact's name:
Input node: Email
This node is a text input node with built-in validation for email addresses. You can use the email input node to ask your contacts to provide their email address. It will automatically check if the input provided is a valid email address. Unless you make the input optional, the contact won‘t be able to proceed to the next conversation step until a valid email address is provided. As you can see in the table below, it is very similar to the text input node. It has an additional `not-valid` condition that is triggered when the email address provided cannot be validated.
Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt the contact for input with. |
type |
email |
Defines the input node as being of the type email |
optional |
boolean |
Whether the input step can be skipped or not by not providing a value, or when the skip keyword is triggered. |
key |
email |
The email variable name the input should be saved to. |
when |
skip / valid / not-valid / exists |
Determines what should happen when the condition defined by the value is met. |
Here's how you would use a simple email input node. As you can see, it's also possible to check if an email is already known for the contact:
Input node: Regex
This is a type of text input node that offers validation. Whereas the Email node can only validate email addresses, the Regex node allows you to provide a Regular expression to validate the data provided. This means it can be used for a wide range of applications, from making sure that a phone number matches a certain format to asking for dates, customer IDs or tracking numbers.
Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt the contact for input with. |
type |
regex |
Defines the input node as being of the type regex |
format |
A valid regular expression | Provide the regular expression that should be matched in order for the input to be considered as valid. |
optional |
boolean |
Whether the input step can be skipped or not by not providing a value, or when the skip keyword is triggered. |
key |
string |
The variable name the input should be saved to. |
when |
skip / valid / not-valid / exists |
Determines what should happen when the condition defined by the value is met. |
Here's how you would use the regex input node:
Input node: Bubbles
The bubble input node can be used to present the contact with multiple options to choose from. It displays them as buttons (or 'bubbles') that can be clicked by the contact. Alternatively, they can also choose an option by entering a number corresponding to one of the choices. For channels that don't support displaying bubbles, a text fallback can be defined which will be displayed instead.
The bubble input node is useful if you want to guide the contact closely along a determined conversation path by proposing a set of options to choose from.


Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt for input with. |
type |
bubbles |
Defines the input node as being of the type bubbles |
fallback |
string |
A string containing the text you want to display when bubbles cannot be displayed. |
any_message |
A node and action to perform | Determines what should happen when none of the options is chosen by the contact or any text is entered instead. |
options |
option |
`options` should be a sequence of maps containing the text to display in the button under the key `option` and which action should be taken when the option is selected. |
A simple example:
Input node: Carousel
The carousel input node is similar to the bubble input node in how it allows you to present a variety of choices that can be clicked by the contact. Instead of only presenting bubbles that can be clicked, the carousel node allows you to add an image and to add a headline and description to each option. The carousel node is perfect for providing the contact with a selection of items, for example in an online store.

Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt for input with. |
type |
carousel |
Defines the input node as being of the type carousel |
fallback |
string |
A string containing the text you want to display when carousel cannot be displayed. |
any_message |
A node and action to perform | Determines what should happen when none of the options is chosen by the contact or any text is entered instead. |
options |
option |
`options` should be a sequence of maps containing the text to display in the button under the key `option` and which action should be taken when the option is selected. |
The `option` map in the carousel node is slightly more complex than that of the bubble node. We've annotated the possible keys in the example below:
Input node: List template
The list template input node is intended **primarily for WhatsApp**, though a reduced version of it will work on other channels. It is is similar to the bubble input node in that it allows you to display a variety of choices that can be clicked by contacts, but allows more extensive formatting options.
This is useful to display a larger list of **up to ten options** for the user to select from.


Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt for input with. |
type |
list_template |
Defines the input node as being of the type list_template |
fallback |
string |
A string containing the text you want to display to contacts when `list_template` cannot be displayed fully, i.e. when used on an unsupported channel. |
any_message |
A node and action to perform | Determines what should happen when contacts choose none of the options or enter text instead. |
header |
String |
Optional headline displayed above the message, <= 60 chars. |
list_header |
String |
Optional headline displayed in the select menu, <= 24 chars. |
footer |
String |
Optional footer displayed below the message, <= 60 chars. |
button_text |
String |
Text displayed on the button prompting the user to select something from the list, <= 20 chars. |
options |
option |
`options` should be a sequence of maps, each one under the key “option”, with <= 10 options.
The sequence can contain: - `action`: Action that should be taken when the option is selected - `label`: Main text on the element to select, <= 24 chars - `description`: Optional description text, <= 72 chars |
A simple example:
Input node: Button template
The button template input node is intended **primarily for WhatsApp**, though a reduced version of it will work on other channels. It is is similar to the bubble input node in that it allows you to display a variety of choices that can be clicked by contacts, but allows more extensive formatting options.
A button template allows you to display a few buttons combined with other content, like text and media files. Note that only **up to three** buttons are supported.

Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt for input with. |
type |
button_template |
Defines the input node as being of the type button_template |
fallback |
string |
A string containing the text you want to display to contacts when `button_template` cannot be displayed fully, i.e. when used on an unsupported channel. |
any_message |
A node and action to perform | Determines what should happen when contacts choose none of the options or enter text instead. |
header_type |
String | Type of headline shown above the message. Can be `text`, `image`, `video` or `document` – or left out if you need no headline. |
header_text |
String | Required for header_type `text`. Represents the headline text, <= 60 chars. |
header_url |
String | Required for all non `text` header_types. Should be a link to the media file. |
footer |
String | Optional footer shown below the message, <= 60 chars. |
options |
option |
`options` should be a sequence of maps, each one under the key “option”, with <= 3 options.
The sequence can contain: - `action`: Action that should be taken when the option is selected - `label`: Main text on the element used for selection, <= 20 chars |
A simple example:
Input node: API
The API input node allows you to fetch data from, or send data to, external systems by making HTTP requests. This allows for a variety of use cases, such as fetching the status of an order or a delivery given a corresponding ID.
You can use the same text expansion capabilities we learned about in the message node to parse the response from the API and display it to the user.
Parameter | Value | Description |
---|---|---|
message |
string |
A string containing the text you want to prompt the contact for input with. |
api |
request / response / when |
api is a map containing the request and response objects. |
As you can see, the API node only has two parameters at the top level. `api` itself takes three parameters that specify the request and response as well as what happens when the request fails or succeeds. This is described in the table below:
Parameter | Value | Description |
---|---|---|
request |
url / method / headers / data |
The data you want to use to make your request. |
response |
key |
The variable the data received in the response should be saved to. |
when |
failure / success |
Determines how to handle request failures and how to proceed after a successful request. |
The following example demonstrates general use of the API node to retrieve data and display it to the user:
The received JSON object is saved to the `result` variable. We can access the data at the top level of the object by expanding the keys by wrapping them in double curly braces. The same applies to accessing the data inside the `company` object. To signal that `{{name}}` in the second instance should refer to the name of the company and not to the name of the person, you can use a section by surrounding it with `{{#company}}{{/company}}` where appropriate.
The API node also supports making POST HTTP requests, which is demonstrated below:
Commands & actions
We‘ve already seen in the previous examples that every step ends with an action. Until now, we‘ve only used actions to proceed to the next step in the conversation flow by using the `next` command. UBL offers several more commands you can use in order to set or clear data of your contact, to navigate, or to forward the contact to human operators.
Commands
Command | Value | Description |
---|---|---|
set_name |
string |
Called on the contact, sets the name to the value provided. |
set_email |
string |
Called on the contact, sets the email to the value provided. |
set_mobile_number |
string |
Called on the contact, sets the mobile number to the value provided. The phone number must match the international phone number format E.164 in order to be persisted on the contact. |
set_external_customer_id |
string |
Called on the contact, sets the external customer id to the value provided. |
clear_name |
boolean |
Called on the contact. If true, clears the name currently saved on the contact. |
clear_email |
boolean |
Called on the contact. If true, clears the email currently saved on the contact. |
clear_mobile_number |
boolean |
Called on the contact. If true, clears the mobile number currently saved on the contact. |
clear_external_customer_id |
boolean |
Called on the contact. If true, clears the external customer id currently saved on the contact. |
forward_group |
string |
Provide the operator group name you want to forward to as a string. You can additionally define a `fallback` behaviour if the group is not online. |
forward_any |
boolean |
If true, forwards the conversation to any available operator. You can additionally define a `fallback` behavior for when no operator is available. |
forward_skills |
List of strings |
Provide (by name) a list of skills an operator needs to possess to be eligible for this forward action. You can additionally define a `fallback` behaviour if no matching operator is available. |
navigate |
url |
Provide a URL to navigate to as a string. The text for the navigation event can be set by using the `text` command. Define the fallback display by using setting the `fallback` value. Note that the target URL must have the same host as the URL the contact is currently visiting. |
note_create |
string |
Called on the contact or the conversation. Creates notes during the current conversation. In the context of contact, the note will appear in the contact’s details. In the context of the current conversation, the note will appear after the latest message in the conversation’s message history. |
Session context
The session can contain information which you can use in your UBL script by saving it to variables, as we've previously seen.
Conversely, you can also access session information in your UBL scripts in case it's already been provided by the contact, for example when using the mandatory registration mode.
If we want to access the contact's name in order to give them a personal greeting (assuming you've gathered it from the registration form before the chat), we would simply use an input step and perform an 'exists' check for the contact name. Since this information was required to start the session, it will be available to the bot. Refer to the "THE EXISTS LOGIC" section above for an example.
You can also access data not saved to the contact during the same session by referring to the variable it was saved to. If you previously asked the contact for their customer number, you will be able to reference the variable this was saved to in a later step in order to make an API call, for example.
Examples
We've prepared an example below that you can use as a starting point for your own scripts.
The following script puts together some of the elements we've seen previously to gather a contact's data before trying to direct them towards certain information.
Depending on whether your bot answers all conversations or only the ones coming in while you are offline, you can adjust your conversation flow to gather the information that's important to you or present your contacts with useful resources to help them out right away.