Use task modules from bots

Task modules can be invoked from Microsoft Teams bots using buttons on Adaptive Cards and Bot Framework cards that is hero, thumbnail, and Office 365 Connector. Task modules are often a better user experience than multiple conversation steps. Keep track of bot state and allow the user to interrupt or cancel the sequence.

There are two ways of invoking task modules:

  • A new kind of invoke message task/fetch: Using the invoke card action for Bot Framework cards, or the Action.Submit card action for Adaptive cards, with task/fetch, task module either a URL or an Adaptive Card, is fetched dynamically from your bot.
  • Deep link URLs: Using the deep link syntax for task modules, you can use the openUrl card action for Bot Framework cards or the Action.OpenUrl card action for Adaptive Cards, respectively. With deep link URLs, the task module URL or Adaptive Card body is already known to avoid a server round-trip relative to task/fetch.

Important

Each url and fallbackUrl must implement the HTTPS encryption protocol.

The next section provides details on invoking a task module using task/fetch.

Invoke a task module using task/fetch

When the value object of the invoke card action or Action.Submit is initialized and when a user selects the button, an invoke message is sent to the bot. In the HTTP response to the invoke message, there is a TaskInfo object embedded in a wrapper object, which Teams uses to display the task module.

task/fetch request or response

The following steps provides the invoke task module using task/fetch:

  1. This image shows a Bot Framework hero card with a Buy invoke card action. The value of the type property is task/fetch and the rest of the value object can be of your choice.

  2. The bot receives the invoke HTTP POST message.

  3. The bot creates a response object and returns it in the body of the POST response with an HTTP 200 response code. For more information on schema for responses, see the discussion on task/submit. The following code provides an example of body of the HTTP response that contains a TaskInfo object embedded in a wrapper object:

    {
      "task": {
        "type": "continue",
        "value": {
          "title": "Task module title",
          "height": 500,
          "width": "medium",
          "url": "https://contoso.com/msteams/taskmodules/newcustomer",
          "fallbackUrl": "https://contoso.com/msteams/taskmodules/newcustomer"
        }
      }
    }
    

    The task/fetch event and its response for bots is similar to the microsoftTeams.tasks.startTask() function in the client SDK.

  4. Microsoft Teams displays the task module.

The next section provides details on submitting the result of a task module.

Submit the result of a task module

When the user is finished with the task module, submitting the result back to the bot is similar to the way it works with tabs. For more information, see example of submitting the result of a task module. There are a few differences as follows:

  • HTML or JavaScript that is TaskInfo.url: Once you have validated what the user has entered, you call the microsoftTeams.tasks.submitTask() SDK function referred to hereafter as submitTask() for readability purposes. You can call submitTask() without any parameters if you want Teams to close the task module, but you must pass an object or a string to your submitHandler. Pass it as the first parameter, result. Teams invokes submitHandler, err is null, and result is the object or string you passed to submitTask(). If you call submitTask() with a result parameter, you must pass an appId or an array of appId strings. This allows Teams to validate that the app sending the result is the same one which invoked the task module. Your bot receives a task/submit message including result. For more information, see payload of task/fetch and task/submit messages.
  • Adaptive Card that is TaskInfo.card: The Adaptive Card body as filled in by the user is sent to the bot through a task/submit message when the user selects any Action.Submit button.

The next section provides details on the flexibility of task/submit.

The flexibility of task/submit

When the user finishes with a task module invoked from a bot, the bot always receives a task/submit invoke message. You have several options when responding to the task/submit message as follows:

HTTP body response Scenario
None ignore the task/submit message The simplest response is no response at all. Your bot is not required to respond when the user is finished with the task module.
{
"task": {
"type": "message",
"value": "Message text"
}
}
Teams displays the value of value in a pop-up message box.
{
"task": {
"type": "continue",
"value": <TaskInfo object>
}
}
Allows you to chain sequences of Adaptive Cards together in a wizard or multi-step experience.

Note

Chaining Adaptive Cards into a sequence is an advanced scenario. The Node.js sample app supports it. For more information, see Microsoft Teams task module Node.js.

The next section provides details on payload of task/fetch and task/submit messages.

Payload of task/fetch and task/submit messages

This section defines the schema of what your bot receives when it receives a task/fetch or task/submit Bot Framework Activity object. The following table provides the properties of payload of task/fetch and task/submit messages:

Property Description
type Is always invoke.
name Is either task/fetch or task/submit.
value Is the developer-defined payload. The structure of the value object is the same as what is sent from Teams. In this case, however, it is different. It requires support for dynamic fetch that is task/fetch from both Bot Framework, which is value and Adaptive Card Action.Submit actions, which is data. A way to communicate Teams context to the bot is required in addition to what is included in value or data.

Combine 'value' and 'data' into a parent object:

{
"context": {
"theme": "default" | "dark" | "contrast",
},
"data": [value field from Bot Framework card] | [data field from Adaptive Card]
}

The next section provides an example of receiving and responding to task/fetch and task/submit invoke messages in Node.js.

Example of task/fetch and task/submit invoke messages in Node.js and C#

handleTeamsTaskModuleFetch(context, taskModuleRequest) {
    // Called when the user selects an options from the displayed HeroCard or
    // AdaptiveCard.  The result is the action to perform.

    const cardTaskFetchValue = taskModuleRequest.data.data;
    var taskInfo = {}; // TaskModuleTaskInfo

    if (cardTaskFetchValue === TaskModuleIds.YouTube) {
        // Display the YouTube.html page
        taskInfo.url = taskInfo.fallbackUrl = this.baseUrl + '/' + TaskModuleIds.YouTube + '.html';
        this.setTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);
    } else if (cardTaskFetchValue === TaskModuleIds.CustomForm) {
        // Display the CustomForm.html page, and post the form data back via
        // handleTeamsTaskModuleSubmit.
        taskInfo.url = taskInfo.fallbackUrl = this.baseUrl + '/' + TaskModuleIds.CustomForm + '.html';
        this.setTaskInfo(taskInfo, TaskModuleUIConstants.CustomForm);
    } else if (cardTaskFetchValue === TaskModuleIds.AdaptiveCard) {
        // Display an AdaptiveCard to prompt user for text, and post it back via
        // handleTeamsTaskModuleSubmit.
        taskInfo.card = this.createAdaptiveCardAttachment();
        this.setTaskInfo(taskInfo, TaskModuleUIConstants.AdaptiveCard);
    }

    return TaskModuleResponseFactory.toTaskModuleResponse(taskInfo);
}

async handleTeamsTaskModuleSubmit(context, taskModuleRequest) {
    // Called when data is being returned from the selected option (see `handleTeamsTaskModuleFetch').

    // Echo the users input back.  In a production bot, this is where you'd add behavior in
    // response to the input.
    await context.sendActivity(MessageFactory.text('handleTeamsTaskModuleSubmit: ' + JSON.stringify(taskModuleRequest.data)));

    // Return TaskModuleResponse
    return {
        // TaskModuleMessageResponse
        task: {
            type: 'message',
            value: 'Thanks!'
        }
    };
}

setTaskInfo(taskInfo, uiSettings) {
    taskInfo.height = uiSettings.height;
    taskInfo.width = uiSettings.width;
    taskInfo.title = uiSettings.title;
}

Bot Framework card actions vs. Adaptive Card Action.Submit actions

The schema for Bot Framework card actions is different from Adaptive Card Action.Submit actions and the way to invoke task modules is also different. The data object in Action.Submit contains an msteams object so it does not interfere with other properties in the card. The following table shows an example of each card action:

Bot Framework card action Adaptive Card Action.Submit action
{
"type": "invoke",
"title": "Buy",
"value": {
"type": "task/fetch",
<...>
}
}
{
"type": "Action.Submit",
"id": "btnBuy",
"title": "Buy",
"data": {
<...>,
"msteams": {
"type": "task/fetch"
}
}
}

Code sample

Sample name Description .NET Node.js
Task module sample bots-V4 Samples for creating task modules. View View

See also