Link unfurling

Important

The code samples in this section are based on 4.6 and later versions of the Bot Framework SDK. If you're looking for documentation for earlier versions, see the Message Extensions - v3 SDK section in the Resources folder of the documentation.

The document guides you on how to add link unfurling to your app manifest using Developer Portal and manually. With link unfurling, your app can register to receive an invoke activity when URLs with a particular domain are pasted into the compose message area. The invoke contains the full URL that was pasted into the compose message area, and you can respond with a card that the user can unfurl, providing additional information or actions. This works similar to a search command with the URL serving as the search term. You can now add link unfurling to Microsoft Teams without installing app.

Screenshot shows the link unfurling experience in a tree chat for a Teams app installed or not installed in Teams and other apps when the link is pasted in Teams compose message area.

Note

  • Currently, link unfurling is not supported on Mobile clients.
  • The link unfurling result is cached for 30 minutes.
  • Messaging extension commands are not required for Link unfurling. However, there must be at least one command in manifest as it is a mandatory property in messaging extensions. For more information, see compose extensions.

The following image is an example of link unfurling using the Azure DevOps message extension. When the Azure DevOps link is pasted into the Teams compose message area, the link unfurls into a card with the work item details:

Screenshot of link urfurling example for Azure Dev Ops links pasted in teams compose message area.

See the following video to learn more about link unfurling:


To add link unfurling to your app manifest, add a new messageHandlers array to the composeExtensions section of your app manifest JSON. You can add the array with the help of Developer Portal or manually. Domain listings can include wildcards, for example *.example.com. This matches exactly one segment of the domain; if you need to match a.b.example.com then use *.*.example.com.

Note

Ensure not to add domains that are not in your control, either directly or through wildcards. For example, yourapp.onmicrosoft.com is valid, but *.onmicrosoft.com is not valid. The top-level domains are prohibited, for example, *.com, *.org.

  1. Open Developer Portal from the Microsoft Teams client and then select the Apps tab.

    create new app in developer portal

    Note

    You need to add Developer Portal app, if you don't have it added in your Teams client.

    Add developer portal app

  2. Load your app manifest.

    load your app manifest

  3. Select Messaging Extension under App features and then either choose Select an existing bot or Create a new bot.

    Select messaging extension option

    select existing bot or create a new bot

  4. Select Save.

  5. Select Add a domain under Preview links section and then enter valid domain.

  6. Select Add. The following image explains the process:

    Screenshot of the message handlers section in Developer Portal.

Note

If authentication is added through Azure AD, unfurl links in Teams using bot.

First, you need to add the messageHandlers array to your app manifest and enable your message extension to interact with links. The following example explains how to add link unfurling manually:

...
{
  "composeExtensions": [
    {
      "botId": "abc123456-ab12-ab12-ab12-abcdef123456",
      "messageHandlers": [
        {
          "type": "link",
          "value": {
            "domains": [
              "*.trackeddomain.com"
            ]
          }
        }
      ]
    }
  ]
}
...

For a complete manifest example, see manifest reference.

After adding the domain to the app manifest, you must update your web service code to handle the invoke request. Use the received URL to search your service and create a card response. If you respond with more than one card, only the first card response is used.

The following card types are supported:

For more information, see Action type invoke.

The following is an example of the invoke request:

      protected override async Task<MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext<IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken)
      {
          //You'll use the query.link value to search your service and create a card response
          var card = new HeroCard
             {
              Title = "Hero Card",
              Text = query.Url,
              Images = new List<CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") },
          };

          var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, card);
          var result = new MessagingExtensionResult(AttachmentLayoutTypes.List, "result", new[] { attachments }, null, "test unfurl");

          return new MessagingExtensionResponse(result);
      }

Zero install link unfurling helps you unfurl previews for your shared links even before a user discovered or installed your app in Teams. You can anonymously unfurl cards with a new invoke request or create a pre-authenticated Adaptive Card preview for users before they install or authenticate your app.

The following image provides a sequential flow to enable and use zero install link unfurling:

Screenshot of the link unfurling code user flow.

To get your app ready for zero install link unfurling, follow these steps:

  1. Set the property supportsAnonymizedPayloads to true in the manifest schema.

  2. Set your app to handle the new invoke request composeExtension/anonymousQueryLink.

    Example of the new invoke request:

    Screenshot of the invoke request  `composeExtension/anonymousQueryLink` declaration in the manifest.

    Example of the invoke request payload:

    {
       "name":"composeExtension/anonymousQueryLink",
       "type":"invoke",
       "timestamp":"2021-12-02T08:12:21.148Z",
       "localTimestamp":"2021-12-02T00:12:21.148-08:00",
       "id":"f:43d59e15-6114-bd53-08c3-b232aa648ec1",
       "channelId":"msteams",
       "serviceUrl":"https://smba.trafficmanager.net/amer/",
       "from":{
          "id":"redacted",
          "name":"redacted"
       },
       "conversation":{
          "isGroup":true,
          "conversationType":"groupChat",
          "tenantId":"redacted",
          "id":" redacted",
          "name":" redacted"
       },
       "recipient":{
          "id":"28:85fa138c-7654-4236-86eb-466160687029",
          "name":"test bot"
       },
       "entities":[
          {
             "locale":"en-US",
             "country":"US",
             "platform":"Mac",
             "timezone":"America/Los_Angeles",
             "type":"clientInfo"
          }
       ],
       "channelData":{
          "tenant":{
             "id":" redacted"
          },
          "source":{
             "name":"compose"
          }
       },
       "value":{
          "url":"https://test.test.com/test"
       },
       "locale":"en-US",
       "localTimezone":"America/Los_Angeles"
    }
    
  3. Respond to the composeExtension/anonymousQueryLink payload.

    1. For non-auth scenarios: You need to send back a response with the type as result and a card. Use the following template:

      {
        "composeExtension": {
          "type": "result",
          "attachmentLayout": "list",
          "attachments": [
            {
              "contentType": "application/vnd.microsoft.teams.card.o365connector",
              "content": {
                "sections": [
                  {
                    "activityTitle": "[85069]: Create a cool app",
                    "activityImage": "https://placekitten.com/200/200"
                  },
                  {
                    "title": "Details",
                    "facts": [
                      {
                    "name": "Assigned to:",
                    "value": "[Larry Brown](mailto:larryb@example.com)"
                      },
                      {
                    "name": "State:",
                    "value": "Active"
                      }
                    ]
                  }
                 ]
               }
            }
          ]
        }
      }
      
    2. For auth scenarios: You need to send back a response with the type as auth with an optional pre-auth card in the attachments. Use the following template:

      {
         "composeExtension": {
            "type": "auth",
            "attachmentLayout": "list",
            "attachments": [
               {
                 "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                 "type": "AdaptiveCard",
                 "version": "1.5",
                 "actions": [],
                 "body": [
                   {
                     "type": "TextBlock",
                     "size": "medium",
                     "weight": "bolder",
                     "text": "Zero-install test app"
                  },
                  {
                     "type": "TextBlock",
                     "text": "Link your account with this app for a full experience",
                     "wrap": true
                  }
                 ]
               }
            ]
         }
      }
      
  4. Pre-auth card (for auth only): Create a card preview to unfurl your links for users who don't have your app installed. You can either create a pre-templated card or add relevant placeholder fields for the users to update. The users can learn about the app even before they’ve installed it.

    You can create customized card and add relevant fields. The users can fill in the required information as per the fields. The following image illustrates a customized card preview:

    Screenshot of the customized card with fields for user to update.

    The following image illustrates a default preview card:

    Screenshot of the link unfurling code default preview card.

    Note

    After the link is pasted in the message compose area, Teams unfurls the link into a card and prompts the user to sign in to the app. If the user doesn't sign in to the app, the link isn't posted as a card in the chat.

  5. Advantages and limitations:

    Zero install link unfurling helps you provide enhanced experience to the users, such as:

    • Unfurl previews for your links that users share in Teams even before they've installed your app.

    • Create a welcome card for your app to show a preview with the placeholder fields.

When a user shares a link in a meeting, the Teams app unfurls the link to an Adaptive Card. The link unfurling result is cached in Teams for 30 minutes. You can update your app to set a cache policy and remove cache for the app, which helps you to show different content in an Adaptive Card when the app's link is shared in a different context in Teams.

To remove link unfurling cache, update your bot with the type as setcachepolicy under the suggestedActions property. Teams doesn't cache the results for the app links with the "type": "setCachePolicy".

The following JSON payload example for suggestedActions property:

"suggestedActions": {
            "actions": [
                {
                    "type": "setCachePolicy",
                    "value": "{\"type\":\"no-cache\"}"
                }
            ]
        },

Step-by-step guide

Follow the step-by-step guide to unfurl links in Teams using bot.

See also