Integrate Miro and CometChat in a Daily video call with our new Prebuilt Integrations API
Tags: programming, tutorial, api, webrtc
Published: 2023-04-27 17:24:14

_By Liza Shulyayeva, Engineer, Daily Developer Relations_

In this post, I’ll go through the core functionality of the Daily Prebuilt Integrations API. I’ll do this by presenting two practical examples of integrating third-party services into a Daily Prebuilt video call:

1. A [Miro](https://miro.com/?ref=daily.co) virtual whiteboard. Miro is an online platform that allows participants to learn or collaborate within the context of virtual whiteboards. It’s often used for lectures and teaching, or for planning and brainstorming together,
2. A [CometChat](https://www.cometchat.com/?ref=daily.co) chat widget. CometChat is a platform that allows you to easily embed advanced chat functionality into your web app.

We’ll do this with an extremely basic demo—no bells and whistles or complexity, just Daily's new Prebuilt Integrations API!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lcgbcc5k4jf3kpyxkxk2.gif)

## Running the demo

If you want to see the code and demo right away, [check it out on Glitch](https://glitch.com/edit/?ref=daily.co#!/daily-prebuilt-integrations?path=README.md%3A1%3A0).

You can either remix the Glitch project above or join your own Daily room with the [deployed version of the app](http://daily-prebuilt-integrations.glitch.me/?ref=daily.co). To do so, follow the steps below:

- [Create a Daily account](https://dashboard.daily.co/signup?ref=daily.co) and a [Daily room](https://dashboard.daily.co/rooms/create?ref=daily.co)
- Copy the room URL of your Daily room (it will be `https://YOUR_DOMAIN.daily.co/YOUR_ROOM_NAME`)
- Navigate to the deployed demo with your room URL as a query parameter: `https://daily-prebuilt-integrations.glitch.me/?roomURL=YOUR_ROOM_URL`

Once you’ve done that, you should see a Daily Prebuilt call frame load in. Upon joining the call, you’ll see an “Apps” button in the Prebuilt tray menu at the bottom. This is where the Miro button lives. Click on it and you’ll see a Miro board load into the main call view.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5geb6kf6odwz55bab8i.gif)

To open up the CometChat integration, click on “People” in the bottom tray and then click “CometChat” at the top. Or, alternatively, click the “Chat” icon in the Prebuilt tray:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ridwiewbech07sbgzz3d.gif)

In this demo, I am showing the CometChat integration with an example chat with Iron Man. If you’d like to use this in production with real cross-participant chat, sign up for CometChat and create your own [chat widget](https://www.cometchat.com/docs/chat-widgets/overview?ref=daily.co).

💡_CometChat requires access to [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API?ref=daily.co), which is sometimes blocked by default in Incognito mode! I suggest running this demo in a non-Incognito window, or enabling local storage in your Incognito browser settings._

Now that we’ve familiarized ourselves with the demo, let’s dig into the Miro “main view” integration.

## Miro + Daily Prebuilt with a “main view” integration

In this integration, you’re going to see an “Apps” menu in your embedded Daily Prebuilt iframe. When clicked, a “Miro” button appears:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31ywkrz5sw6i559xm314.png)

If you click to activate Miro, the main call view (where the active speaker would normally be shown) will be replaced with a Miro board. I’ve provided a default read-only board, or you can replace the URL with your own Miro embed URL.

If you join the same room from another instance of the demo, you’ll see that Miro is opened for **_other_** participants as well, without them clicking the Miro control in the tray menu to toggle it.

We’re going to accomplish all of the above in under 15 lines of code with Daily’s new [`customIntegrations`](https://docs.daily.co/reference/daily-js/daily-iframe-class/properties?ref=daily.co#customIntegrations*) call frame property.

You can check out the code for the demo above [on Glitch](https://glitch.com/edit/?ref=daily.co#!/daily-prebuilt-integrations?path=script.js:38:1) and play around with all the properties, but for the sake of brevity here’s a condensed version:

```
const callFrame = window.DailyIframe.createFrame({
  customIntegrations: {
    miro: {
      controlledBy: "*",
      iconURL:
        "https://cdn.glitch.global/fe2fb078-9d31-4e90-8e78-c9cda05cd705/miroIcon.png?v=1680080952367",
      label: "Miro",
      location: "main",
      shared: true,
      src: "https://miro.com/app/live-embed/uXjVPrAq36w=/?moveToViewport=-2043,-1039,4081,2023&embedId=660028222598",
    },
  },
  // Additional code unrelated to the Miro integration below, we’ll go through this in the subsequent CometChat section...
});
```
Above, I’m adding a new `customIntegrations` property into the object passed into our `createFrame()` factory function. The property is an object containing integration configurations—in this case, just Miro. I decided to call the Miro integration object `miro`, but you could make this anything.

Within the `miro` object, I define some Integration-specific configuration. Here’s what each one means (refer to [our documentation](https://docs.daily.co/reference/daily-js/instance-methods/custom-integrations?ref=daily.co#properties-that-can-be-set-via-setcustomintegrations) for a complete list of properties):

- `controlledBy` tells Daily who can start and stop this integration. In this case, `”*"` means that it can be controlled by **_any_** user.
- `iconURL` specifies which image to show next to the associated Miro button Prebuilt will display in the call frame.
- `label` is the text that will appear next to the icon as part of the Miro button in the call frame.
- `location` specifies that this integration, when activated, will be displayed in the **_main call view_** of the application (where the active speaker would otherwise be shown)
- `shared` dictates whether the **_state_** of this information will be shared with other participants who have it configured. In this case, the state is shared. In practice, this means when a local participant opens or closes the Miro integration view, it will also be opened or closed for other participants who joined through our demo app.
- `src` specifies the embed URL of my default, read-only Miro board.

There are other possible options you can set for an integration which I haven’t used here. Be sure to check out our reference docs for a [comprehensive list of integration properties](https://docs.daily.co/reference/daily-js/instance-methods/custom-integrations?ref=daily.co#properties-that-can-be-set-via-setcustomintegrations).

That’s it! Daily handles the rest, so this is all the code we need to be able to open a Miro board directly through the Daily Prebuilt call frame.

Now, let’s take a look at a slightly different subset of Prebuilt Integrations API features: configuring a sidebar chat integration **_after_** the user joins a Daily call.

## CometChat + Daily Prebuilt with a “sidebar” integration

Some integrations are straightforward enough to be configured pre-call-join, like Miro. But what if you have an integration that you want to enable after the user is in a Daily room, or during some other part of the call life cycle? I’ll show an example of this with the CometChat **_sidebar_** integration.

For the CometChat integration, I’ll be using their [client-side library](https://www.cometchat.com/docs/chat-widgets/web?ref=daily.co) to embed a chat widget into a separate HTML page. I’ll then be embedding that HTML page as a Prebuilt integration. Daily’s [`session_id`](https://docs.daily.co/reference/daily-js/instance-methods/participants?ref=daily.co#participant-properties) for each participant will be used to create their CometChat user ID, so we’ll need to have that available before the integration can be enabled. The local user can activate the integration through either their “People” tray button or a [custom button](https://docs.daily.co/reference/daily-js/instance-methods/custom-tray-buttons?ref=daily.co) in their Daily Prebuilt call frame. The result looks like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uodv3k92ku3zmtmzpbdr.png)

Check out [`comet-chat.html`](https://glitch.com/edit/?ref=daily.co#!/daily-prebuilt-integrations?path=comet-chat.html%3A1%3A0) to see how I embed the CometChat widget into an HTML page in the project. I won’t go through that in detail now since that’s not actually Integrations related. The critical point is, we’ll be embedding this page into Daily Prebuilt as a **_sidebar integration_**. That’s what I’ll focus on here.

Since we need to have the Daily session ID for the local participant to pass to CometChat, we cannot actually configure this integration until after the user joins the call. This is why in [my Integrations API demo](https://glitch.com/edit/?ref=daily.co#!/daily-prebuilt-integrations?path=script.js%3A1%3A0), I instead configure the integration using our new [`setCustomIntegrations()`](https://docs.daily.co/reference/daily-js/instance-methods/set-custom-integrations?ref=daily.co) call frame instance method after receiving Daily’s [`"joined-meeting"`](https://docs.daily.co/reference/daily-js/events/meeting-events?ref=daily.co#joined-meeting) event:

```
callFrame.on("joined-meeting", async (e) => {
  const localParticipant = e.participants.local;
  enableCometChatIntegration(callFrame, localParticipant.session_id);
});
```
That `enableCometChatIntegration()` function is where the magic happens, so let’s take a look:

```
function enableCometChatIntegration(callFrame, sessionID) {
  const integrations = callFrame.customIntegrations();
  integrations.cometChat = getCometChatIntegration(sessionID);
  callFrame.setCustomIntegrations(integrations);
  setupCometChatButton(callFrame);
}
```

The function above takes two parameters: the Daily Prebuilt call frame and the local participant’s session ID (whose session ID we’ll be using to register a CometChat user).

The first thing I do in the function body above is retrieve all existing integrations with the new [`customIntegrations()`](https://docs.daily.co/reference/daily-js/instance-methods/custom-integrations?ref=daily.co) call frame instance method. In this case, this will be the Miro integration we set up earlier!

`setCustomIntegrations()` overrides any existing integrations with the new given object. By retrieving the existing integrations and adding the new CometChat integration to that object, we ensure that we keep all integrations intact instead of overwriting anything.

Finally, I call the `setCustomIntegrations()` call frame instance method with the modified integrations object, which results in the new CometChat integration being added.

I then also set up a custom button for some additional control, which I’ll go through shortly. But let’s go through the integration configuration itself first.

The CometChat integration object is very similar to the Miro one we set up above, with a couple of key differences:

```
function getCometChatIntegration(sessionID) {
  const location = window.location;
  const baseURL = `${location.protocol}//${location.host}${location.pathname}`;
  const src = `${baseURL}comet-chat.html?userID=${sessionID}`;
  return {
    controlledBy: "*",
    label: "CometChat",
    location: "sidebar",
    shared: false,
    src: src,
  };
}
```
The first difference is that instead of a third-party embed URL like a Miro board, I specify the integration `src` property to be an absolute path to the [`comet-chat.html`](https://glitch.com/edit/?ref=daily.co#!/daily-prebuilt-integrations?path=comet-chat.html%3A1%3A0) file served on the demo domain. I also include a `userID` **_query parameter_** in the URL and use it to pass the participant’s session ID to the CometChat logic.

The second key difference is that I set the `location` property to `”sidebar"`. This will result in the integration to be accessible through the Daily Prebuilt sidebar instead of the main call view.

Finally, we also set the `shared` property to `false` here–this means any user can toggle the CometChat integration locally without having that state propagated to each other user.

Once enabled, the code above results in a “CometChat” button being added to the Daily Prebuilt “People” tab. When clicked, it opens up a CometChat widget in the sidebar view:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qu8w4zb7vexu32w06b88.png)

But for something like chat functionality, having the control to open it being tucked away in the sidebar doesn’t really seem like enough. What if we **_also_** want to add a big “Chat” button to the Prebuilt tray and have it open the CometChat sidebar integration when clicked? We can do that, too!

## Manipulating the sidebar view with a custom button

That’s where the `setupCometChatButton()` function I mentioned earlier comes in. By using Daily Prebuilt’s custom tray button feature in conjunction with the new [`setSidebarView()`](https://docs.daily.co/reference/daily-js/instance-methods/set-sidebar-view?ref=daily.co) call frame instance method, we can add a Chat button to the tray and have it toggle our new sidebar CometChat integration when clicked:

```
// setupCometChatButton() sets up a custom tray button to toggle
// the CometChat integration
function setupCometChatButton(callFrame) {
  const viewAndBtnID = "cometChat";
  callFrame.on("custom-button-click", (ev) => {
    const buttonID = ev.button_id;
    if (buttonID !== viewAndBtnID) return;
    callFrame.getSidebarView().then((view) => {
      if (view !== viewAndBtnID) {
        callFrame.setSidebarView(viewAndBtnID);
        return;
      }
      callFrame.setSidebarView(null);
    });
  });

  // Set up CometChat custom tray button
  callFrame.updateCustomTrayButtons({
    cometChat: {
      iconPath:
        "https://cdn.glitch.global/fe2fb078-9d31-4e90-8e78-c9cda05cd705/cometChatIcon.png?v=1680166335558",
      label: "Chat",
      tooltip: "Advanced chat with CometChat",
    },
  });
}
```
Alright, let’s take this step by step. Above, I first create a **_handler_** for when our upcoming custom button will be clicked, and then **_add_** the custom button to the tray. I chose this order to avoid timing issues: I want to make sure that by the time the custom button is added to the tray, the handler is already set up and guaranteed to run.

The handler above uses Daily’s [`"custom-button-click"`](https://docs.daily.co/reference/daily-js/events/meeting-events?ref=daily.co#custom-button-click) event. This event will fire whenever the local user clicks a custom button in the tray.

Inside the handler, I check the ID of the button being clicked (which will be `”cometChat”` as you can see by the `viewAndBtnID` const defined above).

After verifying that the custom button that was clicked is indeed our CometChat button, I use the [`getSidebarView()`](https://docs.daily.co/reference/daily-js/instance-methods/get-sidebar-view?ref=daily.co) call frame instance method to retrieve the current state of the sidebar.  If the sidebar is not already displaying the CometChat integration, I use `setSidebarView()` to activate it. Otherwise, I use `setSidebarView()` to close the integration.

After defining the handler for our upcoming button click above, I use Daily’s [`updateCustomTrayButtons()`](https://docs.daily.co/reference/daily-js/instance-methods/update-custom-tray-buttons?ref=daily.co) call frame instance method to configure a `cometChat` button with my preferred icon path and labels.

And that’s it! We now have a new button in the Daily Prebuilt tray which toggles our new CometChat integration on and off:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cis3cebhizuey2bt8qyz.png)

## Conclusion

I hope this post has served to give you an idea of what’s possible with our new Prebuilt Integrations API.

As you can see, the API is very flexible in **_how_** and **_when_** you enable your integrations. It opens up a world of possibilities to easily embed not just third-party apps directly into Daily Prebuilt, but also your own custom functionality. Watch out for more content around using the Prebuilt Integrations API in conjunction with other Daily features to build unique experiences within your Daily-powered video applications.

If you have any questions or feedback on the Prebuilt Integrations API, please [reach out to our support team](https://www.daily.co/company/contact/support/?ref=daily.co) or find us at [peerConnection](http://community.daily.co/?ref=daily.co), our WebRTC community.