Here you’ll learn how to create code inside the Botmaker platform.
First, go to the main page of Botmaker. Go to the left sidebar menu and look for the word “Code.”

Click there, and you’ll be redirected to the Code Actions screen.

Client actions are useful for developing more complex intents or when you want to add arbitrary code to a conversation. It’s an excellent alternative to connect external services to retrieve relevant, real-time information in user conversations.

For example:
You can ask the user to say a color. Once sent, you can connect Google’s Translation API so the bot replies with the same color in another language.
First, you must create a client action in the Code screen. Click on “Create new code action.”
Assign a name to the action (don’t forget it), select the NodeJS version, and the action type.
You can work on a code template to boost your action.
Once finished, click the “Publish” button to make it available for use.
We support Node.js v22, along with the following libraries:
{
"@google-cloud/pubsub": "^5.0.0",
"@google-cloud/vision": "^5.1.0",
"@turf/helpers": "^6.1.4", // accessed by "turfHelpers"
"@turf/turf": "^6.5.0", // accessed by "turf"
"axios": "^1.9.0",
"bluebird": "^3.5.1", // accessed by "bluebird"
"fast-csv": "^4.3.6", // accessed by "csv"
"googleapis": "^92.0.0", // accessed by "google"
"js-sha256": "^0.9.0", // accessed by "sha256"
"jsonwebtoken": "^9.0.2", // accessed by "jwt"
"lodash": "^4.17.10", // accessed by "_"
"md5": "^2.2.1", // accessed by "md5"
"moment": "^2.22.2", // accessed by "moment"
"moment-timezone": "^0.5.34", // accessed by "momentTimezone"
"node-fetch": "^2.6.6", // accessed by "fetch"
"request": "^2.88.2",
"request-promise": "^4.2.5", // accessed by "rp"
"secure-random": "^1.1.1", // accessed by "securedRandom"
"sharp": "^0.34.1", // accessed by "sharp"
"uuid": "^11.0.3", // accessed by "uuidv4"
"xml2js": "^0.6.2", // accessed by "xml2js"
"xml2json": "^0.7.1"
}
If you’d like to use another library, email us at architecture@botmaker.com, and our team will review the request.
When the code is triggered, all available information about the user, conversations, and general configuration is provided.
The following JSON describes the input a cloud function can use:
{
"context": {
"userData": { ... },
"message": { ... },
"params": {}
}
}
A read-only object containing relevant information that a code action might need. It provides:
Example:
const userFirstName = context.userData.FIRST_NAME;
This object allows reading and writing variables that will persist for the user. It’s a great place to store user-related data.
Values must be strings.
user.get('key') → returns a string or nulluser.set('key', 'value')Example:
if (!user.get('neverWasHere'))
user.set('neverWasHere', 'true');
The variable neverWasHere will remain true unless changed by another client action.
In the variable configuration section, you can change the variable type, visibility to operators, and even set it to expire after inactivity.
When you upload a CSV file in the Records menu, client actions can access it and filter saved lists.
entityLoader('entity name', json => {
if (!json) {
user.set('error', 'No data');
result.done();
return;
}
const data = json.find(row => row.id === 2);
result.text('Showing name -> ' + data.name);
});
We added a new component in Client Actions (CAs) called db. Unlike Redis, it doesn’t need to be imported — it’s used just like user or result.
It includes several methods:
GET
Retrieves a key-value pair from the internal database.
db.get('key')
SET
Stores a key-value pair in the internal database.
Values must always be strings.
db.set('key', 'value')
EXISTS
Checks if a record exists for the given key. Returns true or false.
db.exists('key')
DEL
Deletes a record by its key.
db.del('key')
ZADD
Adds a record to a collection, sorted by score. Includes an expiration time in seconds.
db.zadd('key', 'value', score, expiration)
ZRANGEBYSCORE
Retrieves all records with a score between min and max.
db.zrangebyscore('key', min, max)
ZREMRANGEBYSCORE
Deletes all records in a collection whose score is between min and max.
db.zremrangebyscore('key', min, max)
In “Endpoint” or “Cron” Client Actions, all db methods must be called with request.db instead of just db.
If you import another Client Action as a library and it uses the db object, you must also prefix it with request.
To send output from a client action, use the result object.
result.text('a message')result.image('https://example.com/image.jpg')result.video('https://example.com/video.mp4')result.file('https://example.com/myfile.doc')result.audio('https://example.com/audio.mp3')You can also send text with action buttons:
result.buttonsBuilder()
.text('Select an option')
.addURLButton('click me', 'https://www.google.com')
.addLocationButton()
.quickReplies()
.addPhoneButton('call me', '+11233212312')
.addButton('click me', 'rule name XX')
.send();
After a client action, you can continue the flow by triggering a rule:
result.gotoRule('rule name');
You must call result.done() to end execution.
Always include it in every flow to finalize properly.
Example:
rp({ uri: 'https://script.google.com/...', json: true })
.then(json => {
result.text('The time in Tokyo is ' + json.fulldate);
result.done();
})
.catch(error => {
result.text('Problems: ' + error);
result.done();
});
You can dynamically generate list options in a client action.
const COUNTRIES = ['Argentina', 'Bolivia', 'Brazil', 'Chile', 'Mexico', 'Paraguay', 'Peru', 'Uruguay'];
let myJSONList = COUNTRIES.map((country, index) => ({ id: index, name: country }));
user.set('countries', JSON.stringify(myJSONList));
result.done();
Go to the Bot Designer, click the “More” button at a flow intersection, and select “Action.”
Then click “Code Actions,” and choose between “Code Actions” and “Code Actions with parameters.”
You’ll be able to select any published actions.
Use REST integrations to send or fetch data via an API.
rp({ uri: 'https://httpbin.org/anything', json: true })
.then(response => {
user.set('data', response.data);
result.text('Successful call: ' + JSON.stringify(response));
result.done();
})
.catch(err => {
result.text('Problems!: ' + err.message);
result.done();
});
Used to send or fetch data from SOAP APIs.
const request = `<soapenv:Envelope ...>...</soapenv:Envelope>`;
rp({
uri: 'https://www.custom-service.com/myService.asmx',
method: 'POST',
headers: {
'Content-type': 'text/xml',
'SOAPAction': 'http://tempuri.org/MyAction',
'Content-Length': Buffer.byteLength(request)
},
body: request
})
.then(response => {
xml2js.parseString(response, (err, parsed) => {
user.set('data', parsed.responseResult);
result.text('Successful call!: ' + JSON.stringify(parsed));
result.done();
});
})
.catch(err => {
user.set('error', `Error rp SOAP ${err}`);
result.done();
});
You can create it by using a button that calls another client action:
result.buttonsBuilder()
.addClientActionButton('Button name', 'Client Action name', { 'key': 'value', 'key2': 'another_value' })
.buildButtons();
To access the parameters:
const myVar = context.params.key;
const myVar2 = context.params.key2;
You can create reusable functions in a utility library to avoid duplicate code and speed up your workflow.
Then call them from any other code using the exact same name.
To execute an external API query from a Botmaker client action, follow the example shown above.
Remember to visit our Help Center for further information.