APIs
Getting StartedREST API BasicsComplianceWebhooksWebex APIs
Admin
Calling
Contact Center
Devices
imiconnect
Meetings
Messaging
Webex Assistant Skills
Full API Reference
API Changelog

Embedded Apps Guide

The Webex Embedded Apps Framework allows Webex users to seamlessly interact with your third party application from within Webex.

anchorEmbedded App Framework Development Workflow
anchor

The general approach to developing embedded apps is similar to developing any other web app. The main difference is that your app runs within the context of a Webex Meeting or Space, rather than in an external web browser. Embedded apps integrate with the Embedded App Framework to enable the following features:

  • Ability to start an "Open Together" session with Meeting participants, or "Add to Tab" functionality in a Space.
  • Get information about the meeting or messaging space host and user information (if permitted by the user or organization), Webex or Meeting Center theme color (light or dark, for example), and other details.
  • Respond to events emitted by the framework about changes to the app's environment (theme change, for example), changes to the meeting host or space , or display context (sidebar or pop-out window).

The basic workflow for developing embedded apps is as follows:

  1. Create an embedded app in the Webex Developer Portal, providing the URL of your app's starting page. At this point your app is in development mode is only visible to your Webex account.
  2. Enable Developer Tools in Meeting Center or Spaces so you can debug your app within the embedded context.
  3. Open the app in a Meeting or Space to test it. Publish changes or fixes to your web host, and use the Reload menu item available the right-click/control-click context menu to reload your app's resources. In this way you can quickly iterate on changes directly in the Meeting or Space.
anchorEnabling Developer Tools in Meeting Client and Webex
anchor

To test and debug your embedded app while it runs in the Webex or Meeting Center client, you can use the standard developer tools available in Chrome and other modern web browsers. You first need to set a system flag or preference on your development system to enable access to developer tools.

To enable developer tools in the Meeting Center client:

  • On Windows, set EnableEmbeddedAppDebug to 1 in the Computer\HKEY_CURRENT_USER\SOFTWARE\WebEx\DeveloperTools registry key.
![Windows Registry key/value to enable debugging](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/bltf71da76e63e39ab8/6137f7094a026a122d2b6c5d/enable_dev_tools_windows.png)
  • On MacOS, run the following command:
```shell
defaults write NSGlobalDomain WebexWebAppDeveloperExtras -bool true
```

To enable developer tools in the Webex client:

  • On MacOS, create an empty file named cisco_spark_enable_webinspector.txt and save it to your Mac's Desktop folder, for example:
```shell
touch ~/Desktop/cisco_spark_enable_webinspector.txt
```

To open the developer tools, right-click (or Ctrl-click) anywhere inside the app's viewport and select Inspect Element. A Reload button also appears in the context menu, which you use to reload changes to your embedded app's assets.

Web inspector for embedded app

anchorDeveloper Quick Start
anchor

In this quick start you'll create and test a basic embedded app in a Webex meeting and a Webex space. You'll learn the following:

  • The basics of using the embedded app framework in a web application.
  • How to create and configure your embedded app in the Developer Portal.
  • How to test your app in Webex meetings and spaces.
  • How to respond to events generated by the framework.
  • How to retrieve user information with the Embedded App Framework API.
Prerequisites

The URL for your embedded app (the initiator app, as described previously) needs to be available at a publicly accessible URL. Similarly, any URLs that the initiator app shares with users via the setShareUrl() method must also be publicly accessible. Your app can require users to login to access private or protected resources, or to use the app generally, if desired.

Before getting started, select the two URLs that you'll use for the initiator app and the shared app. For example, these URLs might be "www.example.com/start.html" and "www.example.com/shared.html". You'll need the first URL when you create your app on the Developer Portal, and the second when you're writing code to call setShareUrl().

About the App You'll Create

As explained in overview of embedded apps, a complete embedded app solution involves two parts:

  • The initiator app that a user opens from the Apps tray in a Webex meeting or space. The purpose of this app is to open the URL of another embedded app with Webex meeting participants, or add as a tab to a Webex space.
  • The shared app is the app at the URL shared by the initiator app.

In this tutorial you’ll create two static HTML pages to represent these two apps. In a real-world solution these would be applications that provide richer user interactions and experience but the same concepts will apply.

Create the Embedded App's Start Page

You'll start by creating the HTML start page for your embedded app. The URL for this page is loaded when a user opens the Apps tray in a meeting or space and clicks your app.

  1. Create an HTML file named index.html and add the following code to it:
```html
<html>
<head>
  <title>Embedded Apps Quick Start</title>
  <script src="https://binaries.webex.com/static-content-pipeline/webex-embedded-app/v1/webex-embedded-app-sdk.js" defer></script>
  <script src="./index.js" defer></script>
</head>
<body>
    <h1>Embedded App Quick Start</h1>
    <p>This is the initator app. Its job is to specify a URL to share. Click <b>Set Share URL</b>, then click either <b>Open Together</b> (when running in a meeting) or <b>Add to tab</b> (when running in a space).</p>
    <button onclick="handleSetShare()">Set Share URL</button>
    <h2>Event Log</h2>
    <ul id="console" />
</body>
</html>
```

Note the following about this HTML:

  • The first <script> tag loads the Embedded Apps JavaScript library. Note the defer attribute on the script tag.
  • A second <script> tag that loads your app's index.js file, which you'll create next. Note the defer attribute on this script tag, as well. Scripts with this attribute execute in the order in which they appear in the document. This way you can be sure the framework has loaded before your app attempts to use it.
  • A <button> element that will be used to call setShareUrl(), passing it the URL to be opened with meeting participants, or added as a tab to a space. You'll define the handleSetShare() function specified by the "onclick" attribute next.
  • A <ul> element used to display log statements. The native console.log() function is also available to your app (once you've enabled developer tools in Meeting Center and Webex) but this provides an easier way to view app output.
  1. Save your changes to index.html. Next you'll create the app's index.js JavaScript file.
  2. Create a JavaScript file named index.js and add to it the following code:
```javascript
// Create a new Webex app instance
var app = new window.Webex.Application();

// Wait for onReady() promise to fulfill before using framework
app.onReady().then(() => {
    log("App ready. Instance", app);
}).catch((errorcode) =>  {
    log("Error with code: ", Webex.Application.ErrorCodes[errorcode])
});

// Button click handler to set share URL
function handleSetShare() {
    // Replace this with the URL of your shared page
    var url = "https://www.example.com/shared.html"
    // "Shared App" is the title of the window or tab that will be created
    app.setShareUrl(url, "", "Shared App").then(() => {
        log("Set share URL", url);
    }).catch((errorcode) => {
        log("Error: ", Webex.Application.ErrorCodes[errorcode])
    });
}

// Utility function to log app messages
function log(type, data) {
    var ul = document.getElementById("console");
    var li = document.createElement("li");
    var payload = document.createTextNode(`${type}: ${JSON.stringify(data)}`);
    li.appendChild(payload)
    ul.prepend(li);
}
```

Note the following about this code:
  • It first creates a new instance. This is the main app object you'll use to set sharing URLs, register event listeners, get information about the app's context and environment, and more.
  • The app.onReady() promise handler displays an "App ready" message (using a custom log() function) in the console if the promise is fulfilled, or an error code if the promise fails. Apps should always wait for the onReady() promise to be fulfilled successfully before using the framework. The framework behavior's is undefined if used before the onReady() is fulfilled, or if the promise fails.
  1. Save index.js in the same folder as index.html and publish them to your web host. Note the URL as you'll use it next to create your app on the Developer Portal. Next, you'll create the HTML page whose URL the initiator app shares.
Create the Shared Embedded App Page

Next you'll create the embedded app page whose URL is shared by the initiator app. For this example the shared page displays the ID of the current user using the method.

  1. Create an HTML file named shared.html and add the following code to it:
```html
<html>
<head>
    <title>Embedded App Test</title>
    <script src="https://binaries.webex.com/static-content-pipeline/webex-embedded-app/v1/webex-embedded-app-sdk.js" defer></script>
    <script src="./shared.js" defer></script>
</head>
<body>
    <h2>Shared page</h2>
    <p>This page was shared by the initator app.</p>
    <ul id="console" />
</body>
</html>
```
Like the start page HTML (except without the buttons) the shared app loads the framework JavaScript library and a custom script file (shared.js), which you'll create next.
  1. Create a JavaScript file named shared.js in the same folder as shared.html that contains the following code.
```javascript
var app = new window.Webex.Application();

// Wait for onReady promise, handle error scenario
app.onReady().then(() => {
    log("Application ready. App", app);
    // Display the ID of the current user
    app.context.getUser().then((user)=> {
        log("User ID", user.id)
    }).catch((errorcode) => {
        log("Error", errorcode)
    })
}).catch((errorcode) =>  {
    log("Error with code: ", Webex.Application.ErrorCodes[errorcode])
});

function log(type, data) {
    var ul = document.getElementById("console");
    var li = document.createElement("li");
    var payload = document.createTextNode(`${type}: ${JSON.stringify(data)}`);
    li.appendChild(payload)
    ul.prepend(li);
}
```

This code largely similar to that used in the [iniator app](/docs/api/guides/embedded-apps-guide#create-the-embedded-apps-start-page) but also displays the value of the `user.id` field returned by the [`app.context.getUser()`](/docs/api/guides/embedded-apps-reference#Webex.Application.Context+getUser) in the app's log console.
  1. Save your changes to shared.html and shared.js and publish them to your web host.
Create your Embedded App on the Developer Portal

Next you'll create your embedded application on the Developer Portal. You'll need to provide the following information about your embedded app:

  • If the app will run in a Webex Meeting, Space, or both. In this case the app will be available in both contexts.
  • The URL of the initiator app (index.html) that you previously created. You can specify unique URLs for in-meeting and in-space versions of the initiator app, but for this example you'll use the same start page URL for both contexts.
  • A list of valid domains for your start page URL, and for any URLs that will be shared by the initiator app. In this case initiator page and shared page are being served from the same domain so there will only be one domain one need to add.
  • App name, description, and icon, and other common app metadata.

For more information about creating your, see Creating an Embedded App in the Developer Portal.

To create your app on the Developer Portal:

  1. Login to the Developer Portal and click Start Building Apps or select My Webex Apps from the profile menu in the upper-right.
  1. Click Create a New App, then click Create Embedded App.
  1. In the New Embedded App page enter the requested information for your application:
  • Where does your app work? — Select both Meeting and Messaging.
  • Embedded app name — App name that appears in Apps picker in a meeting or space.
  • Description — App's description.
  • Tag line — App's tagline.
  • Icon — App's icon. Select one of the default icons or upload a 512x512px custom icon in PNG or JPEG formats.
  • Start page URL — URL of the initiator app that you created previously (for example, www.example.com/index.html).
  • Valid domains — The domain(s) where you host your embedded application's start page URL, and any other URLs shared by the initiator app using .
Leave the other fields blank. The following shows the configuration for an sample in-meeting application.
  1. Click Add Embedded App.

Now you're ready to test your app in a Webex meeting or space. At this point your embedded app is in development mode and is only visible in the Apps tray to you (the user who created the app). An app must be approved by your Web organization administrator before others can see it in your organization.

Open the Shared App in a Meeting

Next you'll start a meeting and open the initiator app. You'll click the Set Share URL button, and then click Open together to open the app for other meeting participants. To fully test the end-user experience you will need to invite another user in your organization to your meeting.

To test your embedded application in a meeting:

  1. Start a new meeting and invite another user in your organization to join as a participant.
<div><Callout type="info">You must start the meeting using the Meeting Client desktop app, not the web app.</Callout></div>
  1. Click the Apps tray and then click your application in the tray to open it. Because the app hasn't been approved for use in your organization a privacy dialog appears first appears, as shown below. The app user can decide if they want to share their private information with the app or not. See About Access to Private Data in Embedded Apps for more information.
![Access to private data dialog before opening app](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt3cd8bceeba599606/61776d0eac68a827432693b4/warning_pii.png)
  1. Select Open and share my personal information, then click Open. The initiator app opens and the "ready" message is logged to the app console, as shown below.
![Initiator app running in a meeting](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt2180523397b25eb9/61776d46da02001d99f299e6/app-running-in-meeting.png)
  1. Click Set Share URL, which makes the Open together button visible.
![Calling setSharURL method](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blteb31e9a55813ef11/61776d69de12c91d936cccc1/set-share-url-clicked.png)
  1. Click Open together.
The meeting participant you invited sees a window open with the same privacy dialog.
  1. The participant clicks Open and the URL shared by initiator app (shared.html) opens in the app window.
![Meeting participant view](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/bltf71d28d756507881/61776da599dfaf274905ca66/open-together-participant-view.png)

Note that the user ID is displayed in the app console.
  1. In the initiator app, click Stop session, which has replaced the Open together button. The app window closes for the meeting participant.
![Stop session](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt6c88926ec23b4adb/61776dd2da02001d99f299e8/stop-session.png)
Add the Shared App to a Space

Next you'll use the initiator app to add the shared URL as a tab to a Webex meeting space. Any user that's a member of the space can open and view the app.

To add your embedded application to a space:

  1. In Webex and open an existing space, or create a new space.
  1. Click the + Apps tab in the space to open the Apps dialog, and scroll to the bottom of the list to view in-development apps.
![Apps dialog in space](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt6e3663b6c52d282e/61776dfdda02001d99f299ea/space-open-app.png)
  1. Click your app in the list. The same privacy dialog appears as in the meeting context.
  1. Select a privacy option and click Open to open the initiator app.
![Initiator app open in-space](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt295b36c0d75f68e6/61776e4a428dce288b074e90/space-app-opened.png)
  1. Click Set Share URL to enable the Add to tab button.
![Add to tab button](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/bltf1ee8225d0d54f2c/61776e81b685fa1bb581b75b/space-app-add-to-tab.png)
  1. Click Add to tab. The app appears as a tab in the space. All users in the space can see the tab.
![Space added](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt9aa812dd01ab186d/61776eaaac68a827432693b6/space-added-to-tab.png)
anchorResponding to Events
anchor

The framework emits events in response to changes to the meeting, space, or application (Webex or Meeting Center client) in which an embedded app is running. Embedded apps can create event listeners to respond to these events, as needed. The following events are currently generated by the framework. The event object passed to your app's event listener contains details about the event.

  • application:shareStateChanged — Fired when an embedded app starts or stops a sharing session.
  • application:displayContextChanged — Fired when the app's rendering context changes, such as when a user pops out the app from the sidebar into its own window.
  • application:themeChanged — Fired when the user changes the color theme in the Meeting Center or Webex client.
  • meeting:infoChanged — Fired when information has changed for the meeting in which the embedded app is running.
  • meeting:roleChanged — Fired when the role for the current participant changes, such as from
  • space:infoChanged — Fired when changes are made to information about the current space, such as the space's title.
Creating Event Listeners

The basic pattern for creating event listeners is shown below, where app is a Webex.Application instance previously created:

app.listen().then(function() {
  // listen().then() ok
   app.on(<eventName1>, <callback>);
   app.on(<eventName2>, <callback>);
})
.catch(function (reason) {
  // listen().then() failed
});

Or, with JavaScript arrow functions:

app.listen().then(() => {
   app.on(<eventName1>, <callback>);
   app.on(<eventName2>, <callback>);
})
.catch(function (reason) {
  // Listen() promise failed
});

When the listen() promise resolves successfully it indicates that the framework is ready to register your application's callback functions. For example, the following creates listeners for both meeting.infoChanged and application.themeChanged.

app
  .listen()
  .then(() => {
      app.on("meeting.infoChanged", (event) => {
          let meetingId = event.id;
          let conferenceId = event.conferenceId
          // etc..
      })
      app.on("application:themeChanged", (event) => {
        // Call custom function to update theme:
        // updateAppTheme(event);
      })
  })
  .catch(function (reason) {
      console.error("listen: fail reason=" + reason);
  });
Responding to Color Theme Changes

In the screenshot of the Open Together session shown previously you'll notice that the host and participant had different themes applied to their Meeting Center client. The white background of the shared URL looks good for the host (whose meeting window is set to use the light theme) but not as good for the participant who has selected the dark theme. Ideally, the application theme matches client application's theme.

In this section you'll add code that updates basic CSS styles in the shared application to match the currently selected theme. There are two parts to this:

  • Setting color styles to match the theme setting on initial launch. You can get the current theme setting from the property.
  • Responding to theme changes the user makes in Webex or Meeting client, which generates an event.

To make the app's colors match the selected theme:

  1. Open shared.js from the embedded app you created in the quick start.
  1. Append the following code to the onReady().then() handler:
```javascript
    // Register event handler for themeChanged event:
    app.on('application:themeChanged', (theme) => {
        updateColorTheme(theme);
        log("Updating theme to", theme)
    })
})
```

When the `application:themeChanged` event is emitted the listener function calls a custom function named `updateColorTheme()`, passing it the event object containing the newly selected theme.
  1. Add the updateColorTheme() function to shared.js:
```javascript
function updateColorTheme(theme) {
    switch (theme) {
        case "LIGHT":
            document.body.style["background"] = "#FFFFFF";
            document.body.style["color"] = "#000000";
            break;
        case "DARK":
            document.body.style["background"] = "#121212";
            document.body.style["color"] = "#F7F7F7";
            break;
        default:
            break;
    }
}
```
  1. Lastly, for the app's colors to match the theme when the application starts, add following code to the app's onReady() handler.
```javascript
updateColorTheme(app.theme)
```

Your app's `onReady()` handler should look like the following:

```javascript
app.onReady().then(() => {
    log("Application ready. App", app);
    app.context.getUser().then((user)=> {
        log("User ID", user.id)
    }).catch((errorcode) => {
        log("Error", errorcode)
    })
    // Register event handler for themeChanged event:
    app.on('application:themeChanged', (theme) => {
        updateColorTheme(theme);
        log("Updating theme to", theme)
    })
    // Set app theme to match selected theme on load:
    updateColorTheme(app.theme)
})
```
  1. Publish your changes to shared.js to your web host.

To test these changes:

  1. Open the shared app in a meeting add as a tab to a space. If the shared app is already open in a meeting or space, right-click (or control-click) on any empty area of the shared app's viewport and select Reload.
The app's color theme should match the currently selected theme on initial load.
  1. In Meeting Center select View > Themes and select a different theme, or in a Webex Space open Preferences, click Appearance and select a new theme.
The app's theme changes to match the currently selected theme.

![Color theme change test](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt4b49e3c1016f8c30/6176f0fdfa86b41ef7469188/color-theme-change.png)
anchorCreating an Embedded App in the Developer Portal
anchor

You use the Developer Portal to create your embedded app. Creating your application involves providing the following information about your app:

  • Embedded app's context: Webex Meeting, Webex Space, or both.
  • App name, description, icon, and other common meta-data
  • Starting URL for your embedded app. You can use the same URL for both meeting and spaces, or specify unique URLs for each context. This is the URL of the initiator app that's used to share a URL with meeting participants in real-time, or add as a tab to a space (see About Embedded Apps in Spaces and Meetings for more information).
  • List of valid domains you will use as the start URL(s) for your embedded app, or that will be shared with others by a method call.

By default, the initiator app is only visible to your own Webex account inside a meeting or space.

To create your embedded app:

  1. Login to the Developer Portal and click Start Building Apps.
![Developer Portal](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt578f19425aec4723/617770e2de12c91d936cccc5/login_dev_portal.png)
  1. Click Create a new App, or Create Embedded App if you haven't yet created an app.
![Create embedded app button](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt4b5596c10693bef9/617771a5de12c91d936cccc9/my_apps.png)

![Create embedded app button](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/bltab7a1513f0ae93f7/61777954da02001d99f299f0/create_embedded_app.png)
  1. In the New Embedded App page that opens configure your application as follows:
  • Where does your app work? — Select whether your application will be used in a Webex meeting, Webex messaging space, or both.
  • Application name — Enter the name of your embedded app as it will appear in Webex.
  • Description — Provide details about what your embedded app does, its benefits, and how a user can get started using it (1024 character maximum). If your app is listed on the Webex App Hub this will be used as the listing’s description. You can use basic Markdown text formatting, bullets, and links in your description.
![App context, name, and description](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt8ba09d598591fd68/617779cca43ece1a3719a149/app_context.png)
  • Tag line — A catchy one-liner for your app (256 character maximum). The tag line will appear in search results and the app detail page.
  • Icon — Select or upload an image that is displayed with your application. Image must be in JPEG or PNG format and its dimensions must be 512x512px.
  • Valid domains — Add the domain(s) where you will host your application's start page URLs (see below). You must add at least one domain and it must match the domain(s) used by all start page URLs. For example, if your application's start page URL is www.example.com/embedded-app then you would need to add example.com as a domain.
  • Start page URL — The URL that the initiator (meeting host, for example) will load in the client before sharing in the Webex meeting or space. The URL must be HTTPS and be served from a valid domain.
  • In-meeting start page URL — (Optional) Distinct start page URL for using this app in a Webex meeting. If not specified then Start Page URL is used. The URL must be HTTPS and be served from a valid domain.
  • Space start page URL — (Optional) Distinct start page URL for using this app in a Webex messaging space. If not specified then Start Page URL is used. The URL must be HTTPS and be served from a valid domain.
![Start page URL](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blt341b6b3f52bf5b1a/61777a2aac68a827432693ba/start_page.png)

For example, the following screenshot shows the configuration for an in-meeting application.
  1. Click Add Embedded App.
![App submission confirmation](https://images.contentstack.io/v3/assets/bltd74e2c7e18c68b20/blte5733395731f0a06/61777a94a52d96289195d898/app_submitted.png)

At this point your application is in development mode and is available for your personal use in Webex meetings and messaging spaces. You can request approval of the application so others in your organization can also use it.

Requesting Approval of Embedded Apps

When you create a new embedded app in the Developer Portal it's only visible to you in Web or Meeting Center. You can optionally request your organization's admin to approve that app so that it will be available to all users in your organization.

  1. Open your My Apps page in the Developer Portal.
  2. Click the app you want to have approved.
  3. On the app details page click Request admin approval.

Request admin approval button

The current submission status is displayed.

Submitting your App to Webex App Hub

You can optionally submit your application to Webex for inclusion on App Hub.

To submit your app to App Hub:

  1. Open your My Apps page in the Developer Portal.
  2. Click the app you want to submit.
  3. Click Submit to Webex App Hub to open the Webex App Hub Submission page.
  4. Provide values for all required fields and click Submit.

Button to submit app to Webex

anchorDesign Guidelines for Embedded Apps
anchor

This section contains design guidelines and considerations for embedded app developers and designers.

Size Constraints for Embedded Apps in Meetings and Spaces

Embedded apps can run in several window sizes, from the size of a handheld device, to a tablet, or a full-screen desktop window. The same responsive design techniques used on the open web to provide the best experience should also be used for embedded apps.

Webex provides a Figma design file created by designers at Webex that contains detailed layouts and size constraints for embedded apps running in-meeting and in-space. Designers can use this information to specify appropriate CSS breakpoints for the various form factors.

Figma design assets

Placement of In-App Navigation

If your application contains buttons or other navigation components its recommended that they are placed toward the bottom of the window. This is especially true when the app is running in the sidebar (not in a separate window).

Placement of in-app navigation

In general, avoid placing multiple navigation components in the same area as this can lead to user confusion.

anchorPersonally Identifiable Information (PII) and Embedded Apps
anchor

The Embedded App framework provides APIs that apps can use to obtain personally identifiable information (PII) about its users, but only if permitted by the Webex organization’s administrator. By default, access to PII by embedded apps is disabled for all organizations.

The following data is considered personally identifiable by Webex policy:

  • ID (user.id)
  • Email (user.email)
  • Display name (user.displayName)
  • Organization ID (user.orgId)
  • Conference ID (meeting.conferenceId)
  • ID (meeting.id)
  • Title (meeting.title)

In addition, the JSON Web Token (JWT) included in the response to getUser() contains additional PII data fields that are not exposed as top-level properties. See About the JSON Web Token (JWT) for more information.

An embedded app can determine if it has access to PII by checking the value of app.isPrivateDataAvailable. If true, PII fields will actual data for users, meetings, and spaces; if false, the values provided to your app will either be empty strings or derived values. See About Derived PII Values for more information.

About Derived PII Values

If access to private data has been disabled for an organization, then PII data fields will either contain empty strings or be derived values. Derived values are opaque but are guaranteed to be consistent across different contexts. For example, if the same user from the same organization opens an embedded application on different days, then the derived value for user.id will be the same in both sessions. This allows apps to track users across sessions even without actual user data.

Derived values are generated for the following properties:

  • meeting.id
  • meeting.conferenceId
  • user.id
  • user.orgId
  • space.id

For example, the following shows an example User object returned by app.context.getUser() when access to PII has been disabled:

{
    "id":"eceb7c00-...",
    "orgId":"86434df5-...",
    "email":"",
    "displayName":"",
    "token":"xxx.yyy.zzz"
}

Note that the email and displayName fields are empty, while id and orgId contain derived values. The same derived values for id and orgId would be returned for the same user if they closed and then opened the app again at a later time.

If a meeting or space has a mix of participants – some with PII enabled and some without – there will be two different IDs. Users with PII enabled will have the real meeting (or space) ID in the meeting.id or space.id field, while users without PII enabled will have derived IDs for those fields. To provide apps with a common ID across all users the JWT includes the derived meeting or space ID as an extra field in the token for all users, regardless of whether PII is enabled.

About the JSON Web Token (JWT)

The User object returned by app.context.getUser() contains a field named token whose value is a signed JSON Web Token, or JWT. The purpose of the JWT in the context of embedded apps is two-fold:

  • Provide a way for embedded apps to verify the integrity of the data they are provided by the framework.
  • Expose additional data fields to apps beyond what are available as top-level API properties.

The JWT is not an access token for calling Webex APIs on behalf of the user of your application. Your applications will need to obtain an access token following the standard integration workflows.

To validate that JWT was actually signed by Cisco you can use the value of the new_verification_key field of the JSON object at the verification endpoint at https://idbroker.webex.com/idb/oauth2/v2/keys/verification, shown below.

Verification key field

JWT field reference

The section lists the fields of the JWT returned in response to a call to app.context.getUser(). Some of these fields are also available on the User object returned by getUser(), such as user.id or user.email. Others are only available as JWT fields, such as given_name.

The following are registered claim names included in the JWT:

  • exp – Number. Life span of token in seconds.
  • iat – Number. The time the token was issued.
  • iss – String. URI of the principal that issued the claims contained by the token (https://idbroker.webex.com/idb, for example)
  • aud – String. ID of embedded application.
  • name – String. User’s display name. Blank if PII has been disabled.
  • given_name – String. User’s first name. Blank if PII has been disabled.
  • family_name – String. User’s last name. Blank if PII has been disabled.
  • email – String. User's email. Blank if PII has been disabled.
  • email_verified – Boolean. If "true" indicates that the email was verified by Cisco and the user's PII is shared in the token. If "false", indicates that the user's email was not verified by Cisco and derived values are used for PII.

The following are Cisco claim names included in the JWT:

  • com.cisco.user.orgid – String. User's organization ID. Contains a derived value if PII is disabled.
  • com.cisco.user.uuid – String. User ID. Contains a derived value if PII is disabled.
  • com.cisco.user.level – Array. Contains one or more of the following values:
  • "admin"
  • "guest"
  • "basic"
  • "enhanced"
  • com.cisco.context.uuid.conferenceid – String. Conference ID. Contains a derived value if PII is disabled.
  • com.cisco.context.uuid.conferenceid.derived – String. Derived conference ID. If PII is disabled this will match the value of com.cisco.context.uuid.conferenceid.
  • com.cisco.context.uuid.meetingid – String. Meeting ID. Contains a derived value if PII is disabled.
  • com.cisco.context.uuid.meetingid.derived – String. Derived meeting ID. If PII is disabled this will match the value of com.cisco.context.uuid.meetingid.
  • com.cisco.context.uuid.spaceid – String. Space ID. Contains a derived value if PII is disabled.
  • com.cisco.context.uuid.spaceid.derived – String. Derived space ID. If PII is disabled this will match the value of com.cisco.context.uuid.spaceid.
  • com.cisco.user.info – JSON blob containing additional information about the user, meeting, or space.

Below is an example JWT returned by a call to app.context.getUser(), using abbreviated UUIDs for clarity. In this case, email_verified is false indicating that derived values are returned for PII.

{
  "email_verified": false,
  "iss": "https://idbroker-b-us.webex.com/idb",
  "com.cisco.context.uuid.meetingid.derived": "a9b68195-...",
  "com.cisco.user.uuid": "bbd582d2-...",
  "com.cisco.context.uuid.meetingid": "a9b68195-...",
  "com.cisco.context.uuid.conferenceid": "55c205d8-...",
  "given_name": "",
  "aud": "Y2lzY29z...",
  "com.cisco.user.orgid": "86434df5-...",
  "com.cisco.context.uuid.conferenceid.derived": "55c205d8-...",
  "name": "",
  "com.cisco.user.level": [
    "enhanced",
    "admin"
  ],
  "exp": 1634679561,
  "iat": 1634593161,
  "family_name": "",
  "email": "",
  "com.cisco.user.info": "{\"some_property_name\":\"Some data.\"}"
}
Access to PII for In-Development Apps

Before an embedded application has been approved for use within an organization, it is considered "in-development". Only the user who created the embedded app in the Developer Portal can add an instance of the app to a meeting or space. Other participants in the meeting or space can view the app shared by the app owner but are first presented with a dialog asking them if they want to open the app and share their PII, or open the app without sharing any PII.

In-development PII warning dialog

Note that the JWT token contains derived values, even if the user chooses to share their personal information when opening the app.

anchorDevelopment Tips and Tricks
anchor

This section provides an assortment of solutions to common questions or problems for developing Embedded Apps.

Checking for an Existing Sharing Session

It's good practice to check the value of before calling setShareUrl(). This avoids the scenario of the "Open together" button mistakenly appearing for meeting participants.

For example, in the following code sample the embedded app's handleSetShare() is responsible for calling setShareUrl() in response to some other event. The function first checks the value of app.isShared and exits the function if it's true.

function handleSetShare(url)
    if (app.isShared) {
      log('ERROR: setShareUrl() should not be called while session is active');
      return;
    }
    // Call setShareUrl() as usual...
}
Check if App is Running In-Space or In-Meeting

In some cases an embedded app may need to determine if it's running in a meeting or a space. One way to do this is to check the value of the app.displayContext, which contains one of the following values: "MEETING_SIDEBAR", "MEETING_STANDALONE_WINDOW", "MEETING_MAINVIEW", or "SPACETAB". For example, the following code uses the includes() function to check if app.displayContext contains the string "MEETING". If includes() returns true the app is running in a meeting, otherwise it's running in a space.

    var app = new window.Webex.Application();
    var isMeeting = false;

    app.onReady().then(() => {
        // Check if running in a meeting
        isMeeting = app.displayContext.includes("MEETING");
        if(isMeeting) {
            console.log("I'm running in a meeting");
        } else {
            console.log("I'm running in a space");
        }
    }).catch((errorcode) =>  {
        log("Error: ", Webex.Application.ErrorCodes[errorcode]);
    });
Using Cookies and Web Storage

Embedded apps can use cookies and Web Storage the same way they are used in web browsers. Persistent cookies and local storage data are persisted after a user quits the Webex app or Meeting Center client; session cookies and session storage data are deleted when the user closes Webex or Meeting Center.

The Webex Kitchen Sink app on GitHub demonstrates the various storage options.

Screenshot of storage options

Webex Integrations in Embedded Apps

For an embedded app to make Webex API calls on behalf of its users, the app must first obtain an access token using the standard OAuth grant flow used by Webex Integrations. The signed JSON Web Token (JWT) returned in the response to app.context.getUser() cannot be used to make Webex API calls. Its purpose is to provide apps a way to confirm that the data came from Cisco by verifying the JWT's signature. See About the JSON Web Token for more information.