Manage state data in the v3 JavaScript SDK
APPLIES TO: SDK v3
The Bot Builder Framework enables your bot to store and retrieve state data that is associated with a user, a conversation, or a specific user within the context of a specific conversation. State data can be used for many purposes, such as determining where the prior conversation left off or simply greeting a returning user by name. If you store a user's preferences, you can use that information to customize the conversation the next time you chat. For example, you might alert the user to a news article about a topic that interests them, or alert a user when an appointment becomes available.
For testing and prototyping purposes, you can use the Bot Builder Framework's in-memory data storage. For production bots, you can implement your own storage adapter or use one of Azure Extensions. The Azure Extensions allow you to store your bot's state data in either Table Storage, CosmosDB, or SQL. This article will show you how to use the in-memory storage adapter to store your bot's state data.
Important
The Bot Framework State Service API is not recommended for production environments, and may be deprecated in a future release. It is recommended that you update your bot code to use the in-memory storage adapter for testing purposes or use one of the Azure Extensions for production bots.
In-memory data storage
In-memory data storage is intended for testing only. This storage is volatile and temporary. The data is cleared each time the bot is restarted. To use the in-memory storage for testing purposes, you will need to do two things. First create a new instance of the in-memory storage:
var inMemoryStorage = new builder.MemoryBotStorage();
Then, set it to the bot when you create the UniversalBot:
var inMemoryStorage = new builder.MemoryBotStorage();
var bot = new builder.UniversalBot(connector, [..waterfall steps..])
.set('storage', inMemoryStorage); // Register in-memory storage
You can use this method to set your own custom data storage or use any of the Azure Extensions.
Manage custom data storage
For performance and security reasons in the production environment, you may implement your own data storage or consider implementing one of the following data storage options:
With either of these Azure Extensions options, the mechanism for setting and persisting data via the Bot Framework SDK for Node.js remains the same as the in-memory data storage.
Storage containers
In the Bot Framework SDK for Node.js, the session
object exposes the following properties for storing state data.
Property | Scoped to | Description |
---|---|---|
userData |
User | Contains data that is saved for the user on the specified channel. This data will persist across multiple conversations. |
privateConversationData |
Conversation | Contains data that is saved for the user within the context of a particular conversation on the specified channel. This data is private to the current user and will persist for the current conversation only. The property is cleared when the conversation ends or when endConversation is called explicitly. |
conversationData |
Conversation | Contains data that is saved in the context of a particular conversation on the specified channel. This data is shared with all users participating in the conversation and will persist for the current conversation only. The property is cleared when the conversation ends or when endConversation is called explicitly. |
dialogData |
Dialog | Contains data that is saved for the current dialog only. Each dialog maintains its own copy of this property. The property is cleared when the dialog is removed from the dialog stack. |
These four properties correspond to the four data storage containers that can be used to store data. Which properties you use to store data will depend upon the appropriate scope for the data you are storing, the nature of the data that you are storing, and how long you want the data to persist. For example, if you need to store user data that will be available across multiple conversations, consider using the userData
property. If you need to temporarily store local variable values within the scope of a dialog, consider using the dialogData
property. If you need to temporarily store data that must be accessible across multiple dialogs, consider using the conversationData
property.
Data Persistence
By default, data that is stored using the userData
, privateConversationData
, and conversationData
properties is set to persist after the conversation ends. If you do not want the data to persist in the userData
container, set the persistUserData
flag to false. If you do not want the data to persist in the conversationData
container, set the persistConversationData
flag to false.
// Do not persist userData
bot.set(`persistUserData`, false);
// Do not persist conversationData
bot.set(`persistConversationData`, false);
Note
You cannot disable data persistence for the privateConversationData
container; it is always persisted.
Set data
You can store simple JavaScript objects by saving them directly to a storage container. For a complex object like Date
, consider converting it to string
. This is because state data is serialized and stored as JSON. The following code samples show how to store primitive data, an array, an object map, and a complex Date
object.
Store primitive data
session.userData.userName = "Kumar Sarma";
session.userData.userAge = 37;
session.userData.hasChildren = true;
Store an array
session.userData.profile = ["Kumar Sarma", "37", "true"];
Store an object map
session.userData.about = {
"Profile": {
"Name": "Kumar Sarma",
"Age": 37,
"hasChildren": true
},
"Job": {
"Company": "Contoso",
"StartDate": "June 8th, 2010",
"Title": "Developer"
}
}
Store Date and Time
For a complex JavaScript object, convert it to a string before saving to storage container.
var startDate = builder.EntityRecognizer.resolveTime([results.response]);
// Date as string: "2017-08-23T05:00:00.000Z"
session.userdata.start = startDate.toISOString();
Saving data
Data that is created in each storage container will remain in memory until the container is saved. The Bot Framework SDK for Node.js sends data to the ChatConnector
service in batches to be saved when there are messages to be sent. To save the data that exists in the storage containers without sending any messages, you can manually call the save
method. If you do not call the save
method, the data that exists in the storage containers will be persisted as part of the batch processing.
session.userData.favoriteColor = "Red";
session.userData.about.job.Title = "Senior Developer";
session.save();
Get data
To access the data that is saved in a particular storage container, simply reference the corresponding property. The following code samples show how to access data that was previously stored as primitive data, an array, an object map, and a complex Date object.
Access primitive data
var userName = session.userData.userName;
var userAge = session.userData.userAge;
var hasChildren = session.userData.hasChildren;
Access an array
var userProfile = session.userData.userProfile;
session.send("User Profile:");
for(int i = 0; i < userProfile.length, i++){
session.send(userProfile[i]);
}
Access an object map
var about = session.userData.about;
session.send("User %s works at %s.", about.Profile.Name, about.Job.Company);
Access a Date object
Retrieve date data as string then convert it into a JavaScript's Date object.
// startDate as a JavaScript Date object.
var startDate = new Date(session.userdata.start);
Delete data
By default, data that is stored in the dialogData
container is cleared when a dialog is removed from the dialog stack. Likewise, data that is stored in the conversationData
container and privateConversationData
container is cleared when the endConversation
method is called. However, to delete data stored in the userData
container, you have to explicitly clear it.
To explicitly clear the data that is stored in any of the storage containers, simply reset the container as shown in the following code sample.
// Clears data stored in container.
session.userData = {};
session.privateConversationData = {};
session.conversationData = {};
session.dialogData = {};
Never set a data container null
or remove it from the session
object, as doing so will cause errors the next time you try to access the container. Also, you may want to manually call session.save();
after you manually clear a container in memory, to clear any corresponding data that has previously been persisted.
Next steps
Now that you understand how to manage user state data, let's take a look at how you can use it to better manage conversation flow.