A few weeks ago I published an article here explaining how to use Power Apps to extend meetings in Teams. Power Apps is super easy and powerful, but so far it doesn’t provide access to all Teams meetings extensibility APIs. The only thing we can basically do with Power Apps currently is place the app in a panel that runs during meetings or work with the pre/post tabs to deliver experiences.

This time I want to provide a simple step by step approach to create meetings extensibility experiences on its full potential. For that we will need traditional web development. I’ll try to keep things simple and at the same time bring new cloud concepts so you can learn new things reading the article.

First a few concepts

If you search for meetings extensibility APIs documentation you will find that currently we can create apps to interact with teams meetings in many ways. We can call the Graph API and create meetings, we can get meeting information also using Graph API, and we can also create apps that interact with meetings in pre/during/post moments.

Meetings extensibility apps (the ones that run pre/during/post meetings) can basically call three APIs to get information about the meeting, its participants and to create pop-up notifications.

Pre and post meetings experiences are implemented by your app running in a tab configured in the meeting invite.

Pre-Meeting Application running in an invite tab

pre-meeting tab view

Post-Meeting Application running in an invite tab

post meeting view

During meetings, apps can run on a side panel or create pop-up notifications to interface with users.

In-Meeting Side Panel AppIn-meeting-dialog view

In-Meeting Pop-Up notification

in-meeting experience

How to create my first meetings extensibility app

As I said, let’s keep things simple. Let’s focus on creating a pre-meeting tab and learn how to call the APIs so we can get your first meeting extensibility app running inside teams.

Requirements

Uploading the Aample App

  • Create a folder where you will place all your app files. We will create three files:
    • main.css will have the styles that we will use in the html single page application we are creating.
    • index.html will have the single page application (html and JavaScript) that we will use for the main app.
    • config.html will have the configuration page for the app.
  • Open a command prompt, navigate to the folder you created and type “code .”
  • Click File, New File.
  • Paste the following code:
body {
    font-family: monospace;
}

ul {
    font-family: helvetica;
}

li {
    list-style: circle;
  }
  
.list {
    list-style: square;
  }
  
#msg {
    font-family: monospace;
}
  • Save the file as main.css.
  • Click File, New File.
  • Paste the following code:
<!DOCTYPE html>
<html>
<head>
    <script src= 'https://statics.teams.cdn.office.net/sdk/v1.6.0/js/MicrosoftTeams.min.js'></script>
    <meta charset="UTF-8">
    <title>Teams - Really Simple Meetings Extensibility SPA - Config Page</title>
    <link rel="stylesheet" href="main.css">
</head>

<body>
    <h1>Config Page</h1>
    <h2>Present some configuration options here and let the person who is configuring the app change settings.</h2>
    <h2>Icons, colors, differente content pages, etc</h2>

    <script>

    microsoftTeams.initialize();
    microsoftTeams.settings.setSettings({
        contentUrl: "https://m365x257948blogpost1.z22.web.core.windows.net/index.html",
        entityId: "123456",
        suggestedDisplayName: "Meeting Panel",
        websiteUrl: "https://m365x257948blogpost1.z22.web.core.windows.net/index.html"
    });
    microsoftTeams.settings.setValidityState(true);
    
    </script>
</html>
  • Save the file as config.html. Note that we will return to this file later to update the contentUrl and websiteUrl with the URL of the index.html file.
  • Click File, New File.
  • Paste the following code:
<!DOCTYPE html>
<html>
<head>
    <script src= 'https://statics.teams.cdn.office.net/sdk/v1.6.0/js/MicrosoftTeams.min.js'></script>
    <meta charset="UTF-8">
    <title>Teams - Really Simple Meetings Extensibility SPA</title>
    <link rel="stylesheet" href="main.css">
</head>

<body>

    <!-- html -->
    <h1 id='h1title'></h1>
    <table>
        <tr><td>User: </td><td><div id='userid'></div></td></tr>
        <tr><td>Theme: </td><td><div id='theme'></div></td></tr>
        <tr><td>MeetingId: </td><td><div id='meetingid'></div></td></tr>
        <tr><td>FrameContext: </td><td><div id='framecontext'></div></td></tr>
    </table>
    <!-- html -->

    <script>
    let h1 = document.getElementById('h1title');
    
    //initializes Teams SDK
    microsoftTeams.initialize();
    
    //gets the user context using Teams SDK
    microsoftTeams.getContext((context) =>{
        let userId = document.getElementById('userid');
        let theme = document.getElementById('theme');
        let meetingId = document.getElementById('meetingid');
        let frame = document.getElementById('framecontext');

        //updates the divs in the table with the context variables
        userId.innerHTML = context.userPrincipalName;
        theme.innerHTML = context.theme;
        meetingId.innerHTML = context.meetingId;
        frame.innerHTML = context.frameContext;

        //checks if the tab is running on the panel or in pre-meeting
        if (context.frameContext == 'content') {
            h1.innerHTML = 'This is the pre-meeting experience';
        } else {
            h1.innerHTML = 'This is the side panel content';
        }
    });
    </script>
</html>
  • Save the file as index.html.
  • Click the Azure icon on the left rail in VS Code. Expand Storage and then your Azure subscription. Right click the subscription and select Create Storage Account.
image_thumb.png
  • Provide a name for your storage and click Enter. Wait until the storage account is created in your subscription. When the storage account is created, right click it and select the “Configure Static Website…”.
image.png
  • Press Enter to confirm index.html as the index document name (you will need to upload the file as index.html). And press Enter to confirm the default value for the 404 error message. Wait until the storage is configured to host static websites.
  • Go back to the VS Code Explorer and right click the index.html file (the file you created/edited). Select “Upload to Azure Storage…”. Select your subscription and the storage account you created and configured. Select Blob Containers, then $Web, then /.
  • Your files will be uploaded to the Azure Storage.
  • Click the Azure icon on the left rail in VS Code. Expand Storage and then your Azure subscription. Right click the Storage you created and select Browse Static Website. In your browser, copy the URL of the website.
  • Now edit the config.html file and paste the value you copied on contentUrl and websiteUrl
  • Upload the config.html and the main.css files to the Azure Storage. You need to right click the files and select the option to Upload to Azure Storage. Select your subscription and the storage account you created and configured. Select Blob Containers, then $Web, then /.

Creating the Teams Manifest

Now that you have the sample application already uploaded to the Azure Storage, we need to configure a teams manifest to make it available inside Teams. 

  • Download the sample manifest file here. 
  • Unzip the file and edit the manifest.json file.
  • Change the value of configurationUrl to point to the URL of your config.html file. Remember that it is the base URL of your Azure Storage + /config.html.
  • Replace the value you will find in validDomain by the base URL you have for your Azure Storage. Please note that validDomain doesn’t need the https:// on the beginning of the value.
  • Save the json file. 
  • Zip the manifest.json file together with the two icons you have on the original zip package. Make sure all files are in the root of the zip file.
  • Now open your teams client and load the zip file as an app. You need to click apps, then Upload a Custom App.
  • Remember this is a meetings extensibility app, so it will be available to be included in calendar items when you invite someone for a meeting.

When creating the meeting, inviting someone and adding the app, you will get the configuration message and need to click Save. As soon as you do that, the application will be incorporated into the meeting invite and you will see the screen below.

Screenshot 2021-02-23 170858

Note that if you join the meeting, the app will be available to run as soon as you click on the icon that is available on the top right corner.

Screenshot 2021-02-23 171132

What I’ve Done?

Well. Now some context on what you just finished. Your app is a simple HTML page (a single page application) that uses JavaScript to call the Teams Client SDK. The latest version of the SDK has one of the APIs that we use for Teams meetings extensibility apps.

That is the API to get the user context. 

Screenshot 2021-02-23 171527

The user context provides some properties you use for your application. For example you know using the FrameContext property if the application is running in the pre/post meeting tab or in the in-meeting side panel. That is important so you can make your application behave appropriately depending on where your users are using it.

Another important property is the MeetingID. When you have the meeting identification you can call other APIs and get data about the invite or other properties of the meeting. You also have access to the theme used in Teams as well as the user name running your app.

The list of properties returned by the microsoftTeams.getContext API is available at Get context for your tab – Teams | Microsoft Docs

Now I invite you to check the code and discover where in the index.html we are calling the getContext API. You will see that it is a simple JavaScript call to the Teams Client SDK.

The other APIs available to get the role of the user in the meeting and to create notification popups will be object of the part 2 of this article.

Have fun and thanks for reading!

Cristiano

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.