Widget tab

Embed the ElevenLabs agent widget in a Microsoft Teams tab for click-to-talk.

Overview

Host a small HTML page that loads the agent widget and surface it as a Teams tab. Users open the tab and talk to the agent in the Teams client — no phone number or telephony. This is the lightest-weight approach; use it for internal self-service assistants and demos.

The ElevenLabs agent widget open in a Microsoft Teams
tab

The agent widget running in a Teams tab

How it works

The widget is a web component. Teams renders a tab’s contentUrl inside a webview (iframe), so the widget runs exactly as it would on a website — including microphone capture, provided the page is allowed to embed in Teams and is granted media permission.

Teams user opens a tab whose webview iframes a hosted page running the ElevenLabs agent widget, which streams audio to ElevenLabs
Widget embedded in a Teams tab

Teams will not execute a raw <script> pasted into a chat, message, or Loop page. The widget script must live on a page you host, which Teams then embeds as a tab.

Requirements

  1. A public ElevenLabs agent with authentication disabled (Advanced tab of the agent settings). Widgets require this.
  2. An HTTPS host for a single static HTML file (Vercel, Netlify, Cloudflare Pages, Azure Static Web Apps, etc.).
  3. Permission in your tenant to upload a custom Teams app (Teams admin center → Manage apps → custom app upload), if you use the custom-tab option.

Step 1 — Create the widget page

Create agent-widget.html with the widget embed and your agent ID:

agent-widget.html
1<!doctype html>
2<html>
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>Voice Agent</title>
7 </head>
8 <body style="margin:0">
9 <elevenlabs-convai
10 agent-id="<replace-with-agent_7101k5zvyjhmfg983brhmhkd98n6>"
11 ></elevenlabs-convai>
12 <script
13 src="https://unpkg.com/@elevenlabs/convai-widget-embed"
14 async
15 type="text/javascript"
16 ></script>
17 </body>
18</html>

Deploy it to your HTTPS host and confirm it loads and the mic works in a normal browser first.

If your workspace is on a data residency environment, add the widget’s server-location attribute so it connects to your region — see widget customization for the supported values.

Test the page standalone in a browser before touching Teams. If the mic doesn’t work there, it won’t work in the Teams webview either.

Step 2 — Add it to Teams

You have two options, in increasing order of reliability for voice.

In a chat or channel, + Add a tab → Website, paste your HTTPS URL, and save.

The built-in Website tab sometimes opens the page as an external link rather than embedding it — and even when embedded, microphone access in the Teams desktop webview can be blocked. If voice fails, use Option B.

A tiny custom Teams app declares the page as a static tab and requests media permission, which is what makes the microphone work reliably inside Teams.

1

Create the manifest

Create manifest.json. Replace your-domain.com with your host and set a unique GUID for id:

manifest.json
1{
2 "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json",
3 "manifestVersion": "1.19",
4 "version": "1.0.0",
5 "id": "11111111-1111-1111-1111-111111111111",
6 "developer": {
7 "name": "ElevenLabs",
8 "websiteUrl": "https://your-domain.com",
9 "privacyUrl": "https://your-domain.com/privacy",
10 "termsOfUseUrl": "https://your-domain.com/terms"
11 },
12 "name": { "short": "Voice Agent", "full": "ElevenLabs Voice Agent" },
13 "description": {
14 "short": "ElevenLabs voice agent",
15 "full": "Embedded ElevenLabs voice agent"
16 },
17 "icons": { "outline": "outline.png", "color": "color.png" },
18 "accentColor": "#000000",
19 "staticTabs": [
20 {
21 "entityId": "voice-agent",
22 "name": "Voice Agent",
23 "contentUrl": "https://your-domain.com/agent-widget.html",
24 "websiteUrl": "https://your-domain.com/agent-widget.html",
25 "scopes": ["personal"]
26 }
27 ],
28 "devicePermissions": ["media"],
29 "validDomains": ["your-domain.com", "unpkg.com", "elevenlabs.io", "*.elevenlabs.io"]
30}

The key fields for voice are devicePermissions: ["media"] (microphone) and listing every domain the page touches in validDomains (unpkg.com for the widget script, *.elevenlabs.io for the agent).

2

Package the app

Add a color.png (192×192) and outline.png (32×32, transparent) next to the manifest, then zip the manifest and the two icons at the root of the archive:

$zip -j voice-agent.zip manifest.json color.png outline.png
3

Upload and open

In Teams: Apps → Manage your apps → Upload an app → Upload a custom app, select voice-agent.zip, then open the Voice Agent tab and grant microphone access when prompted.

Teams admins can skip the client UI and publish the app to the whole org from PowerShell — it then shows up for everyone under Apps → Built for your org:

1Connect-MicrosoftTeams
2New-TeamsApp -DistributionMethod organization -Path ./voice-agent.zip

If no prompt appears, open the tab’s dropdown and choose App permissions to grant microphone access manually:

The Teams tab dropdown menu with App permissions
highlighted

Tab dropdown → App permissions

Step 3 — Allow Teams to embed the page

Your host must permit Teams to iframe the page. If you control response headers, set:

1Content-Security-Policy: frame-ancestors 'self' https://teams.microsoft.com https://*.teams.microsoft.com https://*.cloud.microsoft;

If Teams keeps opening the page in a browser instead of embedding it, the page is being blocked from iframe embedding — fix the CSP / X-Frame-Options on your host.

Troubleshooting

The page is blocked from being iframed. Remove any X-Frame-Options: DENY/SAMEORIGIN and set the frame-ancestors CSP shown above to allow the Teams domains. The custom tab app (Option B) is also more reliable than the built-in Website tab.

This is the Teams webview permission layer. Use the custom tab app with "devicePermissions": ["media"], and grant the app microphone permission in Teams (tab dropdown → App permissions). Teams web and Teams desktop behave differently — test both. As a fallback, offer an “Open in browser” link.

Confirm the agent is public with authentication disabled (agent Advanced settings), and that unpkg.com and *.elevenlabs.io are in the manifest validDomains.