Send proactive messages in the v3 JavaScript SDK
APPLIES TO: SDK v3
Typically, each message that a bot sends to the user directly relates to the user's prior input. In some cases, a bot may need to send the user a message that is not directly related to the current topic of conversation or to the last message the user sent. These types of messages are called proactive messages.
Proactive messages can be useful in a variety of scenarios. If a bot sets a timer or reminder, it will need to notify the user when the time arrives. Or, if a bot receives a notification from an external system, it may need to communicate that information to the user immediately. For example, if the user has previously asked the bot to monitor the price of a product, the bot can alert the user if the price of the product has dropped by 20%. Or, if a bot requires some time to compile a response to the user's question, it may inform the user of the delay and allow the conversation to continue in the meantime. When the bot finishes compiling the response to the question, it will share that information with the user.
When implementing proactive messages in your bot:
- Don't send several proactive messages within a short amount of time. Some channels enforce restrictions on how frequently a bot can send messages to the user, and will disable the bot if it violates those restrictions.
- Don't send proactive messages to users who have not previously interacted with the bot or solicited contact with the bot through another means such as e-mail or SMS.
Proactive messages can create unexpected behavior. Consider the following scenario.
In this example, the user has previously asked the bot to monitor prices of a hotel in Las Vegas. The bot launched a background monitoring task, which has been running continuously for the past several days. In the conversation, the user is currently booking a trip to London when the background task triggers a notification message about a discount for the Las Vegas hotel. The bot interjects this information into the conversation, making for a confusing user experience.
How should the bot have handled this situation?
- Wait for the current travel booking to finish, then deliver the notification. This approach would be minimally disruptive, but the delay in communicating the information might cause the user to miss out on the low-price opportunity for the Las Vegas hotel.
- Cancel the current travel booking flow and deliver the notification immediately. This approach delivers the information in a timely fashion but would likely frustrate the user by forcing them start over with their travel booking.
- Interrupt the current booking, clearly change the topic of conversation to the hotel in Las Vegas until the user responds, and then switch back to the in-progress travel booking and continue from where it was interrupted. This approach may seem like the best choice, but it introduces complexity both for the bot developer and the user.
Most commonly, your bot will use some combination of ad hoc proactive messages and other techniques to handle situations like this.
Types of proactive messages
An ad hoc proactive message is the simplest type of proactive message. The bot simply interjects the message into the conversation whenever it is triggered, without any regard for whether the user is currently engaged in a separate topic of conversation with the bot and will not attempt to change the conversation in any way.
To handle notifications more smoothly, consider other ways to integrate the notification into the conversation flow, such as setting a flag in the conversation state or adding the notification to a queue.
Send an ad hoc proactive message
The following code samples show how to send an ad hoc proactive message by using the Bot Framework SDK for Node.js.
To be able to send an ad hoc message to a user, the bot must first collect and save information about the user from the current conversation. The address property of the message includes all of the information that the bot will need to send an ad hoc message to the user later.
bot.dialog('adhocDialog', function(session, args) {
var savedAddress = session.message.address;
// (Save this information somewhere that it can be accessed later, such as in a database, or session.userData)
session.userData.savedAddress = savedAddress;
var message = 'Hello user, good to meet you! I now know your address and can send you notifications in the future.';
session.send(message);
})
Note
The bot can store the user data in any manner as long as the bot can access it later.
After the bot has collected information about the user, it can send an ad hoc proactive message to the user at any time. To do so, it simply retrieves the user data that it stored previously, constructs the message, and sends it.
var inMemoryStorage = new builder.MemoryBotStorage();
var bot = new builder.UniversalBot(connector)
.set('storage', inMemoryStorage); // Register in-memory storage
function sendProactiveMessage(address) {
var msg = new builder.Message().address(address);
msg.text('Hello, this is a notification');
msg.textLocale('en-US');
bot.send(msg);
}
Tip
An ad hoc proactive message can be initiated like from asynchronous triggers such as http requests, timers, queues or from anywhere else that the developer chooses.
Send a dialog-based proactive message
The following code samples show how to send a dialog-based proactive message by using the Bot Framework SDK for Node.js. You can find the complete working example in the startNewDialog folder.
To be able to send a dialog-based message to a user, the bot must first collect (and save) information from the current conversation.
The session.message.address
object includes all of the information that the bot will need to send a dialog-based proactive message to the user.
// proactiveDialog dialog
bot.dialog('proactiveDialog', function (session, args) {
savedAddress = session.message.address;
var message = 'Hey there, I\'m going to interrupt our conversation and start a survey in five seconds...';
session.send(message);
message = `You can also make me send a message by accessing: https://localhost:${server.address().port}/api/CustomWebApi`;
session.send(message);
setTimeout(() => {
startProactiveDialog(savedAddress);
}, 5000);
});
When it is time to send the message, the bot creates a new dialog and adds it to the top of the dialog stack. The new dialog takes control of the conversation, delivers the proactive message, closes, and then returns control to the previous dialog in the stack.
// initiate a dialog proactively
function startProactiveDialog(address) {
bot.beginDialog(address, "*:survey");
}
Note
The code sample above requires a custom file, botadapter.js, which you can download from GitHub.
The survey dialog controls the conversation until it finishes.
Then, it closes (by calling session.endDialog()
), thereby returning control back to the previous dialog.
// handle the proactive initiated dialog
bot.dialog('survey', function (session, args, next) {
if (session.message.text === "done") {
session.send("Great, back to the original conversation");
session.endDialog();
} else {
session.send('Hello, I\'m the survey dialog. I\'m interrupting your conversation to ask you a question. Type "done" to resume');
}
});
Sample code
For a complete sample that shows how to send proactive messages using the Bot Framework SDK for Node.js, see the Proactive Messages sample in GitHub. Within the Proactive Messages sample, simpleSendMessage shows how to send an ad-hoc proactive message and startNewDialog shows how to send a dialog-based proactive message.