Gotchas writing Tabs for Teams

I had great fun last night presenting at the Sydney SharePoint User Group on an “Introduction to Customising Microsoft Teams with Tabs and Bots” (thanks John and Ivan for inviting me). I shamelessly stole the slides and code from Mike Ammerlaan’s excellent VS2017 Launch video Create awesome bots, connectors and tabs in Microsoft Teams.

In my session I demo’d creating a Tab for teams, based on the lab in the teams folder in the OfficeDev Training Content github repo. The lab’s based on the preview version, and since then Teams has gone to General Availability, so there are a few differences, most notably the mechanism for side-loading your tab (or bot) to test. There’s a good doc on the new process available on MSDN.

By the way, the documentation for Teams development is excellent – well worth a look from start to finish.

However, in addition to the new way of doing things, I cam across a couple of other non-intuitive hurdles that I think might cause others (including me, later) to stumble.

There are two places I came across errors that proved difficult to debug:

Error uploading the manifest for the tab to teams

This means there’s something wrong in the manifest file (or associated icons) .

The manifest is a json file (schema reference here). The instructions currently on GitHub require you to use version 0.2 of the schema, but the documentation is all for v0.4. This led to some issues with things like the length of the name property. v0.2 requires that the name property be no more than 16 characters, but I couldn’t find that documented anywhere. Fortunately, I was editing the manifest in VS Code, and it does json file schema validation. It alerted me to the place the error was happening with a green squiggly, so that made things easier to track down.


To upload the manifest, you zip it up with a couple of icon files (44x44 and 88x88 pixels) and here’s where I ran into another gotcha. If you include the icon files (you can reference external URLs instead), they must each be less than 1.5kb in size. Turns out this is not so simple for an 88x88pixel image. I use Syncfusion’s rather excellent (and free) Metro Studio to create my icons, but I really had to tweak some parameters to get the size down.

Any URLs in the manifest appear to be validated, not just checked that they’re a valid format, but actually hit to check that they exist. There were some placeholder URLs in the manifest when I originally uploaded it and I got a generic error. URLs in the manifest must be available when the the manifest is uploaded.

Here’s the manifest.json file that ended up working for me.

[sourcecode language='text'  padlinenumbers='true' toolbar='false']
    "$schema": "",
  "manifestVersion": "0.2",
   "id": "net.coatsy.instrument-sharing",
  "version": "1.0",
   "name": "Instrument Share",
 "developer": {
      "name": "Coatsy",
       "websiteUrl": "",
      "privacyUrl": "",
      "termsOfUseUrl": ""
  "description": {
        "short": "Host instrument inventory and relevant items as a tab.",
      "full": "Work with instrument & accessory inventory items as a tab."
  "icons": {
      "44": "inv44.png",
      "88": "inv88.png"
  "accentColor": "#223344",
   "configUrl": "",
 "canUpdateConfig": true,
    "needsIdentity": false,
 "validDomains": [


Error adding the tab to a channel

This means there’s something wrong on the configuration page.

Once the manifest’s been uploaded and validated, you need to add the new tab to a channel. Doing so displays the page specified in the manifest’s configUrl property. The configuration page allows you to collect any additional setting information and then save all of the configuration information for the tab with a javascript call back into the MicrosoftTeams.js library (API reference for this library is available on MSDN).

Once again, URLs in the configuration settings appear to be validated – they must be https and either be in the same domain as the settings page or from a domain whitelisted in the manifest’s validDomains list.

Here’s the configuration.html that ended up working for me.

[sourcecode language='html' ]


    <br>    microsoftTeams.initialize();<br>    microsoftTeams.settings.registerOnSaveHandler(function(saveEvent){<br>        microsoftTeams.settings.setSettings({<br>            entityId: "InstrumentSharing",<br>            contentUrl: "",<br>            suggestedDisplayName: "Instrument Sharing",<br>            websiteUrl: ""<br>        });<br>        saveEvent.notifySuccess();<br>    });<br>    microsoftTeams.settings.setValidityState(true);<br>    


More Troubleshooting Help

There are more troubleshooting tips in the MSDN documentation.