Updates from: 10/13/2022 04:57:04
Service Microsoft Docs article Related commit history on GitHub Change details
platform Meeting App Extensibility https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/meeting-app-extensibility.md
A meeting lifecycle consists of pre-meeting, in-meeting, and post-meeting app ex
> [!NOTE] >
-> * Apps for instant meetings, scheduled public channel meetings, one-on-one, and group calls are currently available only in [public developer preview](../resources/dev-preview/developer-preview-intro.md).
+> * Apps for scheduled public channel meetings are currently available only in [public developer preview](../resources/dev-preview/developer-preview-intro.md).
> > * Meeting extensions such as bots, cards, message extensions, and message actions are supported in the web client. However, hosted experiences such as tabs, content bubbles, and share to stage are not currently fully supported.
platform Teams Apps In Meetings https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-apps-in-meetings.md
Meetings enable collaboration, partnership, informed communication, and shared f
> [!NOTE] >
-> Apps for instant meetings, scheduled public channel meetings, one-on-one, and group calls are currently available only in [public developer preview](../resources/dev-preview/developer-preview-intro.md).
+> * Apps for scheduled public channel meetings are currently available only in [public developer preview](../resources/dev-preview/developer-preview-intro.md).
+>
+> * Apps aren't supported in [Public Switched Telephone Network (PSTN)](/microsoftteams/cloud-voice-landing-page#public-switched-telephone-network-connectivity-options) and [end-to-end encrypted Teams calls](https://support.microsoft.com/office/use-end-to-end-encryption-for-teams-calls-1274b4d2-b5c5-4b24-a376-606fa6728a90).
Teams supports access to apps during meeting for the following meeting types:
platform Teams Live Share Canvas https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-canvas.md
+
+ Title: Live Share canvas overview
+
+description: In this module, learn more about Live Share canvas, an extension enabling inking, laser pointers, and cursors for meeting apps.
+
+ms.localizationpriority: high
+ Last updated : 10/04/2022++
+# Live Share canvas overview
++
+In conference rooms and classrooms across the globe, whiteboards are a pivotal part of collaboration. In modern times however, the whiteboard is no longer enough. With numerous digital tools such as PowerPoint being the focal point of collaboration in the modern era, it's essential to enable the same creative potential.
+
+To enable more seamless collaboration, Microsoft created PowerPoint Live, which has become instrumental to how people work in Teams. Presenters can annotate over slides for everyone to see, using pens, highlighters, and laser pointers to draw attention to key concepts. Using Live Share canvas, your app can bring the power of PowerPoint Live inking tools with minimal effort.
+
+## Install
+
+To add the latest version of the SDK to your application using npm:
+
+```bash
+npm install @microsoft/live-share@next --save
+npm install @microsoft/live-share-canvas@next --save
+```
+
+OR
+
+To add the latest version of the SDK to your application using [Yarn](https://yarnpkg.com/):
+
+```bash
+yarn add @microsoft/live-share@next
+yarn add @microsoft/live-share-canvas@next
+```
+
+## Setting up the package
+
+Live Share canvas has two primary classes that enable turn-key collaboration: `InkingManager` and `LiveCanvas`. `InkingManager` is responsible for attaching a fully-featured `<canvas>` element to your app, while `LiveCanvas` manages the remote synchronization with other meeting participants. Used together, your app can have complete whiteboard-like functionality in just a few lines of code.
+
+| Classes | Description |
+| | |
+| [InkingManager](/javascript/api/@microsoft/live-share-canvas/inkingmanager) | Class that attaches a `<canvas>` element to a given `<div>` to automatically manage pen or highlighter strokes, laser pointer, lines and arrows, and erasers. Exposes a set of APIs (to control which tool is active) and basic configuration settings. |
+| [LiveCanvas](/javascript/api/@microsoft/live-share-canvas/livecanvas) | A `SharedObject` class that synchronizes strokes and cursor positions from `InkingManager` for everyone in a Live Share session. |
+
+Example:
+
+```html
+<body>
+ <div id="canvas-host"></div>
+</body>
+```
+
+# [JavaScript](#tab/javascript)
+
+```javascript
+import { LiveShareClient } from "@microsoft/live-share";
+import { InkingManager, LiveCanvas } from "@microsoft/live-share-canvas";
+
+// Setup the Fluid container
+const liveShare = new LiveShareClient();
+const schema = {
+ initialObjects: { liveCanvas: LiveCanvas },
+};
+const { container } = await liveShare.joinContainer(schema);
+const { liveCanvas } = container.initialObjects;
+
+// Get the canvas host element
+const canvasHostElement = document.getElementById("canvas-host");
+const inkingManager = new InkingManager(canvasHostElement);
+
+// Begin synchronization for LiveCanvas
+await liveCanvas.initialize(inkingManager);
+```
+
+# [TypeScript](#tab/typescript)
+
+```TypeScript
+import { LiveShareClient } from "@microsoft/live-share";
+import { InkingManager, LiveCanvas } from "@microsoft/live-share-canvas";
+import { ContainerSchema } from "fluid-framework";
+
+// Setup the Fluid container
+const liveShare = new LiveShareClient();
+const schema: ContainerSchema = {
+ initialObjects: { liveCanvas: LiveCanvas },
+};
+const { container } = await liveShare.joinContainer(schema);
+const liveCanvas = container.initialObjects.liveCanvas as LiveCanvas;
+
+// Get the canvas host element
+const canvasHostElement = document.getElementById("canvas-host");
+const inkingManager = new InkingManager(canvasHostElement);
+
+// Begin synchronization for LiveCanvas
+await liveCanvas.initialize(inkingManager);
+```
+++
+## Canvas tools and cursors
+
+Now that the Live Share canvas is set up and synchronizing, you can configure the canvas for user interaction, such as buttons to select a pen tool. In this section, we'll discuss what tools are available and how to use them.
+
+### Inking tools
+
+Each inking tool in Live Share canvas renders strokes as users draw. If using a touch screen or stylus, the tools also support pressure dynamics, affecting stroke width. Configuration settings include brush color, thickness, shape, and an optional end arrow.
+
+#### Pen tool
++
+The pen tool draws solid strokes that are stored into the canvas. The default tip shape is a circle.
+
+```html
+<div>
+ <button id="pen">Enable Pen</button>
+ <label for="pen-color">Select a color:</label>
+ <input type="color" id="color" name="color" value="#000000" />
+ <button id="pen-tip-size">Increase pen size</button>
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+ fromCssColor,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to pen
+document.getElementById("pen").onclick = () => {
+ inkingManager.tool = InkingTool.pen;
+};
+// Change the selected color for pen
+document.getElementById("pen-color").onchange = () => {
+ const colorPicker = document.getElementById("color");
+ inkingManager.penBrush.color = fromCssColor(colorPicker.value);
+};
+// Increase the tip size for pen
+document.getElementById("pen-tip-size").onclick = () => {
+ inkingManager.penBrush.tipSize = inkingManager.penBrush.tipSize + 1;
+};
+```
+
+#### Highlighter tool
++
+The highlighter tool draws translucent strokes that are stored into the canvas. The default tip shape is a square.
+
+```html
+<div>
+ <button id="highlighter">Enable Highlighter</button><br />
+ <label for="highlighter-color">Select a color:</label>
+ <input type="color" id="highlighter-color" name="highlighter-color" value="#FFFC00" />
+ <button id="highlighter-tip-size">Increase tip size</button>
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+ fromCssColor,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to highlighter
+document.getElementById("highlighter").onclick = () => {
+ inkingManager.tool = InkingTool.highlighter;
+};
+// Change the selected color for highlighter
+document.getElementById("highlighter-color").onchange = () => {
+ const colorPicker = document.getElementById("highlighter-color");
+ inkingManager.highlighterBrush.color = fromCssColor(colorPicker.value);
+};
+// Increase the tip size for highlighter
+document.getElementById("highlighter-tip-size").onclick = () => {
+ inkingManager.highlighterBrush.tipSize = inkingManager.penBrush.tipSize + 1;
+};
+```
+
+#### Eraser tool
++
+The eraser tool erases entire strokes that cross its path.
+
+```html
+<div>
+ <button id="eraser">Enable Eraser</button><br />
+ <button id="eraser-size">Increase eraser size</button>
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to eraser
+document.getElementById("eraser").onclick = () => {
+ inkingManager.tool = InkingTool.eraser;
+};
+// Increase the tip size for eraser
+document.getElementById("eraser-size").onclick = () => {
+ inkingManager.eraserSize = inkingManager.eraserSize + 1;
+};
+```
+
+#### Point eraser tool
++
+The point eraser tool erases individual points within strokes that cross its path by splitting existing strokes in half. This tool is computationally expensive and may result in slower frame rates for your users.
+
+> [!NOTE]
+> The point eraser shares the same eraser point size as the regular eraser tool.
+
+```html
+<div>
+ <button id="point-eraser">Enable Point Eraser</button><br />
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to eraser
+document.getElementById("point-eraser").onclick = () => {
+ inkingManager.tool = InkingTool.pointEraser;
+};
+```
+
+#### Laser pointer
++
+The laser pointer is unique as the tip of the laser has a trailing effect as you move your mouse. When you draw strokes, the trailing effect renders for a short period before it fades out completely. This tool is perfect to point out information on the screen during a meeting, as the presenter doesn't have to switch between tools to erase strokes.
+
+```html
+<div>
+ <button id="laser">Enable Laser Pointer</button><br />
+ <label for="laser-color">Select a color:</label>
+ <input type="color" id="laser-color" name="laser-color" value="#000000" />
+ <button id="laser-tip-size">Increase tip size</button>
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+ fromCssColor,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to laser pointer
+document.getElementById("laser").onclick = () => {
+ inkingManager.tool = InkingTool.highlighter;
+};
+// Change the selected color for laser pointer
+document.getElementById("laser-color").onchange = () => {
+ const colorPicker = document.getElementById("laser-color");
+ inkingManager.laserPointerBrush.color = fromCssColor(colorPicker.value);
+};
+// Increase the tip size for laser pointer
+document.getElementById("laser-tip-size").onclick = () => {
+ inkingManager.laserPointerBrush.tipSize = inkingManager.laserPointerBrush.tipSize + 1;
+};
+```
+
+#### Line and arrow tools
++
+The line tool allows users to draw straight lines from one point to another, with an optional arrow that can be applied to the end.
+
+```html
+<div>
+ <button id="line">Enable Line</button><br />
+ <button id="line-arrow">Enable Arrow</button><br />
+ <input type="color" id="line-color" name="line-color" value="#000000" />
+ <button id="line-tip-size">Increase tip size</button>
+</div>
+```
+
+```javascript
+import {
+ InkingManager,
+ InkingTool,
+ fromCssColor,
+} from "@microsoft/live-share-canvas";
+// ...
+
+// Change the selected tool to line
+document.getElementById("line").onclick = () => {
+ inkingManager.tool = InkingTool.line;
+ inkingManager.lineBrush.endArrow = "none";
+};
+// Change the selected tool to line
+document.getElementById("line-arrow").onclick = () => {
+ inkingManager.tool = InkingTool.line;
+ inkingManager.lineBrush.endArrow = "open";
+};
+// Change the selected color for lineBrush
+document.getElementById("line-color").onchange = () => {
+ const colorPicker = document.getElementById("line-color");
+ inkingManager.lineBrush.color = fromCssColor(colorPicker.value);
+};
+// Increase the tip size for lineBrush
+document.getElementById("line-tip-size").onclick = () => {
+ inkingManager.lineBrush.tipSize = inkingManager.lineBrush.tipSize + 1;
+};
+```
+
+#### Clear all strokes
+
+You can clear all strokes in the canvas by calling `inkingManager.clear()`. This deletes all strokes from the canvas.
+
+### Cursors
++
+You can enable live cursors in your application for users to track each other's cursor positions on the canvas. Unlike the inking tools, cursors operate entirely through the `LiveCanvas` class. You can optionally provide a name and picture to identify each user. You can enable cursors separately or with the inking tools.
+
+```javascript
+// Optional. Set user display info
+liveCanvas.onGetLocalUserInfo = () => {
+ return {
+ displayName: "YOUR USER NAME",
+ pictureUri: "YOUR USER PICTURE URI",
+ };
+};
+// Toggle Live Canvas cursor enabled state
+liveCanvas.isCursorShared = !isCursorShared;
+```
+
+## Optimizing across devices
+
+For most applications on the web, content renders differently depending on the screen size or varying application state. If `InkingManager` isn't optimized correctly for your app, it might cause strokes and cursors to appear differently for each user. Live Share canvas supports a simple set of APIs, which allows the `<canvas>` to adjust stroke positions to align correctly with your content.
+
+By default, Live Share canvas works a lot like a whiteboard app, with the content being center aligned to the viewport with a 1x zoom level. Only part of the content is being rendered within the visible bounds of the `<canvas>`. Conceptually, it's like recording a video from bird's-eye view. While the viewport of the camera is recording a portion of the world beneath it, the real world stretches nearly infinitely in every direction.
+
+Here's a simple diagram to help visualize this concept:
++
+You can customize this behavior in the following ways:
+
+- Changing the starting reference point to the top-left corner of the canvas.
+- Alter the pixel offset x and y positions of the viewport.
+- Change the scale level of the viewport.
+
+> [!NOTE]
+> Reference points, offsets, and scale levels are local to the client and aren't synchronized across meeting participants.
+
+Example:
+
+```html
+<body>
+ <button id="pan-left">Pan left</button>
+ <button id="pan-up">Pan up</button>
+ <button id="pan-right">Pan right</button>
+ <button id="pan-down">Pan down</button>
+ <button id="zoom-out">Zoom out</button>
+ <button id="zoom-in">Zoom in</button>
+ <button id="change-reference">Change reference</button>
+</body>
+```
+
+```javascript
+// ...
+
+// Pan left
+document.getElementById("pan-left").onclick = () => {
+ inkingManager.offset = {
+ x: inkingManager.offset.x - 10,
+ y: inkingManager.offset.y,
+ };
+};
+// Pan up
+document.getElementById("pan-up").onclick = () => {
+ inkingManager.offset = {
+ x: inkingManager.offset.x,
+ y: inkingManager.offset.y - 10,
+ };
+};
+// Pan right
+document.getElementById("pan-right").onclick = () => {
+ inkingManager.offset = {
+ x: inkingManager.offset.x + 10,
+ y: inkingManager.offset.y,
+ };
+};
+// Pan down
+document.getElementById("pan-down").onclick = () => {
+ inkingManager.offset = {
+ x: inkingManager.offset.x,
+ y: inkingManager.offset.y + 10,
+ };
+};
+// Zoom out
+document.getElementById("zoom-out").onclick = () => {
+ if (inkingManager.scale > 0.1) {
+ inkingManager.scale -= 0.1;
+ }
+};
+// Zoom in
+document.getElementById("zoom-in").onclick = () => {
+ inkingManager.scale += 0.1;
+};
+// Change reference
+document.getElementById("change-reference").onclick = () => {
+ if (inkingManager.referencePoint === "center") {
+ inkingManager.referencePoint = "topLeft";
+ } else {
+ inkingManager.referencePoint = "center";
+ }
+};
+```
+
+## Ideal scenarios
+
+With web pages coming in all shapes and sizes, it isn't possible to make Live Share canvas to support every scenario. The package is ideal for scenarios in which all users are looking at the same content at the same time. While not all the content needs to be visible on the screen, it must be content that scales across devices linearly.
+
+Here are a couple examples of scenarios where Live Share canvas is a great option for your application:
+
+- Overlay images and videos that render with the same aspect ratio on all clients.
+- Viewing a map, 3D model, or whiteboard from the same rotation angle.
+
+Both the scenarios work well because the content can be viewed the same on all devices even if the users are looking at it with different zoom levels and offsets. If your app's layout or content changes depending on screen size and it isn't possible to generate a common view for all participants, Live Share canvas might not be a good fit for your scenario.
+
+## Code samples
+
+| Sample name | Description | JavaScript |
+| -- | -- | -- |
+| Live Canvas demo | Simple whiteboard application. | [View](https://github.com/microsoft/live-share-sdk/tree/main/samples/03.live-canvas-demo) |
+| React media template | Draw over a synchronized video player. | [View](https://aka.ms/liveshare-mediatemplate) |
+
+## Next step
+
+> [!div class="nextstepaction"]
+> [Agile Poker tutorial](../sbs-teams-live-share.yml)
+
+## See also
+
+- [Live Share SDK FAQ](teams-live-share-faq.md)
+- [Live Share SDK reference docs](/javascript/api/@microsoft/live-share/)
+- [Live Share Canvas SDK reference docs](/javascript/api/@microsoft/live-share-canvas/)
+- [Teams apps in meetings](teams-apps-in-meetings.md)
platform Teams Live Share Capabilities https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-capabilities.md
Title: Live Share getting started
-description: In this module, learn more about live share SDK capabilities, RSC permissions and ephermal data structures.
+description: In this module, learn more about live share SDK capabilities, RSC permissions and live data structures.
ms.localizationpriority: high
Last updated 04/07/2022
# Live Share core capabilities
-The Live Share SDK can be added to your meeting extension's `sidePanel` and `meetingStage` contexts with minimal effort. This article focuses on how to integrate the Live Share SDK into your app and key capabilities of the SDK.
-
-> [!NOTE]
-> Currently, only scheduled meetings are supported, and all participants must be on the meeting calendar. Meeting types such as, one-on-one calls, group calls, and meet now are currently not supported.
+The Live Share SDK can be added to your meeting extension's `sidePanel` and `meetingStage` contexts with minimal effort. This article focuses on how to integrate the Live Share SDK into your app and key capabilities of the SDK.
## Install the JavaScript SDK
The [Live Share SDK](https://github.com/microsoft/live-share-sdk) is a JavaScrip
### npm ```bash
-npm install @microsoft/live-share --save
+npm install @microsoft/live-share@next --save
``` ### yarn ```bash
-yarn add @microsoft/live-share
+yarn add @microsoft/live-share@next
``` ## Register RSC permissions
To enable the Live Share SDK for your meeting extension, you must first add the
// ...rest of your manifest here "configurableTabs": [ {
- "configurationUrl": "https://<<BASE_URI_ORIGIN>>/config",
- "canUpdateConfiguration": false,
+ "configurationUrl": "<<YOUR_CONFIGURATION_URL>>",
+ "canUpdateConfiguration": true,
"scopes": [ "groupchat" ],
To enable the Live Share SDK for your meeting extension, you must first add the
## Join a meeting session
-Follow the steps to join a session that is associated with a user's meeting:
+Follow the steps to join a session that's associated with a user's meeting:
-1. Initialize the Teams Client SDK.
-2. Initialize the [TeamsFluidClient](/javascript/api/@microsoft/live-share/teamsfluidclient).
-3. Define the data structures you want to synchronize. For example, `SharedMap`.
-4. Join the container.
+1. Initialize [LiveShareClient](/javascript/api/@microsoft/live-share/liveshareclient).
+2. Define the data structures you want to synchronize. For example, `SharedMap`.
+3. Join the container.
Example: # [JavaScript](#tab/javascript) ```javascript
-import * as microsoftTeams from "@microsoft/teams-js";
-import { TeamsFluidClient } from "@microsoft/live-share";
+import { LiveShareClient } from "@microsoft/live-share";
import { SharedMap } from "fluid-framework";
-// Initialize the Teams Client SDK
-await microsoftTeams.app.initialize();
- // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: { exampleMap: SharedMap }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
const { container } = await client.joinContainer(schema);
# [TypeScript](#tab/typescript) ```TypeScript
-import * as microsoftTeams from "@microsoft/teams-js";
-import { TeamsFluidClient } from "@microsoft/live-share";
+import { LiveShareClient } from "@microsoft/live-share";
import { ContainerSchema, SharedMap } from "fluid-framework";
-// Initialize the Teams Client SDK
-await microsoftTeams.app.initialize();
- // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema: ContainerSchema = { initialObjects: { exampleMap: SharedMap }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
const { container } = await client.joinContainer(schema);
That's all it took to setup your container and join the meeting's session. Now, let's review the different types of _distributed data structures_ that you can use with the Live Share SDK.
+> [!TIP]
+> Ensure that the Teams Client SDK is initialized before using the Live Share APIs.
+ ## Fluid distributed data structures The Live Share SDK supports any [distributed data structure](https://fluidframework.com/docs/data-structures/overview/) included in Fluid Framework. Here's a quick overview of a few of the different types of objects available:
Let's see how `SharedMap` works. In this example, we've used `SharedMap` to buil
# [JavaScript](#tab/javascript) ```javascript
-import { TeamsFluidClient } from "@microsoft/live-share";
+import { LiveShareClient } from "@microsoft/live-share";
import { SharedMap } from "fluid-framework"; // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: { playlistMap: SharedMap }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const playlistMap = container.initialObjects.playlistMap as SharedMap; // Register listener for changes to values in the map
function onClickAddToPlaylist(video) {
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient } from "@microsoft/live-share";
+import { LiveShareClient } from "@microsoft/live-share";
import { ContainerSchema, SharedMap, IValueChanged } from "fluid-framework"; // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema: ContainerSchema = { initialObjects: { exampleMap: SharedMap }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const playlistMap = container.initialObjects.playlistMap as SharedMap; // Declare interface for object being stored in map
function onClickAddToPlaylist(video: IVideo) {
> [!NOTE] > Core Fluid Framework DDS objects don't support meeting role verification. Everyone in the meeting can change data stored through these objects.
-## Live Share ephemeral data structures
+## Live Share data structures
-The Live Share SDK includes a set of new ephemeral `SharedObject` classes, which provide stateful and stateless objects that aren't stored in the Fluid container. For example, if you want to create a laser-pointer feature into your app, such as the popular PowerPoint Live integration, you can use our `EphemeralEvent` or `EphemeralState` objects.
+The Live Share SDK includes a set of new Live Share `SharedObject` classes, which provide stateful and stateless objects that aren't stored in the Fluid container. For example, if you want to create a laser-pointer feature into your app, such as the popular PowerPoint Live integration, you can use our `LiveEvent` or `LiveState` objects.
-| Ephemeral Object | Description |
-| - | |
-| [EphemeralPresence](/javascript/api/@microsoft/live-share/ephemeralpresence) | See which users are online, set custom properties for each user, and broadcast changes to their presence. |
-| [EphemeralEvent](/javascript/api/@microsoft/live-share/ephemeralevent) | Broadcast individual events with any custom data attributes in the payload. |
-| [EphemeralState](/javascript/api/@microsoft/live-share/ephemeralstate) | Similar to SharedMap, a distributed key-value store that allows for restricted state changes based on role, for example, the presenter. |
+| Live Object | Description |
+| | |
+| [LivePresence](/javascript/api/@microsoft/live-share/livepresence) | See which users are online, set custom properties for each user, and broadcast changes to their presence. |
+| [LiveEvent](/javascript/api/@microsoft/live-share/liveevent) | Broadcast individual events with any custom data attributes in the payload. |
+| [LiveState](/javascript/api/@microsoft/live-share/livestate) | Similar to SharedMap, a distributed key-value store that allows for restricted state changes based on role, for example, the presenter. |
+| [LiveTimer](/javascript/api/@microsoft/live-share/livetimer) | Synchronize a countdown timer for a given interval. |
-### EphemeralPresence example
+### LivePresence example
-The `EphemeralPresence` class makes tracking who is in the session easier than ever. When calling the `.initialize()` or `.updatePresence()` methods, you can assign custom metadata for that user, such as name or profile picture. By listening to `presenceChanged` events, each client receives the latest `EphemeralPresenceUser` object, collapsing all presence updates into a single record for each unique `userId`.
+
+The `LivePresence` class makes tracking who is in the session easier than ever. When calling the `.initialize()` or `.updatePresence()` methods, you can assign custom metadata for that user, such as name or profile picture. By listening to `presenceChanged` events, each client receives the latest `LivePresenceUser` object, collapsing all presence updates into a single record for each unique `userId`.
> [!NOTE]
-> The default `userId` assigned to each `EphemeralPresenceUser` is a random UUID and is not directly tied to an AAD identity. You can override this by setting a custom `userId` to be the primary key, as shown in the example below.
+> The default `userId` assigned to each `LivePresenceUser` is a random UUID and is not directly tied to an AAD identity. You can override this by setting a custom `userId` to be the primary key, as shown in the example below.
Example:
Example:
```javascript import {
- TeamsFluidClient,
- EphemeralPresence,
+ LiveShareClient,
+ LivePresence,
PresenceState, } from "@microsoft/live-share"; // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: {
- presence: EphemeralPresence,
+ presence: LivePresence,
}, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const presence = container.initialObjects.presence; // Register listener for changes to presence
function onUserDidLogIn(userName, profilePicture) {
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient, EphemeralPresence, PresenceState, EphemeralPresenceUser } from "@microsoft/live-share";
+import {
+ LiveShareClient,
+ LivePresence,
+ PresenceState,
+ LivePresenceUser,
+} from "@microsoft/live-share";
// Declare interface for type of custom data for user interface ICustomUserData {
interface ICustomUserData {
} // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: {
- presence: EphemeralPresence<ICustomUserData>,
+ presence: LivePresence<ICustomUserData>,
}, };
-const { container } = await client.joinContainer(schema);
-const presence = container.initialObjects.presence as EphemeralPresence<ICustomUserData>;
+const { container } = await liveShare.joinContainer(schema);
+const presence = container.initialObjects.presence as LivePresence<ICustomUserData>;
// Register listener for changes to presence
-presence.on("presenceChanged", (userPresence: EphemeralPresenceUser<ICustomUserData>, local: boolean) => {
+presence.on("presenceChanged", (userPresence: LivePresenceUser<ICustomUserData>, local: boolean) => {
// Update UI with presence });
function onUserDidLogIn(userName: string, profilePicture: string) {
-### EphemeralEvent example
+### LiveEvent example
-`EphemeralEvent` is a great way to send simple events to other clients in a meeting. It's useful for scenarios like sending session notifications.
+
+`LiveEvent` is a great way to send simple events to other clients in a meeting. It's useful for scenarios like sending session notifications.
# [JavaScript](#tab/javascript) ```javascript
-import { TeamsFluidClient, EphemeralEvent } from "@microsoft/live-share";
+import { LiveEvent, LiveShareClient } from "@microsoft/live-share";
// Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { notifications: EphemeralEvent },
+ initialObjects: { notifications: LiveEvent },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const { notifications } = container.initialObjects; // Register listener for incoming notifications
notifications.sendEvent({
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient, EphemeralEvent, IEphemeralEvent } from "@microsoft/live-share";
+import { LiveShareClient, LiveEvent, ILiveEvent } from "@microsoft/live-share";
// Declare interface for type of custom data for user
-interface ICustomEvent extends IEphemeralEvent {
+interface ICustomEvent extends ILiveEvent {
senderName: string; text: string; } // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: {
- notifications: EphemeralEvent<ICustomEvent>,
+ notifications: LiveEvent<ICustomEvent>,
}, };
-const { container } = await client.joinContainer(schema);
-const notifications = container.initialObjects.notifications as EphemeralEvent<ICustomEvent>;
+const { container } = await liveShare.joinContainer(schema);
+const notifications = container.initialObjects.notifications as LiveEvent<ICustomEvent>;
// Register listener for incoming notifications notifications.on("received", (event: ICustomEvent, local: boolean) => {
notifications.sendEvent({
-### EphemeralTimer example
+### LiveTimer example
+
-`EphemeralTimer` enables scenarios that have a time limit, such as a group meditation timer or a round timer for a game.
+`LiveTimer` enables scenarios that have a time limit, such as a group meditation timer or a round timer for a game.
# [JavaScript](#tab/javascript) ```javascript
-import { TeamsFluidClient, EphemeralTimer } from "@microsoft/live-share";
+import { LiveShareClient, LiveTimer } from "@microsoft/live-share";
// Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { timer: EphemeralTimer },
+ initialObjects: { timer: LiveTimer },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const { timer } = container.initialObjects; // Register listener for when the timer starts its countdown
timer.play();
```TypeScript import {
- TeamsFluidClient,
- EphemeralTimer,
- EphemeralTimerEvents,
+ LiveShareClient,
+ LiveTimer,
+ LiveTimerEvents,
ITimerConfig, } from "@microsoft/live-share"; // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { timer: EphemeralTimer },
+ initialObjects: { timer: LiveTimer },
};
-const { container } = await client.joinContainer(schema);
-const timer = container.initialObjects.timer as EphemeralTimer;
+const { container } = await liveShare.joinContainer(schema);
+const timer = container.initialObjects.timer as LiveTimer;
// Register listener for when the timer starts its countdown
-timer.on(EphemeralTimerEvents.started, (config: ITimerConfig, local: boolean) => {
+timer.on(LiveTimerEvents.started, (config: ITimerConfig, local: boolean) => {
// Update UI to show timer has started }); // Register listener for when a paused timer has resumed
-timer.on(EphemeralTimerEvents.played, (config: ITimerConfig, local: boolean) => {
+timer.on(LiveTimerEvents.played, (config: ITimerConfig, local: boolean) => {
// Update UI to show timer has resumed }); // Register listener for when a playing timer has paused
-timer.on(EphemeralTimerEvents.paused, (config: ITimerConfig, local: boolean) => {
+timer.on(LiveTimerEvents.paused, (config: ITimerConfig, local: boolean) => {
// Update UI to show timer has paused }); // Register listener for when a playing timer has finished
-timer.on(EphemeralTimerEvents.finished, (config: ITimerConfig) => {
+timer.on(LiveTimerEvents.finished, (config: ITimerConfig) => {
// Update UI to show timer is finished }); // Register listener for the timer progressed by 20 milliseconds
-timer.on(EphemeralTimerEvents.onTick, (milliRemaining: number) => {
+timer.on(LiveTimerEvents.onTick, (milliRemaining: number) => {
// Update UI to show remaining time });
timer.play();
-## Role verification for ephemeral data structures
+## Role verification for live data structures
-Meetings in Teams can range from one-on-one calls to all-hands meetings, and may include members across organizations. Ephemeral objects are designed to support role verification, allowing you to define the roles that are allowed to send messages for each individual ephemeral object. For example, you could choose that only meeting presenters and organizers can control video playback, but still allow guests and attendees to request videos to watch next.
+Meetings in Teams can range from one-on-one calls to all-hands meetings, and may include members across organizations. Live objects are designed to support role verification, allowing you to define the roles that are allowed to send messages for each individual live object. For example, you could choose that only meeting presenters and organizers can control video playback, but still allow guests and attendees to request videos to watch next.
> [!NOTE]
-> The `EphemeralPresence` class doesn't support role verification. The `EphemeralPresenceUser` object has a `getRoles` method, which returns the meeting roles for a given user.
+> The `LivePresence` class doesn't support role verification. The `LivePresenceUser` object has a `getRoles` method, which returns the meeting roles for a given user.
-Example using `EphemeralState`:
+Example using `LiveState`:
# [JavaScript](#tab/javascript) ```javascript
-import {
- TeamsFluidClient,
- EphemeralState,
- UserMeetingRole,
-} from "@microsoft/live-share";
+import { LiveShareClient, LiveState, UserMeetingRole } from "@microsoft/live-share";
// Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { appState: EphemeralState },
+ initialObjects: { appState: LiveState },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const { appState } = container.initialObjects; // Register listener for changes to state and corresponding custom data
function onSelectPresentMode(documentId) {
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient, EphemeralState, UserMeetingRole } from "@microsoft/live-share";
+import { LiveShareClient, LiveState, UserMeetingRole } from "@microsoft/live-share";
// Declare interface for type of custom data for user interface ICustomState {
interface ICustomState {
} // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = { initialObjects: {
- appState: EphemeralState<ICustomState>,
+ appState: LiveState<ICustomState>,
}, };
-const { container } = await client.joinContainer(schema);
-const appState = container.initialObjects.appState as EphemeralState<ICustomState>;
+const { container } = await liveShare.joinContainer(schema);
+const appState = container.initialObjects.appState as LiveState<ICustomState>;
// Register listener for changes to state and corresponding custom data appState.on("stateChanged", (state: string, data: ICustomState | undefined, local: boolean) => {
function onSelectPresentMode(documentId: string) {
Listen to your customers to understand their scenarios before implementing role verification into your app, particularly for the **Organizer** role. There's no guarantee that a meeting organizer be present in the meeting. As a general rule of thumb, all users will be either **Organizer** or **Presenter** when collaborating within an organization. If a user is an **Attendee**, it's usually an intentional decision on behalf of a meeting organizer.
+> [!NOTE]
+> Currently, Live Share doesn't support channel meetings.
+ ## Code samples | Sample name | Description | JavaScript |
Listen to your customers to understand their scenarios before implementing role
## Next step > [!div class="nextstepaction"]
-> [Live Share media capabilities](teams-live-share-media-capabilities.md)
+> [Live Share media](teams-live-share-media-capabilities.md)
## See also
-* [GitHub repository](https://github.com/microsoft/live-share-sdk)
-* [Live Share SDK reference docs](/javascript/api/@microsoft/live-share/)
-* [Live Share Media SDK reference docs](/javascript/api/@microsoft/live-share-media/)
-* [Live Share FAQ](teams-live-share-faq.md)
-* [Teams apps in meetings](teams-apps-in-meetings.md)
+- [GitHub repository](https://github.com/microsoft/live-share-sdk)
+- [Live Share SDK reference docs](/javascript/api/@microsoft/live-share/)
+- [Live Share Media SDK reference docs](/javascript/api/@microsoft/live-share-media/)
+- [Live Share FAQ](teams-live-share-faq.md)
+- [Teams apps in meetings](teams-apps-in-meetings.md)
platform Teams Live Share Faq https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-faq.md
Get answers to common questions when using Live Share.<br>
<summary><b>Can I use my own Azure Fluid Relay service?</b></summary>
-Yes! When constructing the `TeamsFluidClient` class, you can define your own `AzureConnectionConfig`. Live Share associates containers you create with meetings, but you'll need to implement the `ITokenProvider` interface to sign tokens for your containers. For example, you can use a provided `AzureFunctionTokenProvider`, which uses an Azure cloud function to request an access token from a server.
+Yes! When initializing Live Share, you can define your own `AzureConnectionConfig`. Live Share associates containers you create with meetings, but you'll need to implement the `ITokenProvider` interface to sign tokens for your containers. For example, you can use a provided `AzureFunctionTokenProvider`, which uses an Azure cloud function to request an access token from a server.
While most of you find it beneficial to use our free hosted service, there may still be times where it's beneficial to use your own Azure Fluid Relay service for your Live Share app. Consider using a custom AFR service connection if you:
Any data sent or stored through Fluid containers created by Live Share's hosted
<summary><b>What meeting types does Live Share support?</b></summary>
-During Preview, only scheduled meetings are supported and all participants must be on the meeting calendar. Meeting types such as, one-on-one calls, group calls, and meet now aren't supported.
+Scheduled meetings, one-on-one calls, group calls, and meet now are supported. Channel meetings aren't yet supported.
<br>
Currently, Live Share supports a maximum of 100 attendees per session. If this i
</details> <details>
-<summary><b>Can I use Live Share's ephemeral data structures outside of Teams?</b></summary>
+<summary><b>Can I use Live Share's data structures outside of Teams?</b></summary>
Currently, Live Share packages require the Teams Client SDK to function properly. Features in `@microsoft/live-share` or `@microsoft/live-share-media` won't work outside Microsoft Teams. If this is something you're interested in, you can [start a discussion here](https://github.com/microsoft/live-share-sdk/discussions).
Currently, Live Share doesn't support adding new `initialObjects` to the Fluid `
To fix errors resulting from changes to `initialObjects` when testing locally in your browser, remove the hashed container ID from your URL and reload the page. If you're testing in a Teams meeting, start a new meeting and try again.
-If you plan to update your app with new `SharedObject` or `EphemeralObject` instances frequently, you should consider how you deploy new schema changes to production. While the actual risk is relatively low and short lasting, there may be active sessions at the time you roll out the change. Existing users in the session shouldn't be impacted, but users joining that session after you deployed a breaking change may have issues connecting to the session. To mitigate this, you may consider some of the following solutions:
+If you plan to update your app with new `SharedObject` or `LiveObject` instances frequently, you should consider how you deploy new schema changes to production. While the actual risk is relatively low and short lasting, there may be active sessions at the time you roll out the change. Existing users in the session shouldn't be impacted, but users joining that session after you deployed a breaking change may have issues connecting to the session. To mitigate this, you may consider some of the following solutions:
* Deploy schema changes for your web application outside of normal business hours. * Use `dynamicObjectTypes` for any changes made to your schema, rather than changing `initialObjects`.
If you plan to update your app with new `SharedObject` or `EphemeralObject` inst
<details> <summary><b>Are there limits to how many change events I can emit through Live Share?</b></summary>
-While Live Share is in Preview, any limit to events emitted through Live Share is not enforced. For optimal performance, you must debounce changes emitted through `SharedObject` or `EphemeralObject` instances to one message per 50 milliseconds or more. This is especially important when sending changes based on mouse or touch coordinates, such as when synchronizing cursor positions, inking, and dragging objects around a page.
+While Live Share is in Preview, any limit to events emitted through Live Share isn't enforced. For optimal performance, you must debounce changes emitted through `SharedObject` or `LiveObject` instances to one message per 50 milliseconds or more. This is especially important when sending changes based on mouse or touch coordinates, such as when synchronizing cursor positions, inking, and dragging objects around a page.
<br>
platform How To Custom Azure Fluid Relay https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-how-to/how-to-custom-azure-fluid-relay.md
Last updated 07/21/2022
# Custom Azure Fluid Relay service
-While you likely will prefer using our free hosted service, there are situations where it is beneficial to use your own Azure Fluid Relay service for your Live Share app.
+While you likely will prefer using our free hosted service, there are situations where it's beneficial to use your own Azure Fluid Relay service for your Live Share app.
## Pre-requisites
While you likely will prefer using our free hosted service, there are situations
## Connect to Azure Fluid Relay service
-When constructing the `TeamsFluidClient` class, you can define your own `AzureConnectionConfig`. Live Share associates containers you create with meetings, but you'll need to implement the `ITokenProvider` interface to sign tokens for your containers. This example explains Azure's `AzureFunctionTokenProvider`, which uses an Azure cloud function to request an access token from a server.
+When calling initializing `LiveShareClient`, you can define your own `AzureConnectionConfig`. Live Share associates containers you create with meetings, but you'll need to implement the `ITokenProvider` interface to sign tokens for your containers. This example explains Azure's `AzureFunctionTokenProvider`, which uses an Azure cloud function to request an access token from a server.
# [JavaScript](#tab/javascript) ```javascript
-import { TeamsFluidClient, EphemeralPresence } from "@microsoft/live-share";
+import { LiveShareClient, LivePresence } from "@microsoft/live-share";
import { SharedMap } from "fluid-framework"; import { AzureFunctionTokenProvider } from "@fluidframework/azure-client"; // Define a custom connection for your app
-const clientProps = {
+const options = {
connection: { tenantId: "MY_TENANT_ID", tokenProvider: new AzureFunctionTokenProvider(
const clientProps = {
}, }; // Join the Fluid container
-const client = new TeamsFluidClient(clientProps);
+const liveShare = new LiveShareClient(options);
const schema = { initialObjects: {
- presence: EphemeralPresence,
+ presence: LivePresence,
ticTacToePositions: SharedMap, }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
const { container } = await client.joinContainer(schema);
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient, EphemeralPresence, ITeamsFluidClientOptions } from "@microsoft/live-share";
+import {
+ LiveShareClient,
+ ILiveShareClientOptions,
+ LivePresence,
+} from "@microsoft/live-share";
import { SharedMap } from "fluid-framework"; import { AzureFunctionTokenProvider } from "@fluidframework/azure-client"; // Define a custom connection for your app
-const clientProps: ITeamsFluidClientOptions = {
+const options: ILiveShareClientOptions = {
connection: { tenantId: "MY_TENANT_ID", tokenProvider: new AzureFunctionTokenProvider(
const clientProps: ITeamsFluidClientOptions = {
}, }; // Join the Fluid container
-const client = new TeamsFluidClient(clientProps);
+const liveShare = new LiveShareClient(options);
const schema = { initialObjects: {
- presence: EphemeralPresence,
+ presence: LivePresence,
ticTacToePositions: SharedMap, }, };
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
Azure Fluid Relay is designed to work with any web-based application, meaning it
Live Share has features that are beneficial to common meeting scenarios that augment other features in your app, including: * [Container mapping](#container-mapping)
-* [Ephemeral objects and role verification](#ephemeral-objects-and-role-verification)
+* [Live objects and role verification](#live-objects-and-role-verification)
* [Media synchronization](#media-synchronization) ### Container mapping
-Live Share's `TeamsFluidClient` class is responsible for mapping a unique meeting identifier to your Fluid containers, which ensures that all meeting participants join the same container. As part of this process, the client attempts to connect to a `containerId` mapped to the meeting that one already exists. If one doesn't exist, the `AzureClient` is used to create a container using your `AzureConnectionConfig` and then relay the `containerId` to other meeting participants.
+The `LiveShareClient` in `@microsoft/live-share` is responsible for mapping a unique meeting identifier to your Fluid containers, which ensures that all meeting participants join the same container. As part of this process, the client attempts to connect to a `containerId` mapped to the meeting that one already exists. If one doesn't exist, the `AzureClient` is used to create a container using your `AzureConnectionConfig` and then relay the `containerId` to other meeting participants.
If your app already has a mechanism for creating Fluid containers and sharing them to other members, such as by inserting the `containerId` into the URL shared to the meeting stage, then this may not be necessary for your app.
-### Ephemeral objects and role verification
+### Live objects and role verification
-Live Share's ephemeral data structures such as `EphemeralPresence`, `EphemeralState`, and `EphemeralEvent` are tailored to collaboration in meetings and thus aren't supported in Fluid containers used outside of Microsoft Teams. Features like role verification help your app align with expectations of our users.
+Live Share's live data structures such as `LivePresence`, `LiveState`, and `LiveEvent` are tailored to collaboration in meetings and thus aren't supported in Fluid containers used outside of Microsoft Teams. Features like role verification help your app align with expectations of our users.
> [!NOTE]
-> As an added benefit, ephemeral objects also feature faster message latencies compared to traditional Fluid data structures.
+> As an added benefit, live objects also feature faster message latencies compared to traditional Fluid data structures.
For more information, see [core capabilities](../teams-live-share-capabilities.md) page.
platform Teams Live Share Media Capabilities https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-media-capabilities.md
Last updated 04/07/2022
:::image type="content" source="../assets/images/teams-live-share/live-share-media-capabilities-docs-feature-1.png" alt-text="Teams Live Share media synchronization":::
-Video and audio are instrumental parts of the modern world and workplace. We've heard wide ranging feedback that there is more we can do to increase the quality, accessibility, and license protections of watching videos together in meetings.
+Video and audio are instrumental parts of the modern world and workplace. We've heard wide ranging feedback that there's more we can do to increase the quality, accessibility, and license protections of watching videos together in meetings.
The Live Share SDK enables robust **media synchronization** for any HTML `<video>` and `<audio>` element with just a few lines of code. By synchronizing media at the player state and transport controls layer, you can individually attribute views and license, while providing the highest possible quality available through your app.
The Live Share SDK enables robust **media synchronization** for any HTML `<video
To add the latest version of the SDK to your application using npm: ```bash
-npm install @microsoft/live-share --save
-npm install @microsoft/live-share-media --save
+npm install @microsoft/live-share@next --save
+npm install @microsoft/live-share-media@next --save
``` OR
OR
To add the latest version of the SDK to your application using [Yarn](https://yarnpkg.com/): ```bash
-yarn add @microsoft/live-share
-yarn add @microsoft/live-share-media
+yarn add @microsoft/live-share@next
+yarn add @microsoft/live-share-media@next
``` ## Media sync overview
The Live Share SDK has two primary classes related to media synchronization:
| Classes | Description | | - | - |
-| [EphemeralMediaSession](/javascript/api/@microsoft/live-share-media/ephemeralmediasession) | Custom ephemeral object designed to coordinate media transport controls and playback state in independent media streams. |
-| [MediaPlayerSynchronizer](/javascript/api/@microsoft/live-share-media/mediaplayersynchronizer) | Synchronizes any object that implements the `IMediaPlayer` interface -- including HTML5 `<video>` and `<audio>` -- using `EphemeralMediaSession`. |
+| [LiveMediaSession](/javascript/api/@microsoft/live-share-media/livemediasession) | Custom live object designed to coordinate media transport controls and playback state in independent media streams. |
+| [MediaPlayerSynchronizer](/javascript/api/@microsoft/live-share-media/mediaplayersynchronizer) | Synchronizes any object that implements the `IMediaPlayer` interface -- including HTML5 `<video>` and `<audio>` -- using `LiveMediaSession`. |
Example:
Example:
# [JavaScript](#tab/javascript) ```javascript
-import * as microsoftTeams from "@microsoft/teams-js";
-import { TeamsFluidClient, UserMeetingRole } from "@microsoft/live-share";
-import { EphemeralMediaSession } from "@microsoft/live-share-media";
-
-// Initialize the Teams Client SDK
-await microsoftTeams.app.initialize();
+import { LiveShareClient, UserMeetingRole } from "@microsoft/live-share";
+import { LiveMediaSession } from "@microsoft/live-share-media";
// Setup the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { mediaSession: EphemeralMediaSession },
+ initialObjects: { mediaSession: LiveMediaSession },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
const { mediaSession } = container.initialObjects; // Get the player from your document and create synchronizer
await mediaSession.initialize(allowedRoles);
# [TypeScript](#tab/typescript) ```TypeScript
-import * as microsoftTeams from "@microsoft/teams-js";
-import { TeamsFluidClient, UserMeetingRole } from "@microsoft/live-share";
-import { EphemeralMediaSession, IMediaPlayer, MediaPlayerSynchronizer } from "@microsoft/live-share-media";
+import { LiveShareClient, UserMeetingRole } from "@microsoft/live-share";
+import { LiveMediaSession, IMediaPlayer, MediaPlayerSynchronizer } from "@microsoft/live-share-media";
import { ContainerSchema } from "fluid-framework";
-// Initialize the Teams Client SDK
-await microsoftTeams.app.initialize();
- // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema: ContainerSchema = {
- initialObjects: { mediaSession: EphemeralMediaSession },
+ initialObjects: { mediaSession: LiveMediaSession },
};
-const { container } = await client.joinContainer(schema);
-const mediaSession = container.initialObjects.mediaSession as EphemeralMediaSession;
+const { container } = await liveShare.joinContainer(schema);
+const mediaSession = container.initialObjects.mediaSession as LiveMediaSession;
// Get the player from your document and create synchronizer const player: IMediaPlayer = document.getElementById("player") as HTMLVideoElement;
await mediaSession.initialize(allowedRoles);
-The `EphemeralMediaSession` automatically listens for changes to the group's playback state. `MediaPlayerSynchronizer` listens to state changes emitted by `EphemeralMediaSession` and applies them to the provided `IMediaPlayer` object, such as an HTML5 `<video>` or `<audio>` element. To avoid playback state changes that a user didn't intentionally initiate, such as a buffer event, we must call transport controls through the synchronizer, rather than directly through the player.
+The `LiveMediaSession` automatically listens for changes to the group's playback state. `MediaPlayerSynchronizer` listens to state changes emitted by `LiveMediaSession` and applies them to the provided `IMediaPlayer` object, such as an HTML5 `<video>` or `<audio>` element. To avoid playback state changes that a user didn't intentionally initiate, such as a buffer event, we must call transport controls through the synchronizer, rather than directly through the player.
Example:
document.getElementById("change-track-button").onclick = () => {
``` > [!NOTE]
-> While you can use the `EphemeralMediaSession` object to synchronize media manually, it's generally recommend to use the `MediaPlayerSynchronizer`. Depending on the player you use in your app, you might need to create a delegate shim to make your web player's interface match the [IMediaPlayer](/javascript/api/@microsoft/live-share-media/imediaplayer) interface.
+> While you can use the `LiveMediaSession` object to synchronize media manually, it's generally recommend to use the `MediaPlayerSynchronizer`. Depending on the player you use in your app, you might need to create a delegate shim to make your web player's interface match the [IMediaPlayer](/javascript/api/@microsoft/live-share-media/imediaplayer) interface.
## Suspensions and wait points :::image type="content" source="../assets/images/teams-live-share/live-share-media-out-of-sync.png" alt-text="Screenshot that shows a suspension sync to the presenter.":::
-If you want to temporarily suspend synchronization for the `EphemeralMediaSession` object, you can use suspensions. A [MediaSessionCoordinatorSuspension](/javascript/api/@microsoft/live-share-media/ephemeralmediasessioncoordinatorsuspension) object is local by default, which can be helpful in cases where a user might want to catch up on something they missed, take a break, and so on. If the user ends the suspension, synchronization resumes automatically.
+If you want to temporarily suspend synchronization for the `LiveMediaSession` object, you can use suspensions. A [MediaSessionCoordinatorSuspension](/javascript/api/@microsoft/live-share-media/livemediasessioncoordinatorsuspension) object is local by default, which can be helpful in cases where a user might want to catch up on something they missed, take a break, and so on. If the user ends the suspension, synchronization resumes automatically.
# [JavaScript](#tab/javascript)
document.getElementById("ready-up-button")!.onclick = () => {
## Audio ducking
-The Live Share SDK supports intelligent audio ducking. You can use the _experimental_ feature in your application by adding the following to your code:
+The Live Share SDK supports intelligent audio ducking. You can use the feature in your application by adding the following to your code:
# [JavaScript](#tab/javascript) ```javascript
-import * as microsoftTeams from "@microsoft/teams-js";
+import { meeting } from "@microsoft/teams-js";
// ... set up MediaPlayerSynchronizer // Register speaking state change handler through Teams Client SDK let volumeTimer;
-microsoftTeams.meeting.registerSpeakingStateChangeHandler((speakingState) => {
+meeting.registerSpeakingStateChangeHandler((speakingState) => {
if (speakingState.isSpeakingDetected && !volumeTimer) { // If someone in the meeting starts speaking, periodically // lower the volume using your MediaPlayerSynchronizer's
microsoftTeams.meeting.registerSpeakingStateChangeHandler((speakingState) => {
# [TypeScript](#tab/typescript) ```TypeScript
-import * as microsoftTeams from "@microsoft/teams-js";
+import { meeting } from "@microsoft/teams-js";
// ... set up MediaPlayerSynchronizer // Register speaking state change handler through Teams Client SDK let volumeTimer: NodeJS.Timeout | undefined;
-microsoftTeams.meeting.registerSpeakingStateChangeHandler((speakingState: microsoftTeams.meeting.ISpeakingState) => {
+meeting.registerSpeakingStateChangeHandler((speakingState: meeting.ISpeakingState) => {
if (speakingState.isSpeakingDetected && !volumeTimer) { // If someone in the meeting starts speaking, periodically // lower the volume using your MediaPlayerSynchronizer's
Additionally, add the following [RSC](/microsoftteams/platform/graph-api/rsc/res
``` > [!NOTE]
-> The `registerSpeakingStateChangeHandler` API used for audio ducking currently works only for non-local users who are speaking.
+> The `registerSpeakingStateChangeHandler` API used for audio ducking currently only works on Microsoft Teams desktop and in scheduled and meet now meeting types.
## Code samples | Sample name | Description | JavaScript | | -- | -- | - |
-| React video | Basic example showing how the EphemeralMediaSession object works with HTML5 video. | [View](https://aka.ms/liveshare-reactvideo) |
+| React video | Basic example showing how the LiveMediaSession object works with HTML5 video. | [View](https://aka.ms/liveshare-reactvideo) |
| React media template | Enable all connected clients to watch videos together, build a shared playlist, transfer whom is in control, and annotate over the video. | [View](https://aka.ms/liveshare-mediatemplate) | ## Next step > [!div class="nextstepaction"]
-> [Agile Poker tutorial](../sbs-teams-live-share.yml)
+> [Live Share canvas](teams-live-share-canvas.md)
## See also - [Live Share SDK FAQ](teams-live-share-faq.md) - [Live Share SDK reference docs](/javascript/api/@microsoft/live-share/) - [Live Share Media SDK reference docs](/javascript/api/@microsoft/live-share-media/)-- [Reference docs](https://aka.ms/livesharedocs) - [Teams apps in meetings](teams-apps-in-meetings.md)
platform Teams Live Share Overview https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-overview.md
Last updated 04/07/2022
# Live Share SDK
-> [!NOTE]
-> The Live Share SDK is currently available in [Public Developer Preview](../resources/dev-preview/developer-preview-intro.md). You must be part of the Public Developer Preview for Microsoft Teams to use Live Share.
+> [!VIDEO https://www.youtube.com/embed/971YIvosuUk]
+
+Live Share is an SDK designed to transform Teams apps into collaborative multi-user experiences without writing any dedicated back-end code. With Live Share, your users can co-watch, co-create, and co-edit during meetings.
-Live Share is an SDK designed to transform Teams apps into collaborative multi-user experiences without writing any dedicated back-end code. Live Share seamlessly integrates meetings with [Fluid Framework](https://fluidframework.com/). Fluid Framework is a collection of client libraries for distributing and synchronizing shared state. Live Share provides a free, fully managed, and ready to use [Azure Fluid Relay](/azure/azure-fluid-relay/) backed by the security and global scale of Teams.
+Sometimes screen sharing just isn't enough, which is why Microsoft built tools like PowerPoint Live and Whiteboard directly into Teams. By bringing your web application directly to center stage in the meeting interface, your users can seamlessly collaborate during meetings and calls.
> [!div class="nextstepaction"] > [Get started](teams-live-share-quick-start.md)
-Live Share includes an `TeamsFluidClient` class for connecting to a special Fluid Container associated with each meeting in a few lines of code. In addition to the data structures provided by Fluid Framework, Live Share also supports a new set of distributed data structure (DDS) classes to simplify building applications for common meeting scenarios, such as shared media playback.
+## Feature overview
+
+Live Share has three packages that support limitless collaborative scenarios. These packages expose a set of distributed data structures (DDS), including primitive building blocks and turn-key scenarios.
+
+Live Share seamlessly integrates meetings with [Fluid Framework](https://fluidframework.com/). Fluid Framework is a collection of client libraries for distributing and synchronizing shared state. Live Share provides a free, fully managed, and ready to use [Azure Fluid Relay](/azure/azure-fluid-relay/) backed by the security and global scale of Teams.
+
+### Live Share core
+
+Live Share enables connecting to a special Fluid Container associated with each meeting in a few lines of code. In addition to the data structures provided by Fluid Framework, Live Share also supports a new set of DDS classes to simplify synchronizing app state in meetings.
+
+Features supported by the Live Share core package include:
+
+- Join a meeting's Live Share session with `LiveShareClient`.
+- Track meeting presence and synchronize user metadata with `LivePresence`.
+- Send real-time events to other clients in the session with `LiveEvent`.
+- Coordinate app state that disappears when users leave the session with `LiveState`.
+- Synchronize a countdown timer with `LiveTimer`.
+- Leverage any feature of Fluid Framework, such as `SharedMap` and `SharedString`.
+
+You can find more information about this package on the [core capabilities page](./teams-live-share-capabilities.md).
+
+### Live Share media
++
+Video and audio are instrumental parts of the modern world and workplace. Live Share media enables **media synchronization** for any media player with just a few lines of code. By synchronizing media at the player state and transport controls layer, you can individually attribute views, while providing the highest possible quality available through your app. Because Microsoft isn't rebroadcasting your media content, your licensing and access requirements are kept intact.
+
+Features supported by Live Share media include:
+- Synchronize media player state and track with `MediaPlayerSynchronizer`.
+- Intelligent adjustments to media volume as users talk during the meeting.
+- Limit which users can modify player state.
+- Suspend and resume media synchronization on the fly or at scheduled wait points.
+
+You can find more information about this package on the [Live Share media page](./teams-live-share-media-capabilities.md).
+
+> [!NOTE]
+> Live Share doesn't rebroadcast media content. It's designed for use with embedded web players, such as HTML5 `<video>` or Azure Media Player.
+
+### Live Share canvas
++
+When collaborating in meetings, it's essential for users to be able to point out and emphasize content on the screen. Live Share canvas makes it easy to add inking, laser pointers, and cursors to your app for seamless collaboration.
+
+Features supported by Live Share canvas include:
+
+- Add a collaborative `<canvas>` to your app with `LiveCanvas`.
+- Convey ideas using the pen, highlighter, line, and arrow tools.
+- Present effectively using the laser pointer.
+- Follow along with real-time mouse cursors.
+- Configure settings for variable devices and view states.
+- Use fully supported mouse, touch, and stylus inputs.
+
+You can find more information about this package on the [Live Share canvas page](./teams-live-share-canvas.md).
## Why build apps with Live Share?
Here are some key benefits of the Live Share SDK:
- Zero-hassle session management and security. - Stateful and stateless distributed data structures. - Media extensions to easily synchronize video and audio.
+- Turn-key inking, laser pointers, and cursors.
- Respect meeting privileges using role verification. - Free and fully managed service with low latency.-- Intelligent audio ducking.-
-To understand if Live Share is right for your collaborative scenario, it is helpful to understand the differences between Live Share and other collaborative frameworks, including:
+To understand if Live Share is right for your collaborative scenario, it's helpful to understand the differences between Live Share and other collaborative frameworks, including:
- [Web sockets](#web-sockets) - [Azure Fluid Relay](#azure-fluid-relay)
Web sockets are a ubiquitous technology for real-time communication in the web,
Like other custom API services, requirements typically include authenticating sessions, regional mapping, maintenance, and scale. Many collaborative scenarios also require maintaining session state in the server, which requires storage infrastructure, conflict resolutions, and more.
+By using Live Share, you get all the power of web sockets without any of the overhead.
+ ### Azure Fluid Relay [Azure Fluid Relay](/azure/azure-fluid-relay/) is a managed offering for the Fluid Framework that helps developers build real-time collaborative experiences and replicate state across connected JavaScript clients. Microsoft Whiteboard, Loop, and OneNote are all examples of apps built with Fluid Framework today.
Live Share provides a turn-key Azure Fluid Relay service backed by the security
# [JavaScript](#tab/javascript) ```javascript
-import { TeamsFluidClient, EphemeralPresence } from "@microsoft/live-share";
+import { LiveShareClient, LivePresence } from "@microsoft/live-share";
// Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema = {
- initialObjects: { presence: EphemeralPresence },
+ initialObjects: { presence: LivePresence },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
const { container } = await client.joinContainer(schema);
# [TypeScript](#tab/typescript) ```TypeScript
-import { TeamsFluidClient, EphemeralPresence } from "@microsoft/live-share";
+import { LiveShareClient, LivePresence } from "@microsoft/live-share";
import { ContainerSchema } from "fluid-framework"; // Join the Fluid container
-const client = new TeamsFluidClient();
+const liveShare = new LiveShareClient();
const schema: ContainerSchema = {
- initialObjects: { presence: EphemeralPresence },
+ initialObjects: { presence: LivePresence },
};
-const { container } = await client.joinContainer(schema);
+const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic ```
For more information, see the custom Azure Fluid Relay service [how-to guide](./
| :-- | :- | | During a marketing review, a user wants to collect feedback on their latest video edit. | User shares the video to the meeting stage and starts the video. As needed, the user pauses the video to discuss the scene and participants draw over parts of the screen to emphasize key points. | | A project manager plays Agile Poker with their team during planning. | Manager shares an Agile Poker app to the meeting stage that enables playing the planning game until the team has consensus. |
-| A financial advisor reviews PDF documents with clients before signing. | The financial advisor shares the PDF contract to the meeting stage. All attendees can see each others cursors and highlighted text in the PDF, after which both parties sign the agreement. |
+| A financial advisor reviews PDF documents with clients before signing. | The financial advisor shares the PDF contract to the meeting stage. All attendees can see each other's cursors and highlighted text in the PDF, after which both parties sign the agreement. |
+
+> [!IMPORTANT]
+> Live Share is licensed under the [Microsoft Live Share SDK License](https://github.com/microsoft/live-share-sdk/blob/main/LICENSE). To use these capabilities in your app, you must first read and agree to these terms.
## Next step
platform Teams Live Share Tutorial https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-tutorial.md
Last updated 04/07/2022
# Dice Roller code tutorial
-In the Dice Roller sample app, users are shown a die with a button to roll it. When the die is rolled, the Live Share SDK uses the Fluid Framework to sync the data across clients, so everyone sees the same result. To sync data, perform the following steps in the [app.js](https://github.com/microsoft/live-share-sdk/blob/main/samples/01.dice-roller/src/app.js) file:
+In the Dice Roller sample app, users are shown a dice with a button to roll it. When the dice is rolled, the Live Share SDK uses the Fluid Framework to sync the data across clients, so everyone sees the same result. To sync data, perform the following steps in the [app.js](https://github.com/microsoft/live-share-sdk/blob/main/samples/01.dice-roller/src/app.js) file:
1. [Set up the application](#set-up-the-application) 2. [Join a Fluid container](#join-a-fluid-container)
In the Dice Roller sample app, users are shown a die with a button to roll it. W
## Set up the application
-Start by importing the required modules. The sample uses the [SharedMap DDS](https://fluidframework.com/docs/data-structures/map/) from the Fluid Framework and the [TeamsFluidClient](/javascript/api/@microsoft/live-share/teamsfluidclient) from the Live Share SDK. The sample supports Teams Meeting Extensibility so we'll need to include the [Teams Client SDK](https://github.com/OfficeDev/microsoft-teams-library-js). Finally, the sample is designed to run both locally and in a Teams meeting so we'll need to include some additional Fluid Framework pieces needed to [test the sample locally](https://fluidframework.com/docs/testing/testing/#azure-fluid-relay-as-an-abstraction-for-tinylicious).
+You can start by importing the required modules. The sample uses [SharedMap DDS](https://fluidframework.com/docs/data-structures/map/) from the Fluid Framework and [TeamsFluidClient](/javascript/api/@microsoft/live-share/teamsfluidclient) from the Live Share SDK. The sample supports Teams Meeting Extensibility so you must include the [Teams Client SDK](https://github.com/OfficeDev/microsoft-teams-library-js). Finally, the sample is designed to run both locally and in a Teams meeting so you need to include more Fluid Framework pieces to [test the sample locally](https://fluidframework.com/docs/testing/testing/#azure-fluid-relay-as-an-abstraction-for-tinylicious).
-Applications create Fluid containers using a schema that defines a set of _initial objects_ that will be available to the container. The sample uses a SharedMap to store the most recent die value that was rolled. For more information, see [Data modeling](https://fluidframework.com/docs/build/data-modeling/).
+Applications create Fluid containers using a schema that defines a set of _initial objects_ that are available to the container. The sample uses a SharedMap to store the current dice value that was rolled. For more information, see [Data modeling](https://fluidframework.com/docs/build/data-modeling/).
-Teams meeting apps require multiple views (content, configuration, and stage). We'll create a `start()` function to help identify the view to render and to perform any initialization that's required. We want our app to support running both locally in a web browser and from within a Teams Meeting so the `start()` function looks for an `inTeams=true` query parameter to determine if it's running in Teams. When running in Teams your application need to call `app.initialize()` prior to calling any other teams-js methods.
+Teams meeting apps require multiple views, such as content, configuration, and stage. You can create a `start()` function to help identify the view. This helps to render and perform any initialization that's required. The app supports running both locally in a web browser and from within a Teams meeting. The `start()` function looks for an `inTeams=true` query parameter to determine if it's running in Teams.
-In addition to the `inTeams=true` query parameter, we can use a `view=content|config|stage` query parameter to determine the view that needs to be rendered.
+> [!NOTE]
+> When running in Teams, your application needs to call `app.initialize()` prior to calling any other teams-js methods.
+
+In addition to the `inTeams=true` query parameter, you can use a `view=content|config|stage` query parameter to determine the view that needs to be rendered.
```js import { SharedMap } from "fluid-framework";
-import { TeamsFluidClient } from "@microsoft/live-share";
import { app, pages } from "@microsoft/teams-js";
-import { LOCAL_MODE_TENANT_ID } from "@fluidframework/azure-client";
+import { LiveShareClient, testLiveShare } from "@microsoft/live-share";
import { InsecureTokenProvider } from "@fluidframework/test-client-utils"; const searchParams = new URL(window.location).searchParams;
start().catch((error) => console.error(error));
## Join a Fluid container
-Not all of your apps views will need to be collaborative. The `stage` view _always_ needs collaborative features, the `content` view _may_ need collaborative features, and the `config` view should _never_ need collaborative features. For the views that do need collaborative features you'll need to join a Fluid container associated with the current meeting.
+Not all of your app's views need to be collaborative. The `stage` view _always_ needs collaborative features, the `content` view _may_ need collaborative features, and the `config` view should _never_ need collaborative features. For the views that do need collaborative features you'll need to join a Fluid container associated with the current meeting.
-Joining the container for the meeting is as simple as creating a new [TeamsFluidClient](/javascript/api/@microsoft/live-share/teamsfluidclient), and then calling it's [joinContainer()](/javascript/api/@microsoft/live-share/teamsfluidclient#@microsoft-live-share-teamsfluidclient-joincontainer) method. When running locally you'll need to pass in a custom connection config with a special `LOCAL_MODE_TENANT_ID` but otherwise, join a local container is the same as joining a container in Teams.
+Joining the container for the meeting is as simple as initializing the [LiveShareClient](/javascript/api/@microsoft/live-share/liveshareclient) and calling its [joinContainer()](/javascript/api/@microsoft/live-share/liveshareclient#@microsoft-live-share-liveshareclient-joincontainer) method.
+
+When running locally, you can import [testLiveShare](/javascript/api/@microsoft/live-share/testliveshare) and call its [initialize()](/javascript/api/@microsoft/live-share.testliveshare#@microsoft-live-share-testliveshare-initialize) method. Then, use the [joinContainer()](/javascript/api/@microsoft/live-share.testliveshare#@microsoft-live-share-testliveshare-joincontainer) method to connect to a session.
```js async function joinContainer() { // Are we running in teams?
- let client;
if (!!searchParams.get("inTeams")) { // Create client
- client = new TeamsFluidClient();
- } else {
- // Create client and configure for testing
- client = new TeamsFluidClient({
- connection: {
- type: "local",
- tokenProvider: new InsecureTokenProvider("", {
- id: "123",
- name: "Test User",
- }),
- endpoint: "http://localhost:7070",
- },
- });
+ const liveShare = new LiveShareClient();
+ // Join container
+ return await liveShare.joinContainer(containerSchema, onContainerFirstCreated);
}-
- // Join container
- return await client.joinContainer(containerSchema, onContainerFirstCreated);
+ // Create client and configure for testing
+ testLiveShare.initialize();
+ return await testLiveShare.joinContainer(containerSchema, onContainerFirstCreated);
} ```
-> [!NOTE]
-> When testing locally, the TeamsFluidClient updates the browser URL to contain the ID of the test container that was created. Copying that link to other browser tabs causes the TeamsFluidClient to join the test container that was created. If the modification of the applications URL interferers with the operation of the application, the strategy used to store the test containers ID can be customized using the [setLocalTestContainerId](/javascript/api/@microsoft/live-share/iteamsfluidclientoptions#@microsoft-live-share-iteamsfluidclientoptions-setlocaltestcontainerid) and [getLocalTestContainerId](/javascript/api/@microsoft/live-share/iteamsfluidclientoptions#@microsoft-live-share-iteamsfluidclientoptions-getlocaltestcontainerid) options passed to the TeamsFluidClient.
+When testing locally, `testLiveShare` updates the browser URL to contain the ID of the test container that was created. Copying that link to other browser tabs causes the `testLiveShare` to join the test container that was created. If the modification of the applications URL interferers with the operation of the application, the strategy used to store the test containers ID can be customized using the [setLocalTestContainerId](/javascript/api/@microsoft/live-share.iliveshareclientoptions#@microsoft-live-share-iliveshareclientoptions-setlocaltestcontainerid) and [getLocalTestContainerId](/javascript/api/@microsoft/live-share.iliveshareclientoptions#@microsoft-live-share-iliveshareclientoptions-getlocaltestcontainerid) options passed to `LiveShareClient`.
## Write the stage view
Many Teams Meeting Extensibility applications are designed to use React for thei
It's easy to create the view using local data without any Fluid functionality, then add Fluid by changing some key pieces of the app.
-The `renderStage` function appends the `stageTemplate` to the passed HTML element, and creates a working dice roller with a random dice value each time the **Roll** button is selected. The `diceMap` is used in the next few steps.
+The `renderStage` function appends the `stageTemplate` to the passed HTML element and creates a working dice roller with a random dice value each time the **Roll** button is selected. The `diceMap` is used in the next few steps.
```js const stageTemplate = document.createElement("template");
function renderStage(diceMap, elem) {
### Modify Fluid data
-To begin using Fluid in the application, the first thing to change is what happens when the user selects the `rollButton`. Instead of updating the local state directly, the button updates the number stored in the `value` key of the passed in `diceMap`. Because the `diceMap` is a Fluid `SharedMap`, changes are distributed to all clients. Any changes to the `diceMap` will cause a `valueChanged` event to be emitted, and an event handler can trigger an update of the view.
+To begin using Fluid in the application, the first thing to change is what happens when the user selects the `rollButton`. Instead of updating the local state directly, the button updates the number stored in the `value` key of the passed in `diceMap`. Because the `diceMap` is a Fluid `SharedMap`, changes are distributed to all clients. Any changes to the `diceMap` can cause a `valueChanged` event to be emitted, and an event handler can trigger an update of the view.
This pattern is common in Fluid because it enables the view to behave the same way for both local and remote changes.
rollButton.onclick = () =>
### Rely on Fluid data
-The next change that needs to be made is to change the `updateDice` function so it no longer accepts an arbitrary value. This means the app can no longer directly modify the local dice value. Instead, the value is retrieved from the `SharedMap` each time `updateDice` is called.
+The next change that needs to be made is to change the `updateDice` function, as it no longer accepts an arbitrary value. This means the app can no longer directly modify the local dice value. Instead, the value is retrieved from the `SharedMap` each time `updateDice` is called.
```js const updateDice = () => {
diceMap.on("valueChanged", updateDice);
## Write the side panel view
-The side panel view, loaded through the tab `contentUrl` with the `sidePanel` frame context, is displayed to the user in a side panel when they open your app within a meeting. The goal of this view is to let a user select content for the app prior to sharing the app to the meeting stage. For the Live Share SDK apps, the side panel view can also be used as a companion experience for the app. Calling [joinContainer()](/javascript/api/@microsoft/live-share/teamsfluidclient#@microsoft-live-share-teamsfluidclient-joincontainer) from the side panel view connects to the same Fluid container the stage view is connected to. This container can then be used to communicate with the stage view. Ensure that you're communicating with everyone's stage view _and_ side panel view.
+The side panel view, loaded through the tab `contentUrl` with the `sidePanel` frame context, is displayed to the user in a side panel when they open your app within a meeting. The goal of side panel view is to let a user select content for the app prior to sharing the app to the meeting stage. For the Live Share SDK apps, the side panel view can also be used as a companion experience for the app. Calling [joinContainer()](/javascript/api/@microsoft/live-share/liveshareclient#@microsoft-live-share-liveshareclient-joincontainer) from the side panel view connects to the same Fluid container the stage view is connected to. This container can then be used to communicate with the stage view. Ensure that you're communicating with everyone's stage view _and_ side panel view.
The sample's side panel view prompts the user to select the share to stage button.
function renderSidePanel(elem) {
## Write the settings view
-The settings view, loaded through `configurationUrl` in your app manifest, is shown to a user when they first add your app to a Teams Meeting. This view lets the developer configure the `contentUrl` for the tab that is pinned to the meeting based on user input. This page is currently required even if no user input is required to set the `contentUrl`.
+The settings view, loaded through `configurationUrl` in your app manifest, is shown to a user when they first add your app to a Teams meeting. This view lets the developer configure the `contentUrl` for the tab that is pinned to the meeting based on user input. This page is currently required even if no user input is required to set the `contentUrl`.
-> [!IMPORTANT]
-> The Live Share SDK's [joinContainer()](/javascript/api/@microsoft/live-share/teamsfluidclient#@microsoft-live-share-teamsfluidclient-joincontainer) is not supported in the tab `settings` context.
+> [!NOTE]
+> The Live Share's' [joinContainer()](/javascript/api/@microsoft/live-share/liveshareclient#@microsoft-live-share-liveshareclient-joincontainer) is not supported in the tab `settings` context.
The sample's settings view prompts the user to select the save button.
After you've started running your app locally with `npm run start`, you can then
1. Open Teams.
-1. Schedule a meeting from the calendar in Teams. Ensure you invite atleast one attendee to the meeting.
+1. Schedule a meeting from the calendar in Teams. Ensure you invite at least one attendee to the meeting.
1. Join the meeting.
platform Common Reasons For App Validation Failure https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/common-reasons-for-app-validation-failure.md
Title: Common reasons for app validation failure
-description: Learn the most common reasons for your app to fail the app validation. Broken links, errors in description, invalid policy links, valid domain guidelines violation, invalid support links, and more.
+description: Learn the most common reasons for app validation failure such as broken links, unexpected errors, crashes, valid domain guidelines violation, functional bugs.
platform Overview https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/post-publish/overview.md
Title: Maintain and support your published app
-description: Learn to maintain your published Microsoft Teams app and what to do after your store is listed on the Teams store and AppSource. Analyze app usage, publish updates, promote your app, complete Microsoft 365 Certification.
+description: Maintain your published Microsoft Teams app. Analyze app usage, publish updates, promote your app, complete Microsoft 365 Certification.
ms.localizationpriority: high
platform Teams Store Ranking Parameters https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/post-publish/teams-store-ranking-parameters.md
Title: Microsoft Teams store ranking parameters
-description: Understand Microsoft Teams store ranking parameters. Main parameters used to determine app placements are historical usage data, user engagement data, app quality and values, udience relevance, app update.
+description: Understand Microsoft Teams store ranking parameters such as historical usage and user engagement data, app quality and values, audience relevance, app update.
ms.localizationpriority: high
platform In App Purchase Flow https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/prepare/in-app-purchase-flow.md
Following code snippet is an example of calling the API from the Teams app built
</div> </body> <script>
- function openPurchaseExperience() {
- app.initialize();
- var planInfo = {
- planId: "<Plan id>", // Plan Id of the published SAAS Offer
- term: "<Plan Term>" // Term of the plan.
- }
+ function openPurchaseExperience() {
+ micorosftTeams.app.initialize();
+ var planInfo = {
+ planId: "<Plan id>", // Plan Id of the published SAAS Offer
+ term: "<Plan Term>" // Term of the plan.
+ }
monetization.openPurchaseExperience(planInfo); } </script>
platform Submission Checklist https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/prepare/submission-checklist.md
Title: Prepare your store submission
-description: Learn the final steps before submitting your Microsoft Teams app to be listed on the store. Learn to validate your app package. Know how to update Apple App Store Connect Team ID on Partner Center.
+description: Final steps before you submit your Microsoft Teams app to be listed on the store. Validate app package and complete publisher verification and attestation.
ms.localizationpriority: high
platform Teams Store Validation Guidelines https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/prepare/teams-store-validation-guidelines.md
Following these guidelines increases the chances of your app to pass the Microso
:::row::: :::column:::
- :::image type="content" source="../../../../assets/icons/value-proposition.png" alt-text="value-proposition-teams" link="#value-proposition":::
+ :::image type="icon" source="../../../../assets/icons/value-proposition.png" link="#value-proposition" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/security.png" alt-text="security-store" link="#security":::
+ :::image type="icon" source="../../../../assets/icons/security.png" link="#security" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/function.png" alt-text="functionality" link="#general-functionality-and-performance":::
+ :::image type="icon" source="../../../../assets/icons/function.png" link="#general-functionality-and-performance" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/package.png" alt-text="app-package" link="#app-package-and-store-listing":::
+ :::image type="icon" source="../../../../assets/icons/package.png" link="#app-package-and-store-listing" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/saas-offer.PNG" alt-text="saas" link="#apps-linked-to-saas-offer":::
+ :::image type="icon" source="../../../../assets/icons/saas-offer.PNG" link="#apps-linked-to-saas-offer" border="false":::
:::column-end::: :::row-end::: :::row::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/tab.png" alt-text="tab-teams" link="#tabs":::
+ :::image type="icon" source="../../../../assets/icons/tab.png" link="#tabs" border="false":::
:::column-end::: :::column:::
- :::image type="content" source="../../../../assets/icons/bot.png" alt-text="bot-teams" link="#bots-1":::
+ :::image type="icon" source="../../../../assets/icons/bot.png" link="#bots-1" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/messaging-extension.png" alt-text="messaging" link="#message-extensions":::
+ :::image type="icon" source="../../../../assets/icons/messaging-extension.png" link="#message-extensions" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/task-module.png" alt-text="task-module-teams" link="#task-modules":::
+ :::image type="icon" source="../../../../assets/icons/task-module.png" link="#task-modules" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/meeting.png" alt-text="meeting-extension" link="#meeting-extensions":::
+ :::image type="icon" source="../../../../assets/icons/meeting.png" link="#meeting-extensions" border="false":::
:::column-end::: :::row-end::: :::row::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/empty.png" alt-text="empty-2":::
+ :::image type="icon" source="../../../../assets/icons/notifications.png" link="#notifications" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/notifications.png" alt-text="teams-notification" link="#notifications":::
+ :::image type="icon" source="../../../../assets/icons/microsoft-365.png" link="#microsoft-365-app-compliance-program" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/microsoft-365.png" alt-text="microsoft" link="#microsoft-365-app-compliance-program":::
+ :::image type="icon" source="../../../../assets/icons/advertising.png" link="#advertising" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/advertising.png" alt-text="advertising-teams" link="#advertising":::
+ :::image type="icon" source="../../../../assets/icons/crypto-currency-based-apps-icon.png" link="#cryptocurrency-based-apps" border="false":::
:::column-end::: :::column span="":::
- :::image type="content" source="../../../../assets/icons/empty.png" alt-text="empty-1":::
+ :::image type="icon" source="../../../../assets/icons/app-functionality-icon.png" link="#app-functionality" border="false":::
+ :::column-end:::
+ :::column span="":::
+ :::image type="icon" source="../../../../assets/icons/mobile-experience-icon.png" link="#mobile-experience" border="false":::
:::column-end::: :::row-end:::
Following these guidelines increases the chances of your app to pass the Microso
An app's name plays a critical role in how users discover it in the store. Use the following guidelines to name an app: * The name must include terms relevant to your users.
-* Names of core Teams features must not be included in your app name, such as:
- * **Chat**
- * **Contacts**
- * **Calendar**
- * **Calls**
- * **Files**
- * **Activity**
- * **Apps**
- * **Help**
* Prefix or suffix common nouns with the developer's name. For example, **Contoso Tasks** instead of **Tasks**.
-* Must not use **Teams** or other Microsoft product names such as Excel, PowerPoint, Word, OneDrive, SharePoint, OneNote, Azure, Surface, Xbox, and so on, that could falsely indicate co-branding or co-selling. For more information about referencing Microsoft software products and services, see [Microsoft Trademark and Brand Guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks/usage/general).
-* If your app is part of an official partnership with Microsoft, the name of your app must come first. For example, **Contoso Connector for Microsoft Teams**.
+* Must not use **Teams** or other Microsoft product names such as Excel, PowerPoint, Word, OneDrive, SharePoint, OneNote, Azure, Surface, and Xbox that could falsely indicate co-branding or co-selling. For more information about referencing Microsoft software products and services, see [Microsoft Trademark and Brand Guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks/usage/general).
* Must not copy the name of an app listed in the store or other offer in the commercial marketplace. * Must not contain profane or derogatory terms. The name also must not include racially or culturally insensitive language.
-* Must be unique. If your app (Contoso) is listed in the Microsoft Teams store and Microsoft AppSource and you want to list another app specific to a geography, such as Contoso Mexico, your submission must meet the following criteria:
+* Must be unique. If your app (Contoso) is listed in the Microsoft Teams store and Microsoft AppSource and you want to list another app specific to a geography such as Contoso Mexico, your submission must meet the following criteria:
* Call out the app's region-specific functionality in the title, metadata, first response app experience, and help sections. For example, title must be Contoso Mexico. App title must clearly differentiate an existing app from the same developer to avoid end-user confusion. * When uploading the app package in Partner Center, select the right **Markets** where the app will be available in the **Availability** section.
- > [!TIP]
- > Your appΓÇÖs branding on the Microsoft Teams store and Microsoft AppSource including your app name, developer name, app icon, Microsoft AppSource screenshots, video, short description and website either separately or taken together must not impersonate an official Microsoft offering unless your app is an official Microsoft 1P offering.
+* App name must not lead with a core Teams feature such as Chat, Contacts, Calendar, Calls, Files, Activity, Teams, Apps, and Help. The app name can shorten to either Chat, Contacts, Calendar, Calls, Files, Activity, Teams, Apps, and Help on install in the left nav.
+
+* If your app is part of an official partnership with Microsoft, the name of your app must come first. For example, **Contoso Connector for Microsoft Teams**.
+
+* The app name must not have any reference to Microsoft or Microsoft products. DonΓÇÖt use **Teams**, **Microsoft**, or **App** in the app name unless your app is in official partnership with Microsoft. In such an instance, the app name must come first before any reference to Microsoft. For example, **Contoso connector for Microsoft Teams**.
+
+* DonΓÇÖt use parenthesis in naming to include Microsoft products.
+
+* Developer name must be the same in the manifest and AppSource.
+
+* App manifests submitted must be production manifests. Accordingly, app name must not indicate that the app is a pre-production app. For example, app name must not contain words such as Beta, Dev, Preview, and UAT.
+
+ > [!TIP]
+ > Your appΓÇÖs branding on the Microsoft Teams store and AppSource including your app name, developer name, app icon, AppSource screenshots, video, short description and website either separately or taken together must not impersonate an official Microsoft offering unless your app is an official Microsoft 1P offering.
</details>
Apps must focus on the Teams experience and not include the names, icons, or ima
### Feature names
-App feature names in buttons and other UI text must not duplicate with terminology reserved for Teams and other Microsoft products. For example, **Start meeting**, **Make call**, or **Start chat**. If necessary, include your app name, such as **Start Contoso meeting**.
+App feature names in buttons and other UI text must not use terminology reserved for Teams and other Microsoft products. For example, **Start meeting**, **Make call**, or **Start chat** are feature names in use by Microsoft in Microsoft Teams. If necessary, include your app name to make the distinction clear, such as **Start Contoso meeting**.
### Authentication
If your app authenticates users with an external service, follow these guideline
* When users sign out, they must sign out only from the app and remain signed in to Teams. * Apps that depend on external accounts or services must provide a way forward for new users to sign up or contact the app publisher to learn more about the services and get access to the services. Way forward must be available in the appΓÇÖs manifest, AppSource long description, and app first run experience (bot welcome message, tab setup or config page).
- * Apps that require tenant admin to complete one time setup must call out dependency on tenant admin to configure the app (before any other tenant user can install and use the app).
+ * Apps that require tenant admin to complete one time setup must call out dependency on tenant admin to configure the app (before any other tenant user can install and use the app).
Dependency must be called out in the appΓÇÖs manifest, AppSource long description, all first run experience touchpoints (bot welcome message, tab setup or config page), help text as considered necessary as part of bot response, compose extension, or static tab content. * **Content sharing experiences**: Apps that require authentication with an external service to share content in Teams channels must clearly state in the help documentation (or similar resources) on how to disconnect or unshare content if that feature is supported on the external service. This doesn't mean the ability to unshare content must be present in your Teams app.
If your app authenticates users with an external service, follow these guideline
[*Mandatory Fix*] <br></br> <details><summary>Expand to know more</summary>
Don't include domains outside of your organization's control (including wildcard
* If your app uses the Azure Bot Service's OAuthCard, you must include `token.botframework.com` as a valid domain or the **Sign in** button won't work. * If your app relies on SharePoint, you can include the associated root SharePoint site as a valid domain using the `{teamSiteDomain}` context property.
+* Don't use top level domains such as **.com**, **.in**, and **.org** as a valid domain. [*Mandatory Fix*]
-#### Government Community Cloud listings
+* Don't use **.onmicrosoft.com or** as a valid domain where **onmicrosoft** isn't under your control. However, you can use **yoursite.com** as a valid domain where **yoursite** is under your control even though the domain includes a wildcard. [*Mandatory Fix*]
-To distribute your app to Government Community Cloud (GCC) users, the authentication process must identify and route users to a GCC-specific or expected URL while avoiding duplicate listings in the Teams store.
+* If your app is a PowerApp built on the Microsoft Power Platform, you must include *apps.powerapps.com* as a valid domain to enable your app to be accessible and functional within Teams.
</details>
App must warn users before downloading any files or executables (.exe) into the
:::image type="icon" source="../../../../assets/icons/certificate-icon-16.png"::: This section is inline with [Microsoft commercial marketplace policy number 1140.4](/legal/marketplace/certification-policies#11404-functionality).
+* Way forward guidance is mandatory for both admin and existing users. You can add way forward guidance as hyperlinks to sign up, get started, contact us, help links, or email.
+* Calling out account dependency or limitations under app functionality isn't required but is mandatory to add it in both manifest long description and AppSource app listing.
+* You must call out any dependency on tenant admins for new users. If there's no dependency, it's mandatory to provide a sign up, contact us, get started link, or email.
+ ### Launching external functionality [*Mandatory Fix*] Apps must not take users out of Teams for core user scenarios. App content and interactions must occur within Teams capabilities, such as bots, Adaptive Cards, tabs, and task modules.
-<br></br>
+<br>
+</br>
+ <details><summary>Expand to know more</summary>
-Link users within Teams app and not to an external site or app. For scenarios that require external functionality, your app must take explicit user permission to launch the functionality.
+* Link users within Teams app and not to an external site or app. For scenarios that require external functionality, your app must take explicit user permission to launch the functionality.
+
+* Button UI text that launches external functionality must include content to indicate the user is taken out of the Teams instance. For example, include text such as **This way to Contoso.com** or **View in Contoso.com**.
-Button UI text that launches external functionality must include content to indicate the user is taken out of the Teams instance. For example, include text such as **This way to Contoso.com** or **View in Contoso.com**.
+* Add **Pop-out** icon to let the users know that they're being navigated outside Teams. You can use the pop-out icon :::image type="icon" source="../../../../assets/icons/pop-out-icon.png" ::: to the right of the link.
+
+* If you're unable to add a **Pop-out** icon, you can implement any of the following options to let the user know that they're being navigated outside Teams:
+ * Add a note in Adaptive Card that states that when users select **Get Help using this app**, it takes the user outside Teams.
+ * Add interstitials dialogs.
</details>
Apps must be fully functional on the latest versions of the following operating
* Microsoft Windows * macOS
-* Microsoft&nbsp;Edge
+* Microsoft Edge
* Google Chrome * iOS * Android
Teams apps must respond within a reasonable timeframe or show a loading or typin
App packages must be correctly formatted and include all required information and components.
-> [!TIP]
-> You must include the following detailed testing instructions for validating your app submission:
+> [!TIP]
>
-> * **Steps to configure the app test accounts** in case app depends on external accounts for authentication.
-> * Summary of **expected app behavior** for the core workflows within Teams.
-> * **Clearly describe Limitations**, conditions, or exceptions to the functionality, features, and deliverables in the app long description and related materials.
-> * **Emphasis on any considerations** for testers while validating your app submission.
-> * **Pre-populate the test accounts with dummy data** to aid testing.
+> * You must ensure the provided test accounts or test environment is valid in perpetuity, that is till the app is live on the commercial marketplace.
+> * You must include the following detailed testing instructions for validating your app submission:
+>
+> * **Steps to configure the app test accounts** in case app depends on external accounts for authentication.
+> * Summary of **expected app behavior** for the core workflows within Teams.
+> * **Clearly describe Limitations**, conditions, or exceptions to the functionality, features, and deliverables in the app long description and related materials.
+> * **Emphasis on any considerations** for testers while validating your app submission.
+> * **Pre-populate the test accounts with dummy data** to aid testing.
+> * If you are providing your test accounts, ensure that you enable third-party integration. Also, disable two-factor or multi-factor authentication.
### App manifest
The Teams app manifest defines your app's configuration.
* If your app includes a bot or message extension, details in the app manifest must be consistent with Bot Framework metadata including bot name, logo, privacy policy link, and terms of service link. * If your app uses Azure Active Directory for authentication, include the Microsoft Azure Active Directory (Azure AD) Application (client) ID in the manifest. For more information, see the [manifest reference](~/resources/schem#webapplicationinfo).
+### Uses of Latest manifest schema
+
+* If your app uses Single sign-on (SSO), you must declare Microsoft Azure Active Directory (Azure AD) ID in the manifest for user authentication. [*Mandatory Fix*]
+
+* You must use a publicly released manifest schema. You can update your app package to use a public version of manifest schema 1.10 or later. [*Mandatory Fix*]
+
+* When you submit an app update, only increase the app version number. App ID of the updated app must match the App ID of the published app. [*Mandatory Fix*]
+
+* The presence of additional files within the app package isn't acceptable. [*Mandatory Fix*]
+
+* The version number must be the same in the manifest file schema and additional languages manifest schema. [*Mandatory Fix*]
+
+* You must use the Teams manifest schema version 1.5 or later to localize your app. To use the app schema version 1.5 or later in your manifest.json file, update the `$schema` attribute to 1.5 or later. Update the `manifestVersion` property to `$schema` version (1.5 in this case). [*Mandatory Fix*]
+
+* When you add, update, or remove an existing capability, add or remove manifest or Partner Center metadata, you must increase the app version number and submit the new app manifest in your Partner Center account for validation.
+
+* The version string must follow the Semantic Versioning Specification (SemVer) standard (MAJOR.MINOR.PATCH). [*Mandatory Fix*]
+
+* If your app requires admins to review permissions and grant consent in Teams admin center, you must declare `webapplicationinfo` in the manifest. If `webapplicationinfo` isn't declared in the manifest, the **Permissions** page for your app in Teams admin center is shown as **...** [*Mandatory Fix*]
+
+* As part of Teams app certification, you must submit a production version of the app manifest. [*Mandatory Fix*]
+
+* We recommend that you declare the Microsoft Partner Network (MPN) ID in the manifest. The MPN ID helps identify the partner organization that builds the app. [*Suggested Fix*]
+ ### App icons [*Mandatory Fix*]
For more information, see [icon guidelines](~/concepts/build-and-test/apps-packa
### App descriptions
-You must have a short and long description of your app. The descriptions in your app configurations and Partner Center must be the same.
+You must have a short and long description for your app. The descriptions in your app configuration and Partner Center must be the same.
+++ <br></br> <details><summary>Expand to know more</summary>
-Descriptions must not directly or through insinuation disparage another brand (Microsoft owned or otherwise). Ensure your description doesn't include claims that can't be substantiated. For example, **Guaranteed 200 percent increase in efficiency**.
+Descriptions must not directly or through insinuation disparage another brand (Microsoft owned or otherwise). Ensure that your description doesn't include claims that can't be substantiated. For example, **Guaranteed 200 percent increase in efficiency**.
+
+* App description must not contain comparative marketing information. For example, don't use competitor logos or trademarks in the offer listing including tags or other metadata that references competing offers or marketplaces. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-comparitive-marketing-fail.png" alt-text="Graphic shows an example of comparative marketing information in app description.":::
+
+* Hyperlink contact details, get started, help, or sign up in app description.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-contact-deatils-hyperlinked.png" alt-text="Graphic shows an example of contact details hyperlinked in the app descriptions.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-contact-deatils-not-hyperlinked.png" alt-text="Graphic shows an example of contact details not hyperlinked in the app descriptions.":::
+
+* App description must identify the intended audience, briefly and clearly explain its unique and distinct value, identify supported Microsoft products and other software, and include any prerequisites or requirements for its use. You must clearly describe any limitations, conditions or exceptions to the functionality, features, and deliverables as described in the listing and related materials before the customer acquires your offer. The capabilities you declare must relate to the core functions and description of your offer. [*Mandatory Fix*]
+
+* If you update your app name, replace the old app name with new app name in the offer metadata in the manifest, AppSource, and wherever applicable. [*Mandatory Fix*]
+
+* Limitations and account dependencies must be called out in the manifest App Description, AppSource, and Partner Center. For example:
+ * Enterprise account
+ * Paid subscription
+ * Another license or account
+ * Language
+ * Public switched telephone network (PSTN) dialing
+ * Regional dependency
+ * Lead time for booking translators or live agents
+ * Role based functionality
+ * Dependency on native app
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-limitations-calledout-pass.png" alt-text="Graphic shows an example of limitations called out in app description.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-limitations-not-calledout-fail.png" alt-text="Graphic shows an example of limitations not called out in app descriptions.":::
+
+* If your app is supported for specific regions or geographical locations, you must call out that specific region dependency in the app description in manifest, Partner Center, and AppSource for that offer.
+
+* If you need to reference Teams, write the first reference in the app listing as Microsoft Teams. Later references can be shortened to Teams.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-teams-reference-pass.png" alt-text="Graphic shows an example of correct reference to Teams in app description.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-teams-reference-fail.png" alt-text="Graphic shows an example of incorrect reference to Teams in app description.":::
#### Short description
The long description can provide an engaging narrative that highlights your app'
**Dos:** * Use [Markdown](https://support.office.com/article/use-markdown-formatting-in-teams-4d10bd65-55e2-4b2d-a1f3-2bebdcd2c772) to format your description.+ * Use active voice and speak to users directly. For example, **You can ...**.+ * List features with bullet points so it's easier to scan the description.+ * Clearly describe limitations, features, conditions or exceptions to the functionality, and deliverables in the listing and related materials before the user installs your app. The Teams capabilities must relate to the core functions described in the listing.
-* Ensure the app description matches with the functionality available inside Teams app. Any reference to workflows outside the Teams app must be limited and distinctly called out from the Teams app functionality.
+
+* Ensure that the app description matches with the functionality available inside Teams app. Any reference to workflows outside the Teams app must be limited and distinctly called out from the Teams app functionality.
+ * Include a help or support link.+ * Refer to **Microsoft 365** instead of **Office 365**.
-* If you need to reference **Teams**, write the first reference as **Microsoft Teams**. Later references can be shortened to **Teams**.
+ * Use the following language when describing how the app works with Teams (or Microsoft 365): * **... works with Microsoft Teams.** * **... working with Microsoft Teams.**
The long description can provide an engaging narrative that highlights your app'
* Exceed 500 words. * Abbreviate **Microsoft** as **MS** or **MSFT**.+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-microsoft-abbreviated.png" alt-text="Graphic shows an example of abbreviating Microsoft as MS or MSFT for the first time in app description.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-microsoft-not-abbreviated.png" alt-text="Graphic shows an example of not abbreviating Microsoft as MS or MSFT for the first time in app description.":::
+ * Indicate the app is an offering from Microsoft, including using Microsoft slogans or taglines.
-* Use copyrighted brand names that you don't own.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-offering-from-microsoft.png" alt-text="Graphic shows an example of how not to indicate Microsoft offering in app description.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-no-offering-indication-from-microsoft.png" alt-text="Graphic that shows an example of how to write app description without using microsoft slogans and taglines.":::
+ * Use the following language unless you're a certified Microsoft partner: * **... certified for ...** * **... powered by ...** * Include typos, grammatical errors. * Unnecessarily capitalize the entire manifest or AppSource long description or app content.+
+ :::image type="content" source="../../../../assets/images/submission/validation-long-description-typos-pass.png" alt-text="Graphic shows an example of app long description without errors.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-long-description-typos-fail.png" alt-text="Graphic shows an example of app long description with typos and errors.":::
+ * Include links to AppSource.+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-description-link-to-appsource.png" alt-text="Graphic shows an example of a fail scenario with links to AppSource in app long description.":::
+ * Make unverified claims. For example, best, top, and ranked, unless it comes with the source of the claim. * Compare your offer with other marketplace offers.
Remember the following:
* Include content that accurately represents your app. * Use text judiciously. * Frame screenshots with a color that reflects your brand and include marketing content.
+* Use high-resolution screenshots that are sharp and contain legible and clearly readable text. [*Mandatory Fix*]
+* Use mockups that accurately depict the appΓÇÖs actual UI for the benefit of end-users. [*Mandatory Fix*]
+* Provide at least three screenshots in your appΓÇÖs marketplace listing.
+* If your Teams app is extensible to other Microsoft 365 hubs, the screenshots provided must depict the app functionality in other Microsoft 365 hubs.
+* At least one screenshot must depict your appΓÇÖs functionality on mobile devices.
+* We recommend that you provide captions in your screenshots to let the user clearly understand the app capability.
**Don'ts:**
-[*Suggested Fix*]
+* Include mockups that inaccurately reflect your app's actual UI, such as showing your app being used outside Teams.
-* Show specific devices, such as phones or laptops.
-* Capture any Teams or browser UI in your screenshots.
-* Include mockups that inaccurately reflect your app's actual UI, such as showing your app being used outside of Teams.
-
-> [!TIP]
-> A video can be the most effective way to communicate why people must use your app. A video also is the first thing users see in your listing. For more information, see [create a video for your store listing](~/concepts/deploy-and-publish/appsource/prepare/submission-checklist.md#create-a-video).
+> [!TIP]
+>
+> * A video can be the most effective way to communicate why people must use your app. A video also is the first thing users see in your listing.
+> * If you choose to provide a video in your app listing, you must turn off ads in YouTube or Vimeo settings before submitting the video link in the Partner Center. Videos provided in the app listing must not be more than 90 seconds in duration and must only depict the app functionality and integration with Microsoft Teams. For more information, see [create a video for your store listing](~/concepts/deploy-and-publish/appsource/prepare/submission-checklist.md#create-a-video).
</details>
Support URLs must include your contact details or a way forward for users to rai
[*Mandatory Fix*]
-If your app supports localization, your app package must include a file with language translations that display based on the Teams language setting. The file must conform to the Teams localization schema. For more information, see [Teams localization schema](~/concepts/build-and-test/apps-localization.md).
+* If your app supports localization, your app package must include a file with language translations that display based on the Teams language setting. The file must conform to the Teams localization schema. For more information, see [Teams localization schema](~/concepts/build-and-test/apps-localization.md).
+
+* App metadata content must be the same in `en-us` and other localization languages. [*Mandatory Fix*]
+
+* Supported languages must be displayed in the AppSource app description. For example, this app is available in X (X= localized language). [*Mandatory Fix*]
+
+* If the user's client settings don't match with any of your additional languages, the default language is used as the final fallback language. Update the `localizationInfo` property with the correct default language that your application supports. [*Mandatory Fix*]
+
+* Update the `localizationInfo` property with the correct default language your application supports or add localized content for manifest and Partner Center long and short description. [*Mandatory Fix*]
## Apps linked to SaaS offer <br></br> <details><summary>General</summary>
If your app supports localization, your app package must include a file with lan
* Provide introduction to subscribers on how to use the product. * Allow the subscriber to assign licenses.
-* Provide different ways to engage with support for issues, such as FAQ, knowledge base, and email address.
+* Provide different ways to engage with support for issues, such as FAQ, knowledge base, and email.
* Validate users to ensure that they donΓÇÖt already have license assigned through another user. * Notify users after license assignment.
-* Guide users through Teams chat bot or email, on how to add the app to Teams and get started.
+* Guide users on how to add the app to Teams and get started through Teams chat bot or email.
</details> </br>
If your app supports localization, your app package must include a file with lan
<details><summary>Configure and test SaaS application</summary>
-If setup of your app for testing purposes is complex, provide an end-to-end functional document, linked SaaS offer configuration steps, and instructions for license and user management as part of your "Notes for Certification".
+If setup of your app for testing purposes is complex, provide an end-to-end functional document, linked SaaS offer configuration steps, and instructions for license and user management as part of your *Notes for Certification*.
-> [!TIP]
+> [!TIP]
> You can add a video on how your app and license management works to assist the team for testing. </details>
If setup of your app for testing purposes is complex, provide an end-to-end func
## Tabs :::image type="icon" source="../../../../assets/icons/certificate-icon-16.png"::: This section is inline with [Microsoft commercial marketplace policy number 1140.4.2](/legal/marketplace/certification-policies#114042-tabs).
-If your app includes a tab, ensure it adheres to these guidelines.
+If your app includes a tab, ensure that it adheres to these guidelines.
> [!TIP] > For more information on creating a high-quality app experience, see [Teams tab design guidelines](~/tabs/design/tabs.md).
If your app includes a tab, ensure it adheres to these guidelines.
* Tab setup **must not dead-end** a new user. Provide a message on how to complete the action or workflow. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-create-new-account.png" alt-text="validation-tabs-setup-create-new-acc":::
-
- :::image type="content" source="../../../../assets/images/submission/validation-tabs-missing-forward-guidance.png" alt-text="validation-tabs-missing-fwd-guidance":::
-
- :::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-new-user.png" alt-text="validation-tabs-set-up-new-user":::
-
-* For the best first run experience, authenticate your users during the tab setup and not after. Authentication can happen outside the tab configuration window. [*Suggested Fix*]
+ :::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-new-user.png" alt-text="Graphic shows an example of Tab with a dead-end on setup.":::
-* The user must not leave the tab configuration experience inside Teams to create content outside of Teams and then return to Teams to pin it. Tab configuration screen must explain the value of configuration and how to configure. [*Mandatory Fix*]
+* The user must not leave the tab configuration experience inside Teams to create content outside Teams and then return to Teams to pin it. Tab configuration screen must explain the value of configuration and how to configure. [*Mandatory Fix*]
:::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-profile-name.png" alt-text="validation-tabs-set-up-profile-name":::
If your app includes a tab, ensure it adheres to these guidelines.
:::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-configuration-screen.png" alt-text="validation-tabs-set-up-configuration-screen":::
-* Tab configuration screen must not ask users to embed a URL. Asking users to configure a URL during tab setup is a broken UX, user leaves tab configuration screen, acquires URL, returns to the configuration screen and inputs the URL. A preexisting Teams feature already allows users to pin a website link in the channel. If your app asks user to embed a website URL during tab configuration and the app is limited to display the entire website content in the channel tab, your app doesn't offer significant value to the user. [*Mandatory Fix*]
+* Apps that require users to input a URL while configuring a tab must:
+ * Provide an appropriate way forward guidance for the user to acquire or generate the URL. [*Mandatory Fix*]
+ * Check for URL that is relevant or appropriate to the appΓÇÖs functionality as per the app description. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-configured-url.png" alt-text="validation-tabs-set-up-configured-url":::
+ :::image type="content" source="../../../../assets/images/submission/validation-tab-configuration-way-forward-url-pass.png" alt-text="Screenshot shows an example of tab configuration with a way forward for user to generate a URL.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-tab-configuration-way-forward-url-fail.png" alt-text="Screenshot shows an example of tab configuration without a way forward for user to generate a URL.":::
+
+* Hyperlink the contact us information in the configuration screen instead of plain text to help users to contact you for support requirements. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-tabs-setup-configured-url-two.png" alt-text="validation-tabs-set-up-configured-url-two":::
+* For a seamless first run user experience, we recommend that you hyperlink your support URL or email in the configuration screen. [*Suggested Fix*]
</details> </br>
If your app includes a tab, ensure it adheres to these guidelines.
:::image type="content" source="../../../../assets/images/submission/validation-views-applogin.png" alt-text="validation-views-app-login":::
-* Content can be simplified by breaking down across multiple tabs. [*Suggested Fix*]
+* Content can be simplified by breaking down across multiple tabs.
:::image type="content" source="../../../../assets/images/submission/validation-views-multiple-tabs.png" alt-text="val-views-multiple-tabs":::
-* Tabs shouldn't have a duplicate header. Remove the duplicate logo from the iframe since the tab framework already displays the app icon and name. [*Suggested Fix*]
+* Tabs shouldn't have a duplicate header. Remove duplicate logos from the I-frame since the tab framework already displays the app icon and name. [*Suggested Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-views-no-duplicate-header-logo.png" alt-text="Graphic shows an example of a tab without duplicate headers and logos.":::
- :::image type="content" source="../../../../assets/images/submission/validation-views-duplicate-header-logo.png" alt-text="validation-views-duplicate-head-logo":::
+ :::image type="content" source="../../../../assets/images/submission/validation-views-duplicate-header-logo.png" alt-text="Graphic shows an example of a tab with duplicate headers and logos.":::
</details> </br>
The following are the navigation guidelines:
Design your app with [basic](~/concepts/design/design-teams-app-basic-ui-components.md) and [advanced](~\concepts\design\design-teams-app-advanced-ui-components.md) Fluent UI components. -- - * Tabs with toolbar in left rail must leave 20 pixels spacing from Teams left navigation. [*Mandatory Fix*] :::image type="content" source="../../../../assets/images/submission/validation-navigation-spacing-between-toolbar.png" alt-text="validation-nav-spacing-between-toolbar":::
-* The secondary and third pages in a tab must be opened in a level two (L2) and level three (L3) view in the main tab area, which is navigated via breadcrumbs or left navigation. You can also include the following components to aid tab navigation: [*Mandatory Fix*]
+* The secondary and tertiary pages in a tab must be opened in a level two (L2) and level three (L3) view in the main tab area, which is navigated via breadcrumbs or left navigation. You can also use the following components to aid navigation in a tab:
* Back buttons * Page headers * Hamburger menus
-* Tab must not have a horizontal scroll. Whiteboarding apps and other apps that require a larger canvas to allow users to collaborate without a perceived broken app experience, can use horizontal scroll depending on their business need. [*Suggested Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-improper-navigation-leveles.png" alt-text="Screenshot that shows an example of in-meeting dialog with multiple navigation levels.":::
* Deep links in tabs must not link to an external webpage but within Teams. For example, task modules or other tabs. [*Mandatory Fix*]
Design your app with [basic](~/concepts/design/design-teams-app-basic-ui-compone
:::image type="content" source="../../../../assets/images/submission/validation-navigation-core-workflow-redirects-outside.png" alt-text="validation-nav-core-workflow-redirects-outside":::
+* Horizontal scroll must not be present in an in-meeting tab. [*Mandatory Fix*]
+
+* In-meeting dialogs used in your app must not allow horizontal scrolling. Use in-meeting dialogs sparingly and for scenarios that are light and task oriented. You can specify the width of the in-meeting dialogΓÇÖs I-frame within the supported size range to account for different scenarios. [*Mandatory Fix*]
+* Task modules used in your app must not allow horizontal scrolling. Task modules allow you to select different sizes to make the content responsive without the need of Horizontal scroll. If required, you can use a Stage View (a full screen UI component to surface your web content) to complete the workflow without Horizontal scroll. [*Mandatory Fix*]
+
+* Horizontal scroll present in the tab in a personal chat, channel, and in-meeting details tab in any scope isn't allowed if the entire tab canvas is scrollable, unless your tab uses an infinite canvas with fixed UI elements. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-horizontal-scroll-allowed-scenarios.png" alt-text="Graphic shows examples of all the scenarios in mobile where horizontal scroll is allowed.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-horizontal-scroll-allowed-kanban.png" alt-text="Graphic shows an example of horizontal scroll in Kanban board.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-horizontal-scroll-list-view-components.png" alt-text="Graphic shows an example of list view with many components.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-horizontal-scroll-fixed-board.png" alt-text="Graphic shows an example of horizontal scroll in a white board with infinite canvas and fixed board.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-horizontal-scroll-in-list-view.png" alt-text="Graphic shows an example of horizontal scroll in list view.":::
+
+* Horizontal scroll in Adaptive Cards must not be present in Teams. [*Mandatory Fix*]
+
+* Bottom rail used for navigation in tabs must not conflict with Teams native mobile app navigation. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-tab-bottom-rail-conflicts-with-teams-mobile.png" alt-text="Graphic shows an example of a tab that conflicts with Teams native mobile app navigation.":::
+ </details> </br>
Design your app with [basic](~/concepts/design/design-teams-app-basic-ui-compone
* Tabs must provide value beyond hosting an existing website. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-usability-app-provides-workflows.png" alt-text="validation-usability-app-provides-work-flows":::
-
- :::image type="content" source="../../../../assets/images/submission/validation-usability-website-i-framed.png" alt-text="validation-usability-website-i-frame":::
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-app-provides-workflows.png" alt-text="Graphic shows an example of an app with a workflow valuable to channel members within a team.":::
- :::image type="content" source="../../../../assets/images/submission/validation-usability-teams-app-identical-website.png" alt-text="validation-usability-teams-app-identical-websites":::
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-website-i-framed.png" alt-text="Graphic shows an example of an app with entire website in an I-frame without any back option.":::
* Content must not truncate or overlap within the tab.
Design your app with [basic](~/concepts/design/design-teams-app-basic-ui-compone
* Tabs must be responsive to Teams themes. When a user changes the theme, the app's theme must reflect the selection.
- :::image type="content" source="../../../../assets/images/submission/validation-usability-responsive-tabs.png" alt-text="validation-usability-responsive-tab":::
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-responsive-tabs.png" alt-text="Graphic shows an example of a tab responsive to a theme in Teams.":::
- :::image type="content" source="../../../../assets/images/submission/validation-usability-unresponsive-tabs.png" alt-text="validation-usability-unresponsive-tab":::
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-unresponsive-tabs.png" alt-text="Graphic shows an example of a Tab not responsive to theme in Teams.":::
-* Tabs must use Teams-styled components such as, Teams fonts, type ramps, color palettes, grid system, motion, tone of voice, and so on, whenever possible. For more information, see [tab design guidelines](/microsoftteams/platform/tabs/design/tabs). [*Suggested Fix*]
+* Tabs must use Teams styled components such as, Teams fonts, type ramps, color palettes, grid system, motion, tone of voice, whenever possible. For more information, see [tab design guidelines](/microsoftteams/platform/tabs/design/tabs). [*Suggested Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-usability-app-uses-diff-font.png" alt-text="validation-usability-app-uses-font":::
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-app-uses-diff-font.png" alt-text="Screenshot shows an example of a tab with calibri font instead of native Teams font.":::
* If your app functionality requires changes in settings, include a **Settings** tab. [*Suggested Fix*]
-* Tabs must follow Teams interaction design such as, in-page navigation, position and use of dialogs, information hierarchies, and so on. For more information, see [Microsoft Teams Fluent UI kit](~/concepts/design/design-teams-app-basic-ui-components.md)
+* Tabs must follow Teams interaction design such as, in-page navigation, position and use of dialogs, information hierarchies. For more information, see [Microsoft Teams Fluent UI kit](~/concepts/design/design-teams-app-basic-ui-components.md).
-* Tab content in the iframe must not include features that mimic Teams core capabilities. For example, bots, message extensions, calling, meeting, and so on.
+* Tab experiences must be fully responsive on mobile (Android and iOS).
-* Content in the landing page of the configurable tabs must be contextually same for all members of the channel.
+ > [!TIP]
+ >
+ > * Include a personal bot alongside a personal tab.
+ > * Allow users to share content from their personal tab.
+
+* Tab must not contain elements that completely obstruct or impede workflows within the tab. For example, bot inside a tab that can't be minimized.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-tab-elements-impede-workflow.png" alt-text="Graphic shows an example of tab with elements that impede workflows within the tab.":::
+
+* Tab must not have a broken functionality. Your offer must be a usable software solution and must provide the functionality, features, and deliverables as described in your listing and other related materials. [*Mandatory Fix*]
+
+* If your tabs contain a footer, ensure that you remove all links unrelated to app functionality from the footer.
+
+</details>
+</br>
+
+<details><summary>Scope selection</summary>
* Content in the landing page of configurable tabs must not be scoped for individual use and not include personal content such as **My Tasks** or **My Dashboard**.
+ :::image type="content" source="../../../../assets/images/submission/validation-configurable-tab-content-personal-scope.png" alt-text="Graphic shows an example of content in a configurable tab with personal scope such as My tasks or My dashboard.":::
+
+* After the configuration experience, the landing page must show a collaborative view for the entire team.
+ * If your app requires provision of a personal scope view for the user to enhance efficiency or workplace productivity, use filtered views, deep links to personal apps, or navigate to L2 or L3 views within the configurable tab and keep the landing page contextually the same for all the users.
- :::image type="content" source="../../../../assets/images/submission/validation-usability-configurable-tab-personal-info.png" alt-text="validation-usability-configurable-tab-pers-info":::
+* Content in the landing page of the configurable tabs must be contextually same for all members of the channel.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-usability-configurable-tab-personal-info.png" alt-text="Graphic shows an example of content in the landing page of the configurable tabs contextually different for all members.":::
* Configurable tabs must have focused functionality. :::image type="content" source="../../../../assets/images/submission/validation-usability-configurable-nested-tabs.png" alt-text="validation-usability-configurable-nested-tab":::
-* Tab experiences must be fully responsive on mobile (Android and iOS).
-
-> [!TIP]
->
-> * Include a personal bot alongside a personal tab.
-> * Allow users to share content from their personal tab.
- </details>
+<br/>
## Bots :::image type="icon" source="../../../../assets/icons/certificate-icon-16.png"::: This section is inline with [Microsoft commercial marketplace policy number 1140.4.3](/legal/marketplace/certification-policies#114043-bots).
-If your app includes a bot, ensure it adheres to these guidelines.
+If your app includes a bot, ensure that it adheres to these guidelines.
> [!TIP] > For more information on creating a high-quality app experience, see [Teams bot design guidelines](~/bots/design/bots.md).
+</br>
+<details><summary>Bot design guidelines</summary>
+
+* Your Teams app must follow [Teams bot design guidelines](../../../../bots/design/bots.md).
+
+* You must implement a task module to avoid multi-turn bot response when the workflow involves the user performing repetitive tasks. For example, use a task module to repetitively capture name, dob, place, and designation instead of using multi-turn conversations. [*Mandatory Fix*]
+
+* Any broken links, responses, or workflows in your app must be fixed. [*Mandatory Fix*]
+
+</details>
+ </br> <details><summary>Bot commands</summary> Analyzing user input and predicting user intent is difficult. Bot commands provide users a set of words or phrases for your bot to understand.
-* Listing supported bot commands in your app configurations is highly recommended. These commands display in the compose box when a user tries to message your bot.
+* You must list at least one supported bot command in the `{commandList}` section of your app manifest. These commands display in the compose box when a user tries to message your bot.
- :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-listed.png" alt-text="validation-bot-commands-list":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-listed.png" alt-text="Graphic shows an example of bot commands listed in the app manifest.":::
- :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-not-listed.png" alt-text="validation-bot-commands-not-list":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-not-listed.png" alt-text="Graphic shows an example of bot commands not listed in the app manifest.":::
* All commands that your bot supports must work correctly, including generic commands such as **Hi**, **Hello**, and **Help**.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-generic-response-pass.png" alt-text="Graphic shows an example of bot responding to generic commands.":::
- :::image type="content" source="../../../../assets/images/submission/validation-bot-help-command.png" alt-text="validation-bots-help-command":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-generic-no-response.png" alt-text="Graphic shows an example of bot with no response to generic commands.":::
* Bot commands must not lead a user to a dead end, the commands must always provide a way forward.
- :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-deadend.png" alt-text="validation-bot-commands-dead-end":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-deadend.png" alt-text="validation-bot-commands-dead-end":::
+
+* You must list at least one valid bot command in the `items.commands.title` section of the manifest and add a suitable description that gives clarity to the user on the bot command and its usage. Bot commands listed in the `commandLists` section of the manifest surface as pre-populated commands in the bot command menu and provide a way forward for the new user to interact with the bot. [*Mandatory Fix*]
+
+* Bot response must not contain any official Microsoft product images or avatars. Use your own assets in your app. Use of Microsoft product images in your app isn't allowed. You may only copy, modify, distribute, display, license, or sell Microsoft copyrighted product images if you're granted explicit permission within the End-User License Agreement (EULA), license terms that accompany the content, or in the [Microsoft Trademark and Brand guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks). [*Mandatory Fix*]
+
+* Bots must respond to user commands without displaying a continuous loading indicator. [*Mandatory Fix*]
+
+* Bot help command response must not redirect the user outside Teams. Bot help command response can redirect user to a canvas within the Teams app or provide a way forward response in an Adaptive Card. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-redirects-user-outside-teams.png" alt-text="Graphic shows an example of bot response redirecting user outside of Teams.":::
+
+* Bots must always provide a valid response to a user input even if the input is irrelevant or improper. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-response-valid-improper-input.png" alt-text="Graphic shows an example of a valid response for improper bot command.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-response-improper-response-invalid-command.png" alt-text="Graphic shows an example of an invalid response for improper bot command.":::
+
+* Special characters such as slash (**/**), must not be prefixed to bot commands. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-commands-special-characters.png" alt-text="Graphic shows an example of a failed scenario where special characters are prefixed to bot commands.":::
+
+* Bots must provide a valid response to invalid user commands. Bots must not dead-end the user or display an error if a user sends an invalid bot command. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-way-forward-for-invalid-command.png" alt-text="Graphic shows an example of bot providing a way forward for an invalid command.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-welcome-message-bot-dead-end-invalid-command.png" alt-text="Graphic shows an example of a failed scenario where a bot sends a same response for a valid and invalid command.":::
+
+* Bot functionality must be relevant to the scope in which the bot is installed and the bot must provide value in the installed scope. [*Mandatory Fix*]
+
+* Bots must not contain duplicate commands. [*Mandatory Fix*]
+
+* Bots must not display a typing indicator after responding to the user command, but can display a typing indicator while responding to the user command. [*Mandatory Fix*]
+
+* Bots must provide a valid response to the **help** command typed in lowercase or uppercase that provides the user with a way forward or lets the user access the help content related to the bot usage. Bots must provide a valid response even when the user hasn't logged onto the app. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-valid-response-lowercase.png" alt-text="Graphic shows an example of bot not providing a valid response for a command in lowercase or uppercase.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-valid-response-logged-app.png" alt-text="Graphic shows an example of a bot without a valid response when the user hasn't logged onto the app.":::
+
+* Bots must provide a valid response to **help** command.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-help-command.png" alt-text="Graphic shows an example of bot sending a valid response to help command.":::
+
+* Bot responses on mobile must be responsive without any data truncation that hampers the end-user's bot usage to complete desired workflows. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-response-no-truncate-mobile.png" alt-text="Graphic shows an example of a bot message without truncating on mobile.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-response-truncate-mobile.png" alt-text="Graphic shows an example of a bot message truncating on mobile.":::
+
+* All the links in a bot response adaptive card must be responsive. Any link that takes the user outside the Teams platform must have a clear redirect text such as, **View in..** or **This way to..**, a pop-out icon in the bot response action button, or have a suitable redirect text in the bot response message body. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-action-button-redirect-warning.png" alt-text="Graphic shows an example of bot response action button with a redirect.":::
+
+* By design, if your bot doesn't respond or support any user command and is a one way bot only intended to notify users. You must set `isNotificationOnly` to true in the manifest. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-command-isnotification-only-true.png" alt-text="Graphic shows an example of notification only property set to true in the app manifest.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-command-isnotification-only-not-true.png" alt-text="Graphic shows an example of notification only bot not responding for a user's message.":::
+
+* Bot user experience must not be broken on mobile platforms. Your bot must be fully responsive on mobile. [*Mandatory Fix*]
> [!TIP] > For personal bots, include a **Help** tab that further describes what your bot can do.
Analyzing user input and predicting user intent is difficult. Bot commands provi
* If the app has a complex configuration flow (requires an enterprise license or lacks an intuitive sign up flow), then bots in such apps must always send a welcome message during the first run.
-For best experience, the welcome message must include the value offered by the bot to users, who installed the bot in channel, how to configure the bot and briefly describe all supported bot commands. You can display the welcome message using an Adaptive Card with buttons for better usability. For more information, see [how to trigger a bot welcome message](~/bots/how-to/conversations/send-proactive-messages.md). For apps without a complex configuration flow, you can choose to trigger a welcome message during the bot first run experience. However, if a welcome message is triggered, it must follow the welcome message guidelines.
+ For best experience, the welcome message must include the value offered by the bot to users, who installed the bot in channel, how to configure the bot, and briefly describe all supported bot commands. You can display the welcome message using an Adaptive Card with buttons for better usability. For more information, see [how to trigger a bot welcome message](~/bots/how-to/conversations/send-proactive-messages.md). For apps without a complex configuration flow, you can choose to trigger a welcome message during the bot first run experience. However, if a welcome message is triggered, it must follow the welcome message guidelines.
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-message.png" alt-text="Graphic shows an example of bot sending a welcome message when the bot has a complex configuration workflow.":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-no-welcome-message.png" alt-text="Graphic shows an example of bot not sending a welcome message when the bot has a complex configuration workflow.":::
* Bot welcome messages in channels and chats are optional during first run, especially if the bot is available for personal use and performs similar actions. Your bot must not send welcome messages to users individually (it's considered [spamming](#botmessagespamming)). The message must also mention the person who added the bot.
- :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-message-not-triggered.png" alt-text="validation-bot-welcome-message-not-trigger":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-message-not-triggered.png" alt-text="validation-bot-welcome-message-not-trigger":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-message-triggered.png" alt-text="validation-bot-wel-message-trigger":::
+
+* Notification only bots must send a welcome message that clarifies that the bot is a notification only bot and users won't be able to interact with the bot. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-notification-only-welcome-message-pass.png" alt-text="Graphic shows an example of bot sending a welcome message that it's a notification only bot.":::
+
+* Welcome message must not dead-end the user. Welcome message must include the value offered by the bot to the users who installed the bot in channel, how to configure the bot, and briefly describe all supported bot commands. You can display the welcome message using an Adaptive Card with buttons for better usability. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-welcome-message-no-way-forward.png" alt-text="Graphic shows an example of a failed scenario where the bot has no way forward for the user in a welcome message.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-welcome-message-clear-way-forward.png" alt-text="Graphic shows an example of bot welcome message with a clear way forward for the user to complete the task.":::
+
+* Bot installed in a channel or group chat scope must not send proactive welcome message to all the team members in 1:1 chat. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-send-proactive-message-to-all-members.png" alt-text="Graphic shows an example of bot sending proactive welcome message to all the team members.":::
+
+* Notification only bot can send a proactive welcome message in a channel only if the message contains important information for any user to complete the configuration for the bot or clarifies the scenarios when notifications are triggered. [*Mandatory Fix*]
+
+* Bot installed in a channel or group chat scope must not send proactive messages (not just welcome message) that are irrelevant to all users in channel or group chat, instead must send proactive messages to the user over 1:1 chat. [*Mandatory Fix*]
+
+* Bot installed in a channel or group chat scope must not allow users to start individual workflows. Bots must complete individual workflows in 1:1 chat with the user. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-message-triggered.png" alt-text="validation-bot-wel-message-trigger":::
+* Bot welcome message must clearly call out the limitations related to bot usage in the installed scope. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-messahe-with-app-limitation.png" alt-text="Graphic shows an example of app limitation in bot welcome message.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-welcome-messahe-without-app-limitation.png" alt-text="Graphic shows an example of a bot without app limitation in a welcome message.":::
+
+* Welcome message must auto trigger on app install in a personal scope. If the bot doesn't send a welcome message in a personal scope, the user is lead to a dead-end. If the app doesn't include a complex configuration workflow, it's optional for the developer to trigger a welcome message in the channel or group chat scope. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-no-welcome-message-in-personal-scope.png" alt-text="Graphic shows an example of bot not sending a welcome message automatically in personal scope.":::
+
+* Welcome messages must trigger only once on bot install. Welcome messages must not trigger every time the user invokes the help command. Help command response must be focused to include a way for the user to access help related to the bot. [*Mandatory Fix*]
+
+* Welcome messages must not trigger with every bot command. This is considered spam. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-welcome-message-trigger-for-any-command.png" alt-text="Graphic shows an example for bot triggering a welcome message for any command.":::
+
+* Welcome message content must be related to the bot workflow mentioned in the appΓÇÖs long description and the installation scope. Welcome message must include the value offered by the bot to users who installed the bot in channel, how to configure the bot, and briefly describe all supported bot commands. [*Mandatory Fix*]
+
+* Bot must not send multiple welcome messages when triggered on app install. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-multiple-message-trigger-install.png" alt-text="Graphic shows an example of bot triggering multiple welcome messaged on app install.":::
+
+* App name in the welcome message must match the app name in the manifest. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-name-mismatch-manifeast-and-welcome-message.png" alt-text="Graphic shows an example of app name in welcome message not matching with the app name in the app manifest.":::
+
+* Welcome message must not display competitor chat based collaborative platform names unless the app provides specific interoperability.
+
+* Welcome message must not redirect the user to another Teams app, instead the welcome message must nudge the user to complete their first task and briefly describe all supported bot commands in the app. [*Mandatory Fix*]
+
+* Welcome message must not contain links to any app marketplace including AppSource. [*Mandatory Fix*]
+
+* If your app has a complex configuration workflow that requires admin led installation, doesn't have an intuitive and readily available sign up flow, or requires users to complete configuration steps outside the Teams experience and return then the bot must send a proactive welcome message in a team or group chat scope after installation. [*Mandatory Fix*]
+
+* If your bot sends a welcome message in the channel, it must not send it to users individually (It's considered spamming). The welcome message must also mention the person who added the bot. [*Suggested Fix*]
> [!TIP] > In welcome messages to individual users, a carousel tour can provide an effective overview of your bot and any other app features to encourage users to try bot commands. For example, **Create a task**.
Bots must not spam users by sending multiple messages in short duration.
:::image type="content" source="../../../../assets/images/submission/validation-bot-message-spamming-multiple-messages.png" alt-text="validation-bot-message-spam-multiple-message"::: * **Bot messages in personal apps**:
- * Don't send multiple messages in quick duration.
+ * Don't send multiple messages in quick succession.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-messages-multiple-message-quick-succession.png" alt-text="Graphic shows an example of a bot sending multiple messages in quick succession.":::
+ * Send one message with complete information. * Avoid multi-turn conversations to complete a single repetitive workflow. * Use a form (or task module) to collect all inputs from a user at one time.
Bots must not spam users by sending multiple messages in short duration.
:::image type="content" source="../../../../assets/images/submission/validation-bot-messages-using-task-module.png" alt-text="validation-bot-message-using-task-module":::
- :::image type="content" source="../../../../assets/images/submission/validation-bot-messages-using-mutliple-conversation.png" alt-text="validation-bot-messages-using-mutliple-conversations":::
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-messages-using-mutliple-conversation.png" alt-text="Graphic shows an example bot using multi-turn messages to complete a single conversation.":::
* **Welcome messages**: Don't repeat the same welcome message over regular intervals. For example, when a new member is added to a team, don't spam the other members with a welcome message. Message the new member personally.
+ :::image type="icon" source="../../../../assets/images/submission/validation-bot-send-proactive-message-to-all-members.png" alt-text="Graphic shows an example bot spamming users with same welcome message.":::
+ </details> </br>
A notification provides value in Teams if:
1. Posted card or text provides adequate details requiring no further user action. 1. Posted card or text provides adequate preview information for a user to take action or decide to view further details in a link opening outside Teams.
-Apps that provide only notifications with content such as **You have a new notification, click to view**, and require user to navigate outside of Teams for everything else don't provide significant value within Teams.
+Apps that provide only notifications with content such as, **You have a new notification**, **click to view** and require the user to navigate outside Teams for everything else don't provide significant value within Teams.
+ :::image type="content" source="../../../../assets/images/submission/validation-bot-notification-only-inadequete-info.png" alt-text="Screenshot shows an example of a notification only bit with inadequate information in the preview.":::
+> [!TIP]
+> Preview information and provide basic inline user actions in the posted card so that the user isn't required to navigate outside Teams for all actions (irrespective of complexity).
+</details>
+<br/>
-> [!TIP]
-> Preview information and provide basic inline user actions in the posted card so that the user is not required to navigate outside Teams for all actions (irrespective of complexity).
+<details><summary>Bot metadata information</summary>
+
+* Bot information in the app manifest (bot name, logo, privacy link, and terms of service link) must be consistent with the Bot Framework metadata. [*Mandatory Fix*]
+
+* Bot ID must match in the app manifest and Bot Framework metadata. [*Mandatory Fix*]
+
+* Ensure that the bot ID in the app manifest matches with bot ID in the last store published version of your app. Changing bot IDs in an app update leads to permanent loss of all user interaction history with the bot for existing users of your app and starts a new conversation chain with the new Bot ID. [*Mandatory Fix*]
+
+* Any change to app name, metadata, bot welcome message, or bot responses must be updated with new name. [*Mandatory Fix*]
+
+* App name in the bot welcome message or bot responses must match the app name in the manifest. [*Mandatory Fix*]
+
+</details>
+<br/>
+
+<details><summary>Bot in collaborative scope</summary>
+
+* Bot installation in a channel or group chat scope to obtain the team roster for sending proactive notifications for users as 1:1 chats for team specific triggers isn't allowed. For example, app that pairs people for a meetup. [*Mandatory Fix*]
+
+* Bot in channel or group chat only used to obtain the messages or posts in Channel or group chat for sending proactive notifications for users as 1:1 chats isn't allowed. [*Mandatory Fix*]
+
+* Bots installed in collaborative scope must provide a user value in the collaborative scope. [*Mandatory Fix*]
</details>
Apps that provide only notifications with content such as **You have a new notif
:::image type="icon" source="../../../../assets/icons/certificate-icon-16.png"::: This section is inline with [Microsoft commercial marketplace policy number 1140.4.4](/legal/marketplace/certification-policies#114044-messaging-extensions).
-If your app includes a message extension, ensure it adheres to these guidelines.
+If your app includes a message extension, ensure that it adheres to these guidelines.
> [!TIP] > For more information on creating a high-quality app experience, see the [Teams message extension design guidelines](~/messaging-extensions/design/messaging-extension-design.md).
+<br/>
+
+<details><summary>Messaging extensions design guidelines</summary>
+
+* If your Teams app uses the messaging extension capability, your app must follow the [Messaging extension design guidelines](../../../../messaging-extensions/design/messaging-extension-design.md).
+
+ :::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-design-guidelines-fail.png" alt-text="Graphic shows an example of an app not meeting extension guidelines.":::
+
+* Messaging extensions are shortcuts for inserting app content or acting on a message without navigating away from the conversation. Keep your messaging extension simple and display only the components required to effectively complete the action. Complete website must not be I-framed within the messaging extension [*Mandatory Fix*]
+
+* Preview images in Adaptive Cards in messaging extensions must load properly. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-preview-image-adaptive-card-loading.png" alt-text="Graphic shows an example of preview image loading in adaptive card.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-preview-image-adaptive-card-not-loading.png" alt-text="Graphic shows an example of preview image not loading in adaptive card.":::
+
+* Messaging extension response card must include the app icon to avoid end user confusion. [*Mandatory Fix*]
+
+* Your app must not have any broken functionality. App must not dead-end or block the user from completing a workflow in a messaging extension. [*Mandatory Fix*]
+
+* Messaging extensions must respond or work as intended in group chat and channel scopes. [*Mandatory Fix*]
+
+* You must include a way for the user to sign in or sign out from the messaging extension. [*Mandatory Fix*]
+
+</details>
</br>
-<details><summary>Action commands</summary>
+
+<details><summary>Action commands for Action-based message extensions</summary>
Action-based message extensions must do the following:
Action-based message extensions must do the following:
:::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-app-doesnot-pass-message.png" alt-text="validation-messaging-extension-app-doesnot-pass-messages":::
-* Incorporate the host app name instead of a generic verb for action commands triggered from a chat message, channel post, or call to action within apps. For example, use **Start a Skype Meeting** for **Start Meeting**, **Upload file to DocuSign** for **Upload file**, and so on. [*Suggested Fix*]
+* Incorporate the host app name instead of a generic verb for action commands triggered from a chat message, channel post, or call to action within apps. For example, use **Start a Skype Meeting** for **Start Meeting**, **Upload file to DocuSign** for **Upload file**. [*Suggested Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-action-command-host-name.png" alt-text="Graphic shows an example of host app name for an action command.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-action-command-verb.png" alt-text="Graphic shows an example of generic verb for an action command.":::
+
+* Invoking a message action must allow the user to complete the workflow. Errors, blank responses, or continuous loading indicators to make the message action functional as intended must not be present. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-continous-loading-indicator-action-command.png" alt-text="Graphic shows an example of continuous loading indicator when a bot invokes an action command.":::
+
+* Duplicate action commands must not be present. [*Mandatory Fix*]
+
+* Message actions must allow the user to complete the workflow as intended without an invalid response. [*Mandatory Fix*]
+
+* Apps with only action-based messaging extension must have the following end state:
- :::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-action-command-host-name.png" alt-text="validation-messaging-extension-action-command-host-names":::
+ * Post a relevant action as a notification either in the context where message extension is invoked or in 1:1 bot chat based on user scenario. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-messaging-extension-action-command-verb.png" alt-text="validation-messaging-extension-action-commands-verb":::
+ * Allow users to share cards with other users based on the action taken. This is to ensure that apps don't take silent actions. For example, a ticket is created based on a message in a channel, but the app doesn't send a notification or doesn't provide a way to request the user to share ticket details after the ticket is created. [*Mandatory Fix*]
</details> </br>
Message extensions must preview recognized links in the Teams compose box. Don't
* Search based message extensions must provide text that helps the users to search effectively. [*Mandatory Fix*]
- :::image type="content" source="../../../../assets/images/submission/validation-search-commands-text-available.png" alt-text="validation-search-command-text-available":::
+ :::image type="content" source="../../../../assets/images/submission/validation-search-commands-text-available.png" alt-text="Graphic shows an example of a message extension with help text for users to search effectively.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-search-commands-text-not-available.png" alt-text="Graphic shows an example of a message extension without help text for users to search effectively.":::
* @mention executables must be clear, easy to understand, and readable.
Message extensions must preview recognized links in the Teams compose box. Don't
</details> </br>
-<details><summary>Action commands</summary>Search based message extension only apps
+<details><summary>Action commands for Search based message extension</summary>
[*Mandatory Fix*] Apps that consist of search-based message extension provide user value by sharing cards that allow for contextual conversations without context switching.
-To pass validation for a search-based message extension only app, the following are required as baseline to ensure the user experience isn't broken. A card shared via a message extension provides value in Teams if:
+To pass validation for a search-based message extension only app, the following are required as baseline to ensure that the user experience isn't broken. A card shared via a message extension provides value in Teams if:
1. Posted card provides adequate details requiring no further user action. 1. Posted card provides adequate preview information for a user to take action or decide to view further details in a link opening outside Teams.
For more information, see [Teams task module design guidelines](~\task-modules-a
> For more information on creating a high-quality app experience, see the [Teams meeting extension design guidelines](~/apps-in-teams-meetings/design/designing-apps-in-meetings.md). </br>
+<details><summary>Meeting extension design guidelines</summary>
+
+* Your Teams apps must follow [Meeting extension design guidelines](../../../../apps-in-teams-meetings/design/designing-apps-in-meetings.md).
+
+* With the in-meeting app experience, you can engage participants during the meeting by using in-meeting tabs, dialog box, and the in-meeting share to stage feature. If your app supports Teams meeting extension, you must provide a responsive in-meeting experience aligned with the Teams meeting experience. [*Mandatory Fix*]
+
+* With the pre-meeting app experience, users can find and add meeting apps. Users can also do pre-meeting tasks such as developing a poll to survey the meeting participants. An app that provides a pre-meeting experience must be relevant to the meeting workflow and offer value to the user. [*Mandatory Fix*]
+
+* With post-meeting app experience, users can view the results of the meeting such as, poll survey results or feedback and other app content. An app that provides a post-meeting experience must be relevant to the workflow of the meeting and offer value to the user. [*Mandatory Fix*]
+
+* With the in-meeting app experience, you can engage meeting participants during the meeting and enhance the meeting experience for all the attendees. Attendees must not be taken outside the Teams meeting to complete core user workflows of the app. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-outside-teams-core-workflows.png" alt-text="Graphic shows an example of an in-meeting experience redirecting user outside Teams for completing core app functionality.":::
+
+* Your app must offer value beyond providing only custom Together Mode scenes in Teams. [*Mandatory Fix*]
+
+* You must declare `groupChat` as a scope under `configurableTabs` and `meetingDetailsTab`, `meetingChatTab`, and `meetingSidePanel` as a context property in the manifest to enable your app for meetings on Teams mobile. [*Mandatory Fix*]
+
+* Meeting canvases must not dead-end a meeting attendee. Meeting canvases must show a graceful failure message for app limitations such as, region specific dependency. [*Mandatory Fix*]
+
+* The meeting canvasΓÇÖ header must display the correct app name to avoid confusing the meeting attendee. [*Mandatory Fix*]
+
+* You must include an option for the user to sign out or log out from the meeting extension. [*Mandatory Fix*]
+
+* Meeting tabs on mobile platforms must include relevant workflows. Blank pages must not be present in a meeting tab. [*Mandatory Fix*]
+
+* Meeting stage is a focused, intuitive, and collaborative participation canvas. Meeting stage must not embed the complete website experience. [*Mandatory Fix*]
+
+* App must not show continuous loading screen, error, or broken functionality that dead-ends the user or blocks completion of a workflow in a meeting scenario. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-app-shows-continous-loading-screen.png" alt-text="Graphic shows an example of continuous loading screen in an app.":::
+
+* App must not open a new Teams instance on starting a meeting. Meeting canvases are an extension of the Teams capabilities that promote real time collaboration and new meetings must always open within the currently active Teams instance. [*Mandatory Fix*]
+
+* Meeting apps must complete workflows within the Microsoft Teams platform without redirecting to competitor chat based platforms. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-apps-redirecting-competitor-chat-platform.png" alt-text="Graphic shows an example of an app redirecting to competitor chat based platform.":::
+
+* If your app supports role based views and certain workflows are unavailable to all participants, we recommend that you implement proper messaging for participants in tab and side-panel stating that the app is currently for organizer's view and provide details about how the attendees will receive the meeting notes, action items, and update agendas. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-way-forward-not-available-for-role-based-views.png" alt-text="Graphic shows an example of an app without a way forward for participants in a role based view.":::
+
+</details>
+<br/>
+ <details><summary>General</summary> Use the following guidelines for meeting extensions:
-* Meeting extensibility apps must offer a responsive in-meeting experience and aligned to the Teams meeting experience. In-meeting experience is mandatory, pre and post-meeting experiences aren't mandatory.
+* Meeting extensibility apps must offer a responsive in-meeting experience aligned to the Teams meeting experience. In-meeting experience is mandatory for a Teams app that supports meeting extensibility but, pre and post-meeting experiences aren't mandatory.
- * With the pre-meeting app experience, users can find and add meeting apps. Users can also perform pre-meeting tasks, such as developing a poll to survey the meeting participants. If your app provides a pre-meeting experience, it must be relevant to the workflow of the meeting.
+ * With the pre-meeting app experience, users can find and add meeting apps. Users can also perform pre-meeting tasks such as developing a poll to survey the meeting participants. If your app provides a pre-meeting experience, it must be relevant to the workflow of the meeting.
- * With the post-meeting app experience, users can view the results of the meeting, such as poll survey results or feedback as well as other app content. If your app provides a post-meeting experience, it must be relevant to the workflow of the meeting.
+ * With the post-meeting app experience, users can view the results of the meeting such as, poll survey results or feedback and other app content. If your app provides a post-meeting experience, it must be relevant to the workflow of the meeting.
- * With the in-meeting app experience, you can engage meeting participants during the meeting and enhance the meeting experience for all the attendees. Attendees must not be taken outside of the Teams meeting for completing core user workflows of your app.
+ * With the in-meeting app experience, you can engage meeting participants during the meeting and enhance the meeting experience for all the attendees. Attendees must not be taken outside the Teams meeting for completing core user workflows of your app.
* Your app must offer value beyond providing custom Together Mode scenes in Teams. * Shared meeting stage feature can only be launched through the Teams desktop app. However, the shared meeting stage consumption experience must be usable and not broken when viewed on mobile devices. > [!TIP]
-> You must declare `groupchat` as a scope under `configurableTabs` and `meetingDetailsTab`, or `meetingChatTab` and `meetingSidePanel` as a context property in the manifest to enable your app for meetings on Teams mobile.
+> You must declare `groupChat` as a scope under `configurableTabs` and `meetingDetailsTab`, `meetingChatTab`, and `meetingSidePanel` as a context property in the manifest to enable your app for meetings on Teams mobile.
</details>- </br>+ <details><summary>Pre and post meeting experience</summary> * Pre and post meeting screens must adhere to general tab design guidelines. For more information, see [Teams design guidelines](~/tabs/design/tabs.md).
-* Tabs must not have horizontal scrolling.
* Tabs must have an organized layout when displaying multiple items. For example, more than 10 polls or surveys, see [example layout](~/apps-in-teams-meetings/design/designing-apps-in-meetings.md#after-a-meeting). * Your app must notify users when the results of a survey or poll are exported by stating, **Results successfully downloaded**.
+ :::image type="content" source="../../../../assets/images/submission/validation-meeting-experience-tab-design-guidelines-fail.png" alt-text="Graphic shows an example of tab not following tab design guidelines.":::
+ </details> </br>
Use the following guidelines for meeting extensions:
* Must maintain padding and component sizes. * Must have a back button if there's more than one layer of navigation.
- :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-exp-back-button.png" alt-text="validation-in-meeting-exp-back-buttons":::
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-exp-back-button.png" alt-text="Graphic shows an example of back button present.":::
- :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-exp-back-button-absent.png" alt-text="validation-in-meeting-exp-back-buttons-absent":::
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-exp-back-button-absent.png" alt-text="Graphic shows an example of back button not present.":::
* Must not include more than one close button. It may confuse users since there's already a built-in header button to dismiss the tab.
-* Must not have horizontal scrolling.
+* Must not have Horizontal scroll.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-tab-vertical-scroll.png" alt-text="Graphic shows an example of in-meeting tab with vertical scroll.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-tab-horizontal-scroll.png" alt-text="Graphic shows an example of in-meeting tab with horizontal scroll.":::
</details>
Use the following guidelines for meeting extensions:
* Must be used sparingly and for scenarios that are light and task oriented. * Must display content in a single column and not have multiple navigation levels.+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-single-column-layout.png" alt-text="Graphic shows an example of single column layout for in-meeting dialog.":::
+
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-multiple-column-layout.png" alt-text="Graphic shows an example of multiple column layouts for in-meeting dialog.":::
+ * Must not use task modules. * Must align with the center of the meeting stage.
- :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-dialog-not-aligned.png" alt-text="validation-in-meeting-dialog-not-align":::
+ :::image type="content" source="../../../../assets/images/submission/validation-in-meeting-dialog-not-aligned.png" alt-text="Graphic shows an example of in-meeting dialog not aligning with the center of meeting stage.":::
* Must be dismissed after a user selects a button or performs an action.
Use the following guidelines for meeting extensions:
:::image type="icon" source="../../../../assets/icons/certificate-icon-16.png"::: This section is inline with [Microsoft commercial marketplace policy number 1140.4.7](/legal/marketplace/certification-policies#114047-notification-apis).
-If your app uses the [activity feed APIs provided by Microsoft Graph](/graph/teams-send-activityfeednotifications), ensure it adheres to the following guidelines.
+If your app uses the [activity feed APIs provided by Microsoft Graph](/graph/teams-send-activityfeednotifications), ensure that it adheres to the following guidelines.
+
+> [!TIP]
+> If your apps supports notification scenarios where the notifications are triggered after long intervals, for example, after one day or one month. Before you submit for review, ensure that you trigger such notifications in the background for us to test the notifications.
+ <br></br>+
+<details><summary>Notification design guidelines</summary>
+
+* Your Teams apps must follow [activity feed notifications design guidelines](/graph/teams-send-activityfeednotifications).
+
+* Irrelevant, improper, unresponsive, or broken workflow must not be present after user selects a notification in Teams activity feed. Users must not be blocked from completing a workflow after they select an activity feed notification. [*Mandatory Fix*]
+
+* Include your appΓÇÖs name in the activity feed notification for end-users to understand the source or trigger for the notification without confusion. [*Mandatory Fix*]
+
+* App must trigger notifications for all the notification scenarios mentioned in the app long description, app first run experience, and in scenarios declared under `activityTypes` in the manifest. [*Mandatory Fix*]
+
+* Notifications must display within five seconds of user action. [*Mandatory Fix*]
+
+* You must call out notification limitations (if any) in your app long description or in the appΓÇÖs first run experience. [*Mandatory Fix*]
+
+</details>
+<br/>
+ <details><summary>General</summary> * All the notification triggers specified in your app configuration must work. * Notifications must be localized per the supported languages configured for your app. * Notifications must display within five seconds of user action.
+* Notifications must be localized as per the supported languages for all the platforms where your app is compatible. [*Mandatory Fix*]
</details> </br>+ <details><summary>Avatars</summary> * The notification avatar must match your app's color icon.
The Microsoft 365 App Compliance Program is intended to help organizations asses
* **Publisher Verification**: Helps admins and end users understand the authenticity of app developers integrating with the Microsoft identity platform. When completed, a blue **verified** badge displays on the Azure Active Directory consent dialog and other screens. For more information, see [Mark your app as publisher verified](/azure/active-directory/develop/mark-app-as-publisher-verified).
- :::image type="content" source="../../../../assets/images/submission/validation-365-compliance-publisher-verification.png" alt-text="validation-365-compliance-publisher-verifications":::
+ :::image type="content" source="../../../../assets/images/submission/validation-365-compliance-publisher-verification.png" alt-text="Graphic shows an example of a blue verified badge on the Azure Active Directory consent dialog.":::
* **Publisher Attestation**: A process in which you share general, data handling, and security and compliance information to help potential customers make informed decisions about using your app.
The Microsoft 365 App Compliance Program is intended to help organizations asses
Apps must not display advertising, including dynamic ads, banner ads, and ads in message. +
+## Cryptocurrency based apps
+
+You must demonstrate compliance with all laws where your app is distributed, if your app:
+
+* Facilitates cryptocurrency transactions or transmissions within the app.
+
+* Promotes cryptocurrency related content.
+
+* Enables users to store or access their stored cryptocurrency.
+
+* Encourages or enables users to complete a cryptocurrency based transaction or transmission outside the Teams platform.
+
+* Encourages or facilitates mining of cryptocurrency tokens.
+
+* Facilitates user participation in Initial Coin Offerings.
+
+* Rewards or incentivizes users with cryptocurrency tokens for completing a task.
+
+After an internal Microsoft review, if the compliance demonstration is satisfactory, Microsoft may proceed with further certification of your app. If the compliance demonstration is unsatisfactory, Microsoft will keep you informed of the decision to not proceed with certification of your app.
+
+## App Functionality
+
+* Workflows or content in the app must be related to the scope. [*Mandatory Fix*]
+* All app capabilities must be functional and must work properly as described in the AppSource or manifest long description. [*Mandatory Fix*]
+* Apps must always intimate the user before downloading any file or executable on the userΓÇÖs environment. Any call to action (CTA), either text based or otherwise, that makes it clear to the user that a file or executable is downloaded on user action is allowed in the app. [*Mandatory Fix*]
+
+## Mobile Experience
+
+* Mobile add-ins must be free. There must not be any in-app content or links that promote upselling, online stores, or other requests for payment. Any accounts required for apps must have no charge for use and if time-limited, must not include any content indicating a need to pay.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-mobile-add-in-charges.png" alt-text="Graphic shows an example of a mobile add-in asking for payment.":::
+
+* Use of the word **FREE**, **FREE TRIAL**, or **TRY FREE** is allowed on desktop or web app experience without any limitation or consideration.
+
+* Use of the word **FREE** as plain text in the context of a trial or app upgrade is allowed on mobile.
+
+* Use of the word **FREE** in the context of a trial or app upgrade with a link that leads to a landing page without payment or pricing information is allowed on mobile. Plain text to signal app is **PAID** is allowed on mobile.
+
+* Use of the word **FREE** as plain text in the context of a trial or app upgrade and associated with pricing details isn't allowed on mobile.
+
+* Use of the word **FREE** in the context of a trial or app upgrade and associated with a link that leads to a landing page with pricing information or payment details on mobile isn't allowed.
+
+* Pricing details on mobile in any format, for example, image, text, or link isn't allowed. CTA such as **view plans** on mobile isn't allowed. Information about plans without pricing details but with a contact link or email on mobile isn't allowed. Any text with contact details linking or alluding to a paid upgrade isn't allowed on mobile. Payments for physical goods are allowed on mobile. For example, your app can allow payment to book a taxi.
+
+ :::image type="content" source="../../../../assets/images/submission/validation-mobile-exp-pricing-details-on-mobile-fail.png" alt-text="Graphic shows an example of pricing details on mobile.":::
+
+* Payments for digital goods in app aren't allowed on mobile. [*Mandatory Fix*]
+
+ :::image type="content" source="../../../../assets/images/submission/validation-mobile-exp-payments-digital-goods.png" alt-text="Graphic shows an example of payments for digital goods on mobile.":::
+
+* Teams apps must offer an appropriate cross-device mobile experience. [*Mandatory Fix*]
+
+* Capabilities that aren't supported on mobile must not dead-end a user and must provide a graceful failure message where applicable. [*Mandatory Fix*]
+ ## Next step
-> [!div class="nextstepaction"]
+> [!div class=*nextstepaction*]
> [Create a Partner Center account](~/concepts/deploy-and-publish/appsource/prepare/create-partner-center-dev-account.md) ## See also
platform Update Apple Store Team Connect Id https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/prepare/update-apple-store-team-connect-id.md
Title: Update Apple Store Connect Team ID on Partner center
-description: Learn how to update your Apple App Store Connect Team ID in the Microsoft Partner Center to enable end-users to install your app on the Teams iOS platform.
+description: Update your Apple App Store Connect Team ID in the Microsoft Partner Center to enable end-users to search and acquire your app on the Teams iOS platform.
ms.localizationpriority: medium
platform Publish https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/publish.md
Title: Overview - Publish your app to the Microsoft Teams store
-description: Understand the process for publishing your app to Microsoft Teams store, what to expect after you submit, tips for rapid approval to publish your app and app linked to a SaaS offer.
+description: Publish your app to Microsoft Teams store or AppSource. What to expect after you submit, tips for rapid approval and publishing apps linked to a SaaS offer.
platform Resolve Submission Issues https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/resolve-submission-issues.md
Title: Resolve issues with your store submission
-description: Learn how to troubleshoot and correct problems with your Microsoft Teams store submission. Get help directly from Microsoft, resolve issues and resubmit your app.
+description: Troubleshoot and correct problems with your Microsoft Teams store submission. Get help directly from Microsoft, resolve issues and resubmit your app.
platform Create Channel Group Tab https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/create-channel-group-tab.md
zone_pivot_groups: teams-app-environment
# Create a channel tab
-Channel or group tabs deliver content to channels and group chats, and are a great way to create collaborative spaces around dedicated web-based content.
+Channel or group tabs deliver content to channels and group chats, which helps to create collaborative spaces around dedicated web-based content.
Ensure that you have all the [prerequisites](~/tabs/how-to/tab-requirements.md) to build your channel or group tab.
Ensure that you have all the [prerequisites](~/tabs/how-to/tab-requirements.md)
npm install yo gulp-cli --global ```
-2. At the command prompt, install Microsoft Teams App generator by entering the following command:
+2. At the command prompt, install Microsoft Teams app generator by entering the following command:
```cmd npm install generator-teams --global
Following are the steps to create a channel or group tab:
1. At the command prompt, create a new directory for your channel or group tab.
-1. Enter the following command in your new directory to start the Microsoft Teams App generator:
+1. Enter the following command in your new directory to start the Microsoft Teams app generator:
```cmd yo teams ```
-1. Provide your values to a series of questions prompted by Microsoft Teams App generator to update your `manifest.json` file:
+1. Provide your values to a series of questions prompted by Microsoft Teams app generator to update your `manifest.json` file:
![generator opening screenshot](/microsoftteams/platform/assets/images/tab-images/teamsTabScreenshot.PNG)
Following are the steps to create a channel or group tab:
* **Your (company) name? (max 32 characters)**
- Your company name will be used in the app manifest. Enter a company name or select **Enter** to accept the default name.
+ Your company name can be used in the app manifest. Enter a company name or select **Enter** to accept the default name.
* **Which manifest version would you like to use?**
Following are the steps to create a channel or group tab:
Select **( &ast; ) A Tab**.
- * **The URL where you will host this solution?**
+ * **The URL to host this solution?**
- By default, the generator suggests an Azure Web Sites URL. You're only testing your app locally, so a valid URL isn't necessary.
+ By default, the generator suggests an Azure website URL. You're only testing your app locally, so a valid URL isn't necessary.
* **Would you like show a loading indicator when your app/tab loads?**
gulp build
#### Run your application
-1. At the command prompt enter the following command to start a local web server:
+1. At the command prompt, enter the following command to start a local web server:
```bash gulp serve
gulp build
:::image type="content" source="~/assets/images/tab-images/homePage.png" alt-text="Default Tab":::
-1. To view your tab configuration page, go to `http://localhost:3007/<yourDefaultAppNameTab>/config.html`. The following is shown:
+1. To view your tab configuration page, go to `http://localhost:3007/<yourDefaultAppNameTab>/config.html`.
:::image type="content" source="~/assets/images/tab-images/configurationPage.png" alt-text="Tab configuration page":::
In the Visual Studio Solution Explorer window, right-click on the project and se
### Establish a secure tunnel to your tab
-At the command prompt in the root of your project directory run the following command to establish a secure tunnel to your tab:
+At the command prompt in the root of your project directory, run the following command to establish a secure tunnel to your tab:
```cmd ngrok http 3978 --host-header=localhost
Ensure that you keep the command prompt with ngrok running and make a note of th
```html <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js"></script>
- <script src="https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js"></script>
+ <script src="https://res.cdn.office.net/teams-js/2.2.0/js/MicrosoftTeams.min.js"
+ integrity="sha384yBjE++eHeBPzIg+IKl9OHFqMbSdrzY2S/LW3qeitc5vqXewEYRWegByWzBN/chRh"
+ crossorigin="anonymous" >
+ </script>
``` > [!IMPORTANT]
Ensure that you keep the command prompt with ngrok running and make a note of th
1. Insert a call to `microsoftTeams.app.initialize();` in the `script` tag.
-1. In Visual Studio Solution Explorer go to the **Pages** folder and open **Tab.cshtml**
+1. In Visual Studio Solution Explorer, go to the **Pages** folder and open **Tab.cshtml**
- Within **Tab.cshtml** the application presents the user with two options for displaying the tab with a red or gray icon. The **Select Gray** or **Select Red** button triggers `saveGray()` or `saveRed()` respectively, sets `pages.config.setValidityState(true)`, and enables **Save** on the configuration page. This code lets Teams know that you've completed the requirements configuration and can proceed with the installation. The parameters of `pages.config.setConfig` are set. Finally, `saveEvent.notifySuccess()` is called to indicate that the content URL has been successfully resolved.
+ Within **Tab.cshtml**, the application presents the user with two options for displaying the tab with a red or gray icon. The **Select Gray** or **Select Red** button triggers `saveGray()` or `saveRed()` respectively, sets `pages.config.setValidityState(true)`, and enables **Save** on the configuration page. This code lets Teams know that you've completed the requirements configuration and can proceed with the installation. The parameters of `pages.config.setConfig` are set. Finally, `saveEvent.notifySuccess()` is called to indicate that the content URL has been successfully resolved.
1. Update the `websiteUrl` and `contentUrl` values in each function with the HTTPS ngrok URL to your tab.
These files need to be zipped in an app package for use in uploading your tab to
#### .csproj
-In the Visual Studio Solution Explorer window, right-click on the project and select **Edit Project File**. At the end of the file you see the following code that creates and updates your zip folder when the application builds:
+In the Visual Studio Solution Explorer window, right-click on the project and select **Edit Project File**. At the end of the file you, see the following code that creates and updates your zip folder when the application builds:
```xml <PropertyGroup>
In the Visual Studio Solution Explorer window, right-click on the project and se
#### Models
-**ChannelGroup.cs** presents a Message object and methods that will be called from the controllers during configuration.
+**ChannelGroup.cs** presents a message object and methods that can be called from the controllers during configuration.
#### Views These are the different views in ASP.NET Core MVC:
-* Home: ASP.NET Core treats files called **Index** as the default or home page for the site. When your browser URL points to the root of the site, **Index.cshtml** will be displayed as the home page for your application.
+* Home: ASP.NET Core treats files called **Index** as the default or home page for the site. When your browser URL points to the root of the site, **Index.cshtml** can be displayed as the home page for your application.
-* Shared: The partial view markup **_Layout.cshtml** contains the application's overall page structure and shared visual elements. It will also reference the Teams Library.
+* Shared: The partial view markup **_Layout.cshtml** contains the application's overall page structure and shared visual elements that also reference the Teams Library.
#### Controllers
The controllers use the `ViewBag` property to transfer values dynamically to the
### Establish a secure tunnel to your tab
-At the command prompt in the root of your project directory run the following command to establish a secure tunnel to your tab:
+At the command prompt in the root of your project directory, run the following command to establish a secure tunnel to your tab:
```cmd ngrok http 3978 --host-header=localhost
Ensure that you keep the command prompt with ngrok running and make a note of th
```html <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js"></script>
- <script src="https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js"></script>
+ <script src="https://res.cdn.office.net/teams-js/2.2.0/js/MicrosoftTeams.min.js"
+ integrity="sha384yBjE++eHeBPzIg+IKl9OHFqMbSdrzY2S/LW3qeitc5vqXewEYRWegByWzBN/chRh"
+ crossorigin="anonymous" >
+ </script>
``` > [!IMPORTANT]
Ensure that you keep the command prompt with ngrok running and make a note of th
1. Insert a call to `microsoftTeams.app.initialize();` in the `script` tag.
-1. In Visual Studio Solution Explorer go to the **Tab** folder and open **Tab.cshtml**
+1. In Visual Studio Solution Explorer, go to the **Tab** folder and open **Tab.cshtml**
- Within **Tab.cshtml** the application presents the user with two options for displaying the tab with a red or gray icon. The **Select Gray** or **Select Red** button triggers `saveGray()` or `saveRed()` respectively, sets `pages.config.setValidityState(true)`, and enables **Save** on the configuration page. This code lets Teams know that you've completed the requirements configuration and can proceed with the installation. The parameters of `pages.config.setConfig` are set. Finally, `saveEvent.notifySuccess()` is called to indicate that the content URL has been successfully resolved.
+ Within **Tab.cshtml**, the application presents the user with two options for displaying the tab with a red or gray icon. The **Select Gray** or **Select Red** button triggers `saveGray()` or `saveRed()` respectively, sets `pages.config.setValidityState(true)`, and enables **Save** on the configuration page. This code lets Teams know that you've completed the requirements configuration and can proceed with the installation. The parameters of `pages.config.setConfig` are set. Finally, `saveEvent.notifySuccess()` is called to indicate that the content URL has been successfully resolved.
1. Update the `websiteUrl` and `contentUrl` values in each function with the HTTPS ngrok URL to your tab.
platform Create Personal Tab https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/create-personal-tab.md
Ensure that you have all the [prerequisites](~/tabs/how-to/tab-requirements.md)
npm install yo gulp-cli --global ```
-1. At the command prompt, install Microsoft Teams App generator by entering the following command:
+1. At the command prompt, install Microsoft Teams app generator by entering the following command:
```cmd npm install generator-teams --global
Following are the steps to create a personal tab:
1. At the command prompt, create a new directory for your personal tab.
-1. Enter the following command in your new directory to start the Microsoft Teams App generator:
+1. Enter the following command in your new directory to start the Microsoft Teams app generator:
```cmd yo teams ```
-1. Provide your values to a series of questions prompted by Microsoft Teams App generator to update your `manifest.json` file.
+1. Provide your values to a series of questions prompted by Microsoft Teams app generator to update your `manifest.json` file.
:::image type="content" source="~/assets/images/tab-images/teamsTabScreenshot.PNG" alt-text="Teams generator":::
Following are the steps to create a personal tab:
* **The URL where you will host this solution?**
- By default, the generator suggests an Azure Web Sites URL. You're only testing your app locally, so a valid URL isn't necessary.
+ By default, the generator suggests an Azure website URL. You're only testing your app locally, so a valid URL isn't necessary.
* **Would you like show a loading indicator when your app/tab loads?**
gulp build
#### Run your application
-1. At the command prompt enter the following command to start a local web server:
+1. At the command prompt, enter the following command to start a local web server:
```cmd gulp serve
gulp ngrok-serve
1. In the left pane of Teams, select ellipses &#x25CF;&#x25CF;&#x25CF; and then choose your uploaded app to view your personal tab.
- Now you have successfully created and added your personal tab in Teams.
+ Now you've successfully created and added your personal tab in Teams.
As you have your personal tab in Teams, you can also [reorder](#reorder-static-personal-tabs) your personal tab.
In Visual Studio Solution Explorer, right-click on the project and select **Edit
<script src="https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js" integrity="sha384-QtTBFeFlfRDZBfwHJHYQp7MdLJ2C3sfAEB1Qpy+YblvjavBye+q87TELpTnvlXw4" crossorigin="anonymous"></script> ```
-1. In Visual Studio Solution Explorer open **PersonalTab.cshtml** from **Pages** folder and add `app.initialize()` in the `<script>` tags and save.
+1. In Visual Studio Solution Explorer, open **PersonalTab.cshtml** from **Pages** folder and add `microsoftTeams.app.initialize()` in the `<script>` tags.
+
+1. Select **Save**.
1. In Visual Studio, select **F5** or choose **Start Debugging** from your application's **Debug** menu. ### Establish a secure tunnel to your tab
-At the command prompt in the root of your project directory run the following command to establish a secure tunnel to your tab:
+At the command prompt in the root of your project directory, run the following command to establish a secure tunnel to your tab:
```cmd ngrok http 3978 --host-header=localhost
ngrok http 3978 --host-header=localhost
1. Open **Apps** and select **Import app**.
-1. The app package file name is `tab.zip` and it is available at `/bin/Debug/netcoreapp3.1/tab.zip` path.
+1. The app package file name is `tab.zip` and it's available at `/bin/Debug/netcoreapp3.1/tab.zip` path.
1. Select `tab.zip` and open it in the Developer Portal.
ngrok http 3978 --host-header=localhost
1. In **App URLs**, update the Privacy policy to `https://<yourngrokurl>/privacy` and Terms of use to `https://<yourngrokurl>/tou` and select **Save**.
-1. In **App features**, select **Personal app** > **Create your first personal app tab** and enter the Name and update the **Content URL** with `https://<yourngrokurl>/personalTab`. Leave the Website URL field blank and select **Context** as personalTab from the dropdown list and select **Confirm**.
+1. In **App features**, select **Personal app** > **Create your first personal app tab** and enter the name and update the **Content URL** with `https://<yourngrokurl>/personalTab`. Leave the Website URL field blank and select **Context** as personalTab from the dropdown list and select **Confirm**.
1. Select **Save**.
ngrok http 3978 --host-header=localhost
:::image type="content" source="~/assets/images/tab-images/personaltabaspnetuploaded.png" alt-text="Default Tab":::
- Now you have successfully created and added your personal tab in Teams.
+ Now you've successfully created and added your personal tab in Teams.
As you have your personal tab in Teams, you can also [reorder](#reorder-static-personal-tabs) your personal tab.
The controllers use the `ViewBag` property to transfer values dynamically to the
<script src="https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js" integrity="sha384-QtTBFeFlfRDZBfwHJHYQp7MdLJ2C3sfAEB1Qpy+YblvjavBye+q87TELpTnvlXw4" crossorigin="anonymous"></script> ```
-1. In Visual Studio Solution Explorer open **PersonalTab.cshtml** from **Views** > **PersonalTab** folder and add `app.initialize()` inside the `<script>` tags and save.
+1. In Visual Studio Solution Explorer, open **PersonalTab.cshtml** from **Views** > **PersonalTab** folder and add `microsoftTeams.app.initialize()` inside the `<script>` tags.
+
+1. Select **Save**.
1. In Visual Studio, select **F5** or choose **Start Debugging** from your application's **Debug** menu. ### Establish a secure tunnel to your tab
-At the command prompt in the root of your project directory run the following command to establish a secure tunnel to your tab:
+At the command prompt in the root of your project directory, run the following command to establish a secure tunnel to your tab:
```cmd ngrok http 3978 --host-header=localhost
ngrok http 3978 --host-header=localhost
1. In **App URLs**, update the Privacy policy to `https://<yourngrokurl>/privacy` and Terms of use to `https://<yourngrokurl>/tou` and select **Save**.
-1. In **App features**, select **Personal app** > **Create your first personal app tab** and enter the Name and update the **Content URL** with `https://<yourngrokurl>/personalTab`. Leave the Website URL field blank and select **Context** as personalTab from the dropdown list and select **Confirm**.
+1. In **App features**, select **Personal app** > **Create your first personal app tab** and enter the name and update the **Content URL** with `https://<yourngrokurl>/personalTab`. Leave the Website URL field blank and select **Context** as personalTab from the dropdown list and select **Confirm**.
1. Select **Save**.
ngrok http 3978 --host-header=localhost
:::image type="content" source="~/assets/images/tab-images/personaltabaspnetmvccoreuploaded.png" alt-text="Personal tab":::
- Now you have successfully created and added your personal tab in Teams.
+ Now you've successfully created and added your personal tab in Teams.
As you have your personal tab in Teams, you can also [reorder](#reorder-static-personal-tabs) your personal tab.
ngrok http 3978 --host-header=localhost
## Reorder static personal tabs
-Starting with manifest version 1.7, developers can rearrange all tabs in their personal app. In particular, a developer can move the **bot chat** tab, which always defaults to the first position, anywhere in the personal app tab header. Two reserved tab `entityId` keywords are declared, **conversations** and **about**.
+Starting with manifest version 1.7, developers can rearrange all tabs in their personal app. You can move the **bot chat** tab, which always defaults to the first position, anywhere in the personal app tab header. Two reserved tab `entityId` keywords are declared, **conversations** and **about**.
If you create a bot with a **personal** scope, it appears in the first tab position in a personal app by default. If you want to move it to another position, you must add a static tab object to your manifest with the reserved keyword, **conversations**. The **conversation** tab appears on web or desktop depending on where you add the **conversation** tab in the `staticTabs` array.
platform Configuration Page https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/create-tab-pages/configuration-page.md
A configuration page is a special type of [content page](content-page.md). The u
## Configure a channel or group chat tab
-The application must reference the [Microsoft Teams JavaScript client SDK](/javascript/api/overview/msteams-client?view=msteams-client-js-latest&preserve-view=true) and call `app.initialize()`. The URLs used must be secured HTTPS endpoints and available from the cloud.
+The application must reference the [Microsoft Teams JavaScript client SDK](/javascript/api/overview/msteams-client) and call `app.initialize()`. The URLs used must be secured HTTPS endpoints and are available from the cloud.
### Example
The following code is an example of corresponding code for the configuration pag
```html <head>
- <script src='https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js'></script>
+ <script src="https://res.cdn.office.net/teams-js/2.2.0/js/MicrosoftTeams.min.js"
+ integrity="sha384yBjE++eHeBPzIg+IKl9OHFqMbSdrzY2S/LW3qeitc5vqXewEYRWegByWzBN/chRh"
+ crossorigin="anonymous" >
+ </script>
<body> <button onclick="(document.getElementById('icon').src = '/images/iconGray.png'); colorClickGray()">Select Gray</button> <img id="icon" src="/images/teamsIcon.png" alt="icon" style="width:100px" /> <button onclick="(document.getElementById('icon').src = '/images/iconRed.png'); colorClickRed()">Select Red</button>
- <script type="module">
- import {app, pages} from 'https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js';
- await app.initialize();
+ <script>
+ await microsoftTeams.app.initialize();
let saveGray = () => {
- pages.config.registerOnSaveHandler((saveEvent) => {
+ microsoftTeams.pages.config.registerOnSaveHandler((saveEvent) => {
const configPromise = pages.config.setConfig({ websiteUrl: "https://yourWebsite.com", contentUrl: "https://yourWebsite.com/gray",
The following code is an example of corresponding code for the configuration pag
} let saveRed = () => {
- pages.config.registerOnSaveHandler((saveEvent) => {
+ microsoftTeams.pages.config.registerOnSaveHandler((saveEvent) => {
const configPromise = pages.config.setConfig({ websiteUrl: "https://yourWebsite.com", contentUrl: "https://yourWebsite.com/red",
The following code is an example of corresponding code for the configuration pag
const colorClickGray = () => { gr.display = "block"; rd.display = "none";
- pages.config.setValidityState(true);
+ microsoftTeams.pages.config.setValidityState(true);
saveGray() } const colorClickRed = () => { rd.display = "block"; gr.display = "none";
- pages.config.setValidityState(true);
+ microsoftTeams.pages.config.setValidityState(true);
saveRed(); } </script>
Choosing the appropriate button triggers either `saveGray()` or `saveRed()`, and
* The `pages.config.registerOnSaveHandler()` event handler is triggered. * **Save** on the app's configuration page, is enabled.
-The configuration page code informs Teams that the configuration requirements are satisfied and the installation can proceed. When the user selects **Save**, the parameters of `pages.config.setConfig()` are set, as defined by the `Config` interface. For more information, see [config interface](/javascript/api/@microsoft/teams-js/pages.config?). `saveEvent.notifySuccess()` is called to indicate that the content URL has successfully resolved.
+The configuration page code informs Teams that the configuration requirements are met and the installation can proceed. When the user selects **Save**, the parameters of `pages.config.setConfig()` are set, as defined by the `Config` interface. For more information, see [config interface](/javascript/api/@microsoft/teams-js/pages.config?). `saveEvent.notifySuccess()` is called to indicate that the content URL has successfully resolved.
>[!NOTE] >
After your page uploads, Teams updates the query string placeholders with releva
```html <script>
- await app.initialize();
+ await microsoftTeams.app.initialize();
const getId = () => { let urlParams = new URLSearchParams(document.location.search.substring(1)); let blueTeamId = urlParams.get('team');
Authenticate before allowing a user to configure your app. Otherwise, your conte
## Modify or remove a tab
-Set your manifest's `canUpdateConfiguration` property to `true`. It enables the users to modify or reconfigure a channel or group tab. You can rename your tab only through Teams user interface. Inform the user about the impact on content when a tab is removed. To do this, include a removal options page in the app, and set a value for the `removeUrl` property in the `setConfig()` (formerly `setSettings()`) configuration. The user can uninstall personal tabs but cannot modify them. For more information, see [create a removal page for your tab](~/tabs/how-to/create-tab-pages/removal-page.md).
+Set your manifest's `canUpdateConfiguration` property to `true`. It enables the users to modify or reconfigure a channel or group tab. You can rename your tab only through Teams user interface. Inform the user about the impact on content when a tab is removed. To do this, include a removal options page in the app, and set a value for the `removeUrl` property in the `setConfig()` (formerly `setSettings()`) configuration. The user can uninstall personal tabs but can't modify them. For more information, see [create a removal page for your tab](~/tabs/how-to/create-tab-pages/removal-page.md).
Microsoft Teams `setConfig()` (formerly `setSettings()`) configuration for removal page:
platform Content Page https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/create-tab-pages/content-page.md
A content page is a webpage that is rendered within the Teams client, which is a
* A channel or group custom tab: The content page is displayed after the user pins and configures the tab in the appropriate context. * A [task module](~/task-modules-and-cards/what-are-task-modules.md): You can create a content page and embed it as a webview inside a task module. The page is rendered inside the modal pop-up.
-This article is specific to using content pages as tabs; however most of the guidance here applies regardless of how the content page is presented to the user.
+This article is specific to using content pages as tabs; however, most of the guidance here applies regardless of how the content page is presented to the user.
[!INCLUDE [sdk-include](~/includes/sdk-include.md)]
The following code provides an example of how your page and the Teams client com
<html> <head> ...
- <script src= 'https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js'></script>
+ <script src="https://res.cdn.office.net/teams-js/2.2.0/js/MicrosoftTeams.min.js"
+ integrity="sha384yBjE++eHeBPzIg+IKl9OHFqMbSdrzY2S/LW3qeitc5vqXewEYRWegByWzBN/chRh"
+ crossorigin="anonymous" >
+ </script>
...
+</head>
<body> ...
- <script type="module">
- import {app} from 'https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js';
- await app.initialize();
+ <script>
+ microsoftTeams.app.initialize();
</script> ... </body>
The following code provides an example of how your page and the Teams client com
<script src= 'https://statics.teams.cdn.office.net/sdk/v1.10.0/js/MicrosoftTeams.min.js'></script> ... </head>- <body> ... <script>
You can access additional content by using the SDK to interact with Teams, creat
### Use the SDK to interact with Teams
-The [Teams client JavaScript SDK](~/tabs/how-to/using-teams-client-sdk.md) provides many additional functions that you can find useful while developing your content page.
+The [Teams client JavaScript SDK](~/tabs/how-to/using-teams-client-sdk.md) provides many more functions that you can find useful while developing your content page.
### Deep links
You can create deep links to entities in Teams. They're used to create links tha
### Task modules
-A task module is a modal pop-up experience that you can trigger from your tab. In a content page, use task modules to present forms for gathering additional information, displaying the details of an item in a list, or presenting the user with additional information. The task modules themselves can be additional content pages, or created completely using Adaptive Cards. For more information, see [using task modules in tabs](~/task-modules-and-cards/task-modules/task-modules-tabs.md).
+A task module is a modal pop-up experience that you can trigger from your tab. In a content page, use task modules to present forms for gathering additional information, displaying the details of an item in a list, or presenting the user with additional information. The task modules themselves can be additional content pages or created completely using Adaptive Cards. For more information, see [using task modules in tabs](~/task-modules-and-cards/task-modules/task-modules-tabs.md).
### Valid domains
To show the loading indicator:
1. Add `"showLoadingIndicator": true` to your manifest. 1. Call `app.initialize();`.
-1. As a **mandatory** step, call `app.notifySuccess()` to notify Teams that your app has successfully loaded. Then, Teams hides the loading indicator, if applicable. If `notifySuccess` is not called within 30 seconds, Teams assumes that your app timed out, and displays an error screen with a retry option.
+1. As a **mandatory** step, call `app.notifySuccess()` to notify Teams that your app has successfully loaded. Then, Teams hides the loading indicator, if applicable. If `notifySuccess` isn't called within 30 seconds, Teams assumes that your app timed out, and displays an error screen with a retry option.
1. **Optionally**, if you're ready to print to the screen and wish to lazy load the rest of your application's content, you can hide the loading indicator manually by calling `app.notifyAppLoaded();`. 1. If your application doesn't load, you can call `app.notifyFailure({reason: app.FailedReason.Timeout, message: "failure message"});` to let Teams know about the failure and, optionally, provide a failure message. An error screen is shown to the user. The following code shows the enumeration that defines the possible reasons you can indicate for the application's failure to load:
platform Removal Page https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/create-tab-pages/removal-page.md
The optional removal page is an HTML page that you host and is displayed when th
### Register a remove handler
-Optionally, within your removal page logic, you can invoke the `registerOnRemoveHandler((RemoveEvent) => {}` event handler when the user removes an existing tab configuration. The method takes in the [`RemoveEvent`](/javascript/api/@microsoft/teams-js/pages.config.removeevent?view=msteams-client-js-latest&preserve-view=true) interface and executes the code in the handler when a user attempts to remove content. The method is used to perform cleanup operations such as removing the underlying resource powering the tab content. At a time only one remove handler can be registered.
+Optionally, within your removal page logic, you can invoke the `registerOnRemoveHandler((RemoveEvent) => {}` event handler when the user removes an existing tab configuration. The method takes in the [`RemoveEvent`](/javascript/api/@microsoft/teams-js/pages.config.removeevent?view=msteams-client-js-latest&preserve-view=true) interface and executes the code in the handler when a user attempts to remove content. The method is used to perform clean up operations such as removing the underlying resource powering the tab content. At a time only one, remove handler can be registered.
The `RemoveEvent` interface describes an object with two methods:
The following is a sample tab removal code block:
```html <body> <button onclick="onClick()">Delete this tab and all underlying data?</button>
- <script type="module">
- import {app, pages} from 'https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js';
- await app.initialize();
+ <script>
+ await microsoftTeams.app.initialize();
pages.config.registerOnRemoveHandler((removeEvent) => { // Here you can designate the tab content to be removed and/or archived. const configPromise = pages.getConfig();
platform Connectors Creating https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/webhooks-and-connectors/how-to/connectors-creating.md
With Microsoft Teams apps, you can add your existing Office 365 Connector or bui
See the following video to learn how to create an Office 365 Connectors: <br>
-> [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE4OIzv]
+> [!VIDEO <https://www.microsoft.com/en-us/videoplayer/embed/RE4OIzv>]
<br> [!INCLUDE [sdk-include](~/includes/sdk-include.md)]
To integrate the configuration experience:
1. Register `microsoftTeams.pages.config.registerOnRemoveHandler()` event handler, which is called when the user removes connector.
-This event gives your service an opportunity to perform any cleanup actions.
+This event gives your service an opportunity to perform any clean up actions.
The following code provides a sample HTML to create a connector configuration page without the customer service and support:
The following code provides a sample HTML to create a connector configuration pa
</section> </div>
-<script src="https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js" integrity="sha384-Q2Z9S56exI6Oz/ThvYaV0SUn8j4HwS8BveGPmuwLXe4CvCUEGlL80qSzHMnvGqee" crossorigin="anonymous"></script>
+<script src="https://res.cdn.office.net/teams-js/2.2.0/js/MicrosoftTeams.min.js" integrity="sha384-Q2Z9S56exI6Oz/ThvYaV0SUn8j4HwS8BveGPmuwLXe4CvCUEGlL80qSzHMnvGqee" crossorigin="anonymous"></script>
<script src="/Scripts/jquery-1.10.2.js"></script>
-<script type="module">
- import {app, pages} from 'https://res.cdn.office.net/teams-js/2.0.0/js/MicrosoftTeams.min.js';
-
+<script>
function onClick() { pages.config.setValidityState(true); }
- await app.initialize();
+ await microsoftTeams.app.initialize();
pages.config.registerOnSaveHandler(function (saveEvent) { var radios = document.getElementsByName('notificationType');
The following table provides the parameters and the details of `getConfig` respo
| `contentUrl` | The URL of the configuration page, as set by your code when calling `setConfig()`. | | `webhookUrl` | The webhook URL created for the connector. Use the webhook URL to POST structured JSON to send cards to the channel. The `webhookUrl` is returned only when the application returns data successfully. | | `appType` | The values returned can be `mail`, `groups`, or `teams` corresponding to the Office 365 Mail, Office 365 Groups, or Teams respectively. |
-| `userObjectId` | The unique ID corresponding to the Office 365 user who initiated the set up of the connector. It must be secured. This value can be used to associate the user in Office 365, who has set up the configuration in your service. |
+| `userObjectId` | The unique ID corresponding to the Office 365 user who initiated the setup of the connector. It must be secured. This value can be used to associate the user in Office 365, who has set up the configuration in your service. |
#### Handle edits
This call is made as part of your save event handler. Then, when the `contentUrl
#### Handle removals
-You can execute an event handler when the user removes an existing connector configuration. You register this handler by calling `microsoftTeams.pages.config.registerOnRemoveHandler()`. This handler is used to perform cleanup operations, such as removing entries from a database.
+You can execute an event handler when the user removes an existing connector configuration. You register this handler by calling `microsoftTeams.pages.config.registerOnRemoveHandler()`. This handler is used to perform clean up operations, such as removing entries from a database.
### Include the connector in your Manifest
platform Whats New https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/whats-new.md
Discover Microsoft Teams platform features that are generally available (GA). Yo
Microsoft Teams platform features that are available to all app developers.
-**2022 September**
+**2022 October**
-* ***September 30, 2022***: [Manage SaaS licenses for third party apps in Teams](concepts/deploy-and-publish/appsource/prepare/include-saas-offer.md#manage-license-for-third-party-apps-in-teams)
-* ***September 29, 2022***: [Teams mobile app now supports file downloads to local devices.](concepts/device-capabilities/media-capabilities.md#file-download-on-teams-mobile)
-* ***September 16, 2022***: [Adaptive Cards in search based message extensions now support Universal Actions.](messaging-extensions/how-to/search-commands/universal-actions-for-search-based-message-extensions.md)
-* ***September 06, 2022***: [Introduced code snippets for capturing videos using camera through `selectMedia` API.](concepts/device-capabilities/media-capabilities.md#code-snippets)
+* ***October 12, 2022***: [Apps are supported in instant meetings, one-on-one, and group calls.](apps-in-teams-meetings/teams-apps-in-meetings.md)
+* ***October 12, 2022***: [Live Share canvas](apps-in-teams-meetings/teams-live-share-canvas.md)
:::column-end::: :::row-end:::
Microsoft Teams platform features that are available to all app developers.
| **Date** | **Update** | **Find here** | | -- | | -|
+| 09/30/2022|Manage SaaS licenses for third party apps in Teams|Monetize your app > Include a SaaS offer with your Teams app > [Manage license for third party apps in Teams](concepts/deploy-and-publish/appsource/prepare/include-saas-offer.md#manage-license-for-third-party-apps-in-teams)|
+| 09/29/2022|Teams mobile app now supports file downloads to local devices.|Integrate device capabilities > Integrate media capabilities > [File download on Teams mobile](concepts/device-capabilities/media-capabilities.md#file-download-on-teams-mobile)|
+| 09/16/2022|Adaptive Cards in search based message extensions now support Universal Actions.|Build message extensions > Search commands > [Universal Actions for search based message extensions](messaging-extensions/how-to/search-commands/universal-actions-for-search-based-message-extensions.md)|
+| 09/06/2022|Introduced code snippets for capturing videos using camera through `selectMedia` API.| Integrate device capabilities > Integrate media capabilities > [Code snippets](concepts/device-capabilities/media-capabilities.md#code-snippets)|
| 08/09/2022 | Introduced Teams Toolkit for Visual Studio 2022 | Tools and SDK > Teams Toolkit for Visual Studio > [Teams Toolkit overview for Visual Studio](toolkit/teams-toolkit-overview-visual-studio.md) | | 08/03/2022 | Share to Teams from personal app or tab | Integrate with Teams > Share to Teams > [Share to Teams from personal app or tab](concepts/build-and-test/share-to-teams-from-personal-app-or-tab.md) | | 08/03/2022 | Added feature for retrieving meeting transcripts in the post-meeting scenario. | Build apps for Teams meetings and calls > Get meeting transcripts using Graph APIs > [Overview](graph-api/meeting-transcripts/overview-transcripts.md) |
Explore updates from the previous GA releases listed here.
| **Date** | **Update** | **Find here** | | -- | | |
-| 12/26/2019 | The `replyToId` parameter in payloads sent to a bot is no longer encrypted, allowing you to use this value to construct deeplinks to these messages. Message payloads include the encrypted values in the parameter `legacy.replyToId`. |
+| 12/26/2019 | The `replyToId` parameter in payloads sent to a bot is no longer encrypted, allowing you to use this value to construct deep links to these messages. Message payloads include the encrypted values in the parameter `legacy.replyToId`. |
| 11/05/2019 | Single sign-on using the Teams JavaScript SDK. | [Single sign-on](tabs/how-to/authentication/tab-sso-overview.md) | | 10/31/2019 | Conversational bots and message extension documentation updated to reflect the 4.6 Bot Framework SDK. Documentation for the v3 SDK is available in the Resources section. | All bot and message extension documentation | | 10/31/2019 | New documentation structure, and major article refactoring. Please report any dead links or 404's by creating a GitHub Issue. | All of them! |
Developer preview is a public program that provides early access to unreleased T
| 08/10/2022 | Apps for scheduled public channel meetings | Build apps for Teams meetings and calls > [Overview](apps-in-teams-meetings/teams-apps-in-meetings.md) | | 08/03/2022 | Mute and unmute APIs for apps in Teams meeting stage | Build apps for Teams meetings and calls > [Meeting apps API references](/microsoftteams/platform/apps-in-teams-meetings/api-references?tabs=dotnet) | | 08/02/2022| Collaboration controls for Teams| Integrate with Teams > [Collaboration controls](samples/collaboration-control.md) |
-| 06/30/2022 | Apps for instant meetings, one-on-one, and group calls| Build apps for Teams meetings and calls > [Overview](apps-in-teams-meetings/teams-apps-in-meetings.md)|
|05/24/2022| Enhanced collaboration with Live Share SDK | Build apps for Teams meetings > Enhanced collaboration with Live Share > [Overview](apps-in-teams-meetings/teams-live-share-overview.md) | | 02/03/2022 | Introduced app manifest version 1.13 | App manifest > Public developer preview > [Manifest schema](resources/schem) | | 01/17/2022 | People Picker in Adaptive cards for mobile | Build cards and task modules > Build cards > [People Picker in Adaptive Cards](task-modules-and-cards/cards/people-picker.md)|