XML API DeprecationGetting StartedREST API BasicsComplianceWebhooksWebex APIs
Contact Center
Webex Assistant Skills
Full API Reference
API Changelog

Embedded Apps Developer 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

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

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.

Developer tools are currently unavailable to messaging-based apps running in the Webex client on Windows systems. They are available to meeting-based apps running in Meeting Center on Windows.

To enable developer tools in the Meeting Center client on Windows and MacOS:

  • On Windows, set EnableEmbeddedAppDebug to 1 in the Computer\HKEY_CURRENT_USER\SOFTWARE\WebEx\DeveloperTools registry key.

    Windows Registry key/value to enable debugging

  • On MacOS, run the following command:

    defaults write NSGlobalDomain WebexWebAppDeveloperExtras -bool true

To enable developer tools in the Webex client on MacOS:

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

    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

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.

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:

      <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>
        <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" />

    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.
  2. Save your changes to index.html. Next you'll create the app's index.js JavaScript file.

  3. Create a JavaScript file named index.js and add to it the following code:

    // 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)}`);

    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.
  4. 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:

        <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>
        <h2>Shared page</h2>
        <p>This page was shared by the initator app.</p>
        <ul id="console" />

    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.

  2. Create a JavaScript file named shared.js in the same folder as shared.html that contains the following code.

    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)}`);

    This code largely similar to that used in the iniator app but also displays the value of the user.id field returned by the in the app's log console.

  3. 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 details on using the Developer Portal to create and configure embedded apps, 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.

  2. Click Create a New App, then click Create Embedded App.

  3. 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.

  4. 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.

    You must start the meeting using the Meeting Client desktop app, not the web app.

  2. 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

  3. 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

  4. Click Set Share URL, which makes the Open together button visible.

    Calling setSharURL method

  5. Click Open together.

    The meeting participant you invited sees a window open with the same privacy dialog.

  6. The participant clicks Open and the URL shared by initiator app (shared.html) opens in the app window.

    Meeting participant view

    Note that the user ID is displayed in the app console.

  7. In the initiator app, click Stop session, which has replaced the Open together button. The app window closes for the meeting participant.

    Stop session

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.

  2. 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

  3. Click your app in the list. The same privacy dialog appears as in the meeting context.

  4. Select a privacy option and click Open to open the initiator app.

    Initiator app open in-space

  5. Click Set Share URL to enable the Add to tab button.

    Add to tab button

  6. Click Add to tab. The app appears as a tab in the space. All users in the space can see the tab.

    Space added

anchorResponding to Events

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.

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

  2. Append the following code to the onReady().then() handler:

        // Register event handler for themeChanged event:
        app.on('application:themeChanged', (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.

  3. Add the updateColorTheme() function to shared.js:

    function updateColorTheme(theme) {
        switch (theme) {
            case "LIGHT":
                document.body.style["background"] = "#FFFFFF";
                document.body.style["color"] = "#000000";
            case "DARK":
                document.body.style["background"] = "#121212";
                document.body.style["color"] = "#F7F7F7";
  4. Lastly, for the app's colors to match the theme when the application starts, add following code to the app's onReady() handler.


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

    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) => {
            log("Updating theme to", theme)
        // Set app theme to match selected theme on load:
  5. 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.

  2. 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

anchorCreating an Embedded App in the Developer Portal

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

  2. Click Create a new App, or Create Embedded App if you haven't yet created an app.

    Create embedded app button

    Create embedded app button

  3. 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

    • 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

    For example, the following screenshot shows the configuration for an in-meeting application.

  4. Click Add Embedded App.

    App submission confirmation

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

anchorPersonally Identifiable Information (PII) and Embedded Apps

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:

  • The following user data returned by app.context.getUser():

    • ID (user.id)
    • Email (user.email)
    • Display name (user.displayName)
    • Organization ID (user.orgId)
  • The following meeting data returned by app.context.getMeeting():

    • Conference ID (meeting.conferenceId)
    • ID (meeting.id)
    • Title (meeting.title)
  • The following space data returned by app.context.getSpace():

    • ID (space.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:


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": [
  "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

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');
    // 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

About Combined Embedded App and Integration Solutions

Embedded apps can't make Webex API calls directly. However, your embedded app can be backed by a server process that acts as a Webex Integration. In this scenario, the embedded app prompts the user to initiate the OAuth authorization process to obtain an access token to make Webex API calls on the user's behalf.

First, the user clicks a button or link in the embedded app that opens the Webex authorization request URL(https://webexapis.com/v1/authorize). This URL is configured with your Webex integration's requested scopes, client ID, and redirect URL, and other request parameters.

Button to start OAuth flow

Once the user has signed in to their Webex account they are asked if they want to accept the request for access to data in the specified scopes.

Webex login screen

User authorizes access to data

Once the user accepts the request they are redirected to your integration's specified Redirect URL, which is passed an authorization code from the authorization server. This page can exchange the auth code for an API access token to make Webex API calls (to the /v1/people/me API endpoint, for example) on the user's behalf and display the results in the embedded app, as shown below.

Redirect page showing results of authenticated API call

Clearing the Webex Cache

When iteratively testing changes to your embedded app you'll typically post your changes to your web host, and then click "Reload" in developer tools menu to refresh the app. Like stand-alone web browsers the Webex app caches your embedded app's assets for faster loading times, so you may need to clear its cache to view your app's most recent changes.

To manually clear the cache, see the instructions in the following Webex support articles:

Alternatively, you can click Clear Cookies under the Accounts tab in the Webex app's preferences. (Note that this will also log you out of any current Webex sessions.)

Clear cookies button in Webex preferences

Ensuring the Framework is Loaded and Ready

Once the embedded app framework is loaded and ready to use, it calls your app's onReady promise handler, for example:

// Create Webex app object and initialize your application
var app = new window.Webex.Application();

app.onReady().then(() => {
    console.log("Framework is ready.");

However, if this code is parsed and executed before the framework's JavaScript library has finished loading, an 'undefined' runtime error will be generated since the window.Webex object doesn't yet exist. To avoid this you can either use the defer attribute on the <script> tag used to load the framework library, or modify your code to defer creation of the app object until window.Webex exists. Both of these approaches are described below.

Using the defer Script Tag Attribute

When present on a <script> tag, the defer attribute indicates to the embedded web view in which your app is running that the script should be executed after the document has been parsed. Scripts with the defer attribute execute in the order in which they appear in the document. For this reason the <script> tag that loads the embedded app framework must be declared before any <script> tag that loads your application code, as shown below.

    <!-- Load the embedded app framework -->
    <script src="https://binaries.webex.com/static-content-pipeline/webex-embedded-app/v1/webex-embedded-app-sdk.js" defer></script>
    <!-- Load your app's main javascript file -->
    <script src="./index.js" defer></script>

With this setup your app's code is guaranteed to execute only after the framework is loaded. Without the defer attribute there's a chance that the window.Webex object will be undefined when your app's code attempts to use it.

Wait Until the Webex Object Exists

As an alternative to use the defer script tag attribute, your app code can defer creation of the main Webex app object until window.Webex exists. The framework will then automatically call your onReady() promise handler. For example, the following uses the setInterval() function before creating the app object.

// Declare app object:
var app;

// Wait for window.Webex
var checkForWebex = setInterval(function() {
   if (window.Webex) {
      app = new window.Webex.Application();    
}, 100); // check every 100ms

// Define onReady handler:
app.onReady().then(() => {
    console.log("Framework is ready.");