The Request and Initial Learnings

So you have been asked to make your company website or your company intranet website available in Teams… directly
from the left rail. That is, together with the Activity, Chat, Teams, Calendar, and other default Teams icons, you
want a button to allow your users access the Intranet directly from the main Teams window (figure below).


You take the first step and research how to do it. You find out that using an app called App Studio you can create something called manifest and also a Teams App, that combines the manifest and the icons you want to display on Teams. Nice!

You go ahead and install App Studio. Run it and click on the Create a new app in the Manifest editor tab.

You fill out the basic information for the app and then click Tabs under capabilities. That is the place where you will add your Personal Tab. The personal tab is the entity that will be used to link your website to the button/icon that will be displayed on the Microsoft Teams interface.

You call the personal tab Intranet, use an unique entity id and use both Content URL and Website URL fields to point to the website you want to link. For the purpose of this article, let’s use the ubiquitous web site (figure below).

Nice!!! We’re getting there. Now we need to install the app in Teams and test (before go through the whole process to publish the app to all company users). You save your tab, go to Test and Distribute under Finish and hit Install. Voilá… you now have the nice Intranet button on your Teams client. Ready to test!

But as any good feeling in IT is followed by a deception, it didn’t work.  You click your button and you just see a blank page. Nothing from the known website.

The Problem

So why website is not displaying on Teams (please replace by any website you are using and keep in mind that some websites work and some don’t).

But why am I getting a blank page? That is because and many other websites have a security feature that blocks them to be loaded inside an iFrame, and Teams personal tabs are implemented using an iFrame.

You can easily prove that is the issue with a simple html with an iFrame. Just save the content below as iframetest.html and open it in your browser.

Click here to download the iframetest.html file (code below).

You will see the following result:

Going a little further on the technical details, the reason behind is associated to a specific http header that is sent by the webserver hosting the website that doesn’t display ok. The header is called X-Frame-Options and with the value SAMEORIGIN, instructs your browser to block the display of the website in iFrames hosted outside websites with the same domain name of the website you want to display. So the iFrame would only work if hosted in any * website.

If you are curious you can use POSTMAN or Fiddler to check on the returned headers and verify by your own means.

OK. Problem understood, how can we still run the intranet (or inside Teams and have a button on the left rail pointing to the website?


First you need to understand that tabs in channels are not leveraging iFrames. Those tabs load websites just like your browser, so a site loaded by the Website app in a tab on a Teams channel is not subject to the X-Frame-Options restrictions.

Step 1 – Run your website on a tab in a channel inside a company wide team

So the first step in our solution is to create a company-wide team in Teams and create a tab in a channel using the Website app.

You will end up with the (or your website that is unable to run inside an iFrame, running on a tab inside a channel of your Teams team). In the case below I have the website running in a tab of the General channel in my team.

Step 2 – Copy the link to your tab

Now that you have your tab running the “protected” website, click on the … on the upper right and select the Copy link to tab option. Save the value that was stored in your clipboard in a notepad, you will need it for the next step.

Step 3 – Create the Deeplink Execution html

Now we will create a html file with a javascript code that will instruct teams to execute a deeplink to the tab where you have your website running. It is a pretty simple html that loads the Teams client SDK and execute a single instruction to navigate to the tab. You need to get the content below, edit it and replace the value indicated as [LINK TO THE TAB]with the value you saved on step 2.

Click here to download the index.html file (code below)

Step 4 – Make the file accessible

Now you need to make your file accessible from Teams. You app will call the html file and you need a way to serve the https request for that. There are many options. You can host the file in an Azure Blob (free for the first 12 months and then USD 0.01 per month for 1GB – list price on 1/7/2021), you can use AWS S3, Google Cloud storage, a webserver that you have on-prem… you choose.

In this tutorial I’m using an Azure Blob Storage. I loaded my html file into Visual Studio Code and installed the Azure Storage extension. With the extension I can do everything from Visual Studio Code.

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.

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…”.

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.

Now 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 /.

Click again on the Azure icon, expand storage, your subscription, right click the storage account and select Browse Static Website. You must see a blank page with the title “Teams Deep Link Example”.

Note that similar result can be achieved with any cloud storage service or even a on-premises web server that is capable to host a single static html page via HTTPS protocol.

Step 5 – Update your Teams App

Now you’re ready to go back to App Studio and replace the direct website URL you used by the one you browsed from Azure Blob storage.

Open the Teams client and run the App Studio. Click Manifest Editor and click the App you created previously. Click Tabs and edit the tab you created. In my case I’m replacing by which is the URL that points to my static web website hosted on Azure Blob storage.

Click Save. Click Test and distribute under Finish and re-install the app for test purposes. Now every time you click on the Intranet icon available on the left rail, the Teams client will execute the code in your html page and navigate to the tab where the website is loaded.

Thanks for reading this!


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.