Manage State

Params are variables that are set within a conversation. But, whenever a session is reset or expires, these variables are lost.

Using a simple storage mechanism you can manage stateful data. Data is stored on a thread level and can be accessed even weeks after the first conversation took place.

Code example

async payload => {

  // Get the current count, or 0
  let count = await state.get('count') || 0

  // Save the current count
  await'count', count + 1 )

  // Show or speak the current count
  return new Message(`Count is ${count}`)

Save a Value

Storing data can be done using the method. Provide a key and value to save:

async payload => {

  await'watched', {
    season: 1,
    episode: 2,
    serie: 'game-of-thrones'

Get a Value

Fetch a value by key using the get() method:

async payload => {

  // Could be null if not found
  const watched = await state.get('watched')

  if(watched) {
    // ....



If no data exists get() will return null

Removing values

Remove a specific value by key:

async payload => {
  // Remove aa specific key
  await state.remove('watched')

Clear all values stored for this thread:

async payload => {
  // Remove all data for this conversation
  await state.clear()

Reference, value)

Save data in state

Returns: Promise - Promise that resolves with the value being stored


keystringKey used to save data
valueobjectEither an object, array, or string to store
collectionNamestringOptional. Custom collection name to share state across multiple users


Retrieve data from the state by key.

Returns: Promise - Promise that resolved with the value being stored or null if the key does not exist.


keystringKey used to find the data
collectionNamestringOptional. Custom collection name to find shared state from other users


Remove data from the state by key.

Returns: Promise - Resolves with the key of the deleted data


keystringKey of the data to delete
collectionNamestringOptional. Name of custom collection to delete


Clear all data from the state.

Returns: undefined

Shared state example

Let's say you have a simple quiz bot, and you want to let users submit their score to a leaderboard. You can use a collection to let users get a reference to the scores of other users.

In this example, we assume the user already has a score parameter. In the Code Action below, we create a score object with the value of that param, as well as the userId so we can keep track of whose score it is. Next, we retrieve the scores from the leaderboard collection. If that's empty, we create a new empty array. If the user already has a score on the leaderboard, we override the value with the new score. Otherwise, we add the new score. At last, we save the shared state again in the leaderboard collection.

async payload => {
  try {

    console.log("payload", payload);

    const score = {
      score: payload.params.score[payload.params.score.length - 1].value,
      userId: payload.user.userId ? payload.user.userId:

    let scores = await state.get('scores', 'leaderboard');

    if (scores === null) scores = [];

    const existingScoreIndex = scores.findIndex((scoreInState) => scoreInState.userId === score.userId);

    if (existingScoreIndex !== -1) {
      scores[existingScoreIndex].score = score.score;
    } else {

    console.log("Storing new scores to state", scores);

    await'scores', scores, 'leaderboard');

  } catch(err) {

In another Code Action, you could set parameters to display the full leaderboard or the position of the user within a reply:

async payload => {
  try {

    let scores = await state.get('scores', 'leaderboard');
    console.log("scores", scores);

    let fullLeaderboardObj = null;
    let leaderboardPlayerResult = "You are not on the leaderboard yet. Answer the quiz questions to get a score on the leaderboard.";

    if (scores?.length > 0) {
      const sortedScores = scores.sort((a, b) => b.score - a.score);
      console.log("sortedScores", sortedScores);

      const userId = payload.user.userId ? payload.user.userId :;
      let playerFound = false;
      let playerRank;
      let playerScore;
      fullLeaderboard = "";

      for (let i = 0; i < sortedScores.length; i++) {
        if (sortedScores[i].userId === userId) {
          playerFound = true;
          playerRank = i + 1;
          playerScore = sortedScores[i].score;

        fullLeaderboard += `${sortedScores[i].userId} - ${sortedScores[i].score} points\n\n`;

      console.log("fullLeaderboard", fullLeaderboard);
      fullLeaderboardObj = [{
        value: fullLeaderboard,
        match: fullLeaderboard

      leaderboardPlayerResult = "";

      if (playerFound) leaderboardPlayerResult = `You are on rank ${playerRank} of all ${sortedScores.length} players on the leaderboard with ${playerScore} points.`

    console.log("leaderboardPlayerResult", leaderboardPlayerResult);

    return {
      params: {
        leaderboardPlayerResult: [{
          value: leaderboardPlayerResult,
          match: leaderboardPlayerResult
        fullLeaderboard: fullLeaderboardObj
  } catch(err) {

At last, you can also reset the full leaderboard by passing the collectionName in the state.clear() function:

async payload => {
  try {
    await state.clear("leaderboard");
  } catch(err) {