How To Add Video Conferencing to Your Web App Using the Whereby Browser SDK

The Whereby Browser SDK lets you add video calling to your web application, customizing layout and features to fit your use case and brand.

One of the most common requests we get at Whereby is the ability to create a fully-customized UI for video calls and conferences. That's now possible with the latest version of the Whereby Browser SDK.

The Whereby Browser SDK lets you add video calling to your web application, customizing layout and features to fit your use case and brand.

What you'll need

The Whereby Browser SDK takes advantage of React. This tutorial assumes that you're familiar with JavaScript, React and its JSX syntax. You should also be familiar with either npm or yarn, JavaScript's primary package managers.

To follow along with this tutorial, you'll need to do two things.

  • Sign up for a Whereby Embedded account. You can get started with Whereby's free plan. It provides you with 2,000 participant minutes each month.

  • Create a Whereby meeting room. You'll need the meeting room's URL. Create your room using the wizard on your account dashboard or with Whereby's REST API. For this tutorial, leave the room unlocked.

You should also have a basic React project set up. Vite or Parcel will get you up-and-running quickly.

Install the SDK

First, add the Whereby Browser SDK to your React project. We'll need to install version 2.0.0-beta3 or later. Open a terminal window and type (or copy-and-paste) the following command.

Typescript
npm i @whereby.com/browser-sdk

If you're using yarn as your package manager, replace npm i with yarn add (e.g. yarn add @whereby.com/browser-sdk).

Connecting to your room

Next, connect to your room. The Whereby Browser SDK exposes a custom React hook — useRoomConnection — that connects participants in a meeting room. Import both React and useRoomConnection into your project file as shown below.

Typescript
import React from "react";
import { useRoomConnection } from "@whereby.com/browser-sdk/react";

The useRoomConnection hook requires two parameters:

  • a Whereby room URL; and

  • an object that contains a localMediaOptions field. localMediaOptions determines whether the browser should request access to a participant's camera, microphone, or both.

Use the useRoomConnection hook inside of a component function. Here's an example.

Typescript
import React from "react";
import { useRoomConnection } from "@whereby.com/browser-sdk/react";

const MEETING_URL = 'https://<example>.whereby.com/b9538dfc-e52c-4f24-a509-xxxxxxxxxxxx';

const Meeting = () => {
  const mediaOptions = {
      localMediaOptions: {
          audio: true,
          video: true,
      }
  }

  const connection = useRoomConnection(MEETING_URL, mediaOptions);

  // Return the UI here
  return (
     <></>
  )
}

export default Meeting;

useRoomConnection returns a RoomConnectionReference object that contains three properties:

  • state, an object that reflects the status of the current room, including the call's participants;

  • components, an object containing the pre-bound components available in the room; and

  • actions, an object representing the available actions in the room.

This tutorial will introduce you to all three.

See yourself on screen

RoomConnectionReference.state includes two properties that represent participants in the meeting:

  • localParticipant, an object that represents the individual meeting attendee (you, in this case); and

  • remoteParticipants, an array of objects representing other meeting participants.

Each localParticipant and remoteParticipants object contains a stream property, that you'll use with the VideoView component to display video for each participant.

To see your own video stream, use the localParticipant property. Check whether localParticipant has an active stream, then conditionally render the VideoView component as shown below.

NOTE: The examples in this tutorial use destructuring assignment, a syntax that allows you to extract Object properties into variables. If you prefer, you can use dot-syntax (e.g. connection.components.VideoView or connection.state.localParticipant) to access these values.

Typescript
//…
const connection = useRoomConnection(MEETING_URL, mediaOptions);

const {state, components} = connection;
const {localParticipant} = state;
const {VideoView} = components;

return (
  <>
    {localParticipant?.stream ? (
      <div id="you" style={{width: '400px', height: 'auto'}}>
        <VideoView stream={localParticipant?.stream} muted />
      </div>
     ) : null
    }
  </>
)

VideoView requires a stream prop. Set its value to localParticipant.stream. The muted prop is optional, but good to use when rendering VideoView. Using muted for the localParticipant view prevents audio feedback from your own microphone.

Any attribute supported by HTML's <video> element can be added as a VideoView prop. Remember, however, to use className instead of class when adding CSS class names to React components.

Add microphone and camera controls

In the preceding example, the camera and microphone are enabled for the local participant — that's you. You probably want the ability to turn your camera and microphone off and on, though. You can accomplish that using the toggleCamera and toggleMicrophone methods of the actions property.

Typescript
//…
// Update the following line to define the `actions` variable.
const {state, components, actions} = connection;

// Extract toggleCamera and toggleMicrophone from the actions property.
const {toggleCamera, toggleMicrophone} = actions;

Set an initial state for the camera and microphone with React.useState().

Typescript
const [isCameraActive, setIsCameraActive] = React.useState(true);
const [isMicrophoneActive, setIsMicrophoneActive] = React.useState(true);

Then update your markup to add a button for each control.

Typescript
//…
return (
  <>
  {localParticipant?.stream ? (
    <div id="you" style={{width: '400px', height: 'auto'}}>
      <VideoView stream={localParticipant?.stream} muted />
        <p className="controls">

          <button
            type="button"
            onClick={() => {
              setIsCameraActive((previous) => !previous);
              toggleCamera();
            }
          }>Toggle Camera</button>

          <button
            type="button"
            onClick={() => {
              setIsMicrophoneActive((previous) => !previous);
              toggleMicrophone();
            }}
          >Toggle Microphone</button>
        </p>
      </div>
		) : null
  }
  </>
);

In the click handler for each button, you'll first need to update state for your camera (setIsCameraActive) or microphone (setIsMicrophoneActive), before invoking the appropriate toggle method. Each meeting participant will have these controls available in their meeting room view.

Add friends and colleagues

Talking to yourself is normal, but it's not a video call until you're talking to someone else. Use the remoteParticipants property and Array.prototype.map() to display the other participants' video streams.

Typescript
//…

<div id="participants">
{remoteParticipants?.length ?
  remoteParticipants.map((friend) => {
      return (
        <div className="participant">
          <VideoView stream={friend?.stream} />
        </div>
      )
  }) : null
}
</div>

As with localParticipant, each remoteParticipant object contains a stream property. Set remoteParticipant.stream as the value of the stream prop for each VideoView instance. Don’t add the muted property to the VideoView component here. Doing so would mute audio for all attendees in the room.

Altogether, your code should now resemble the example below.

Typescript
import React from "react";
import { useRoomConnection } from "@whereby.com/browser-sdk/react";

const MEETING_URL = 'https://<example>.whereby.com/b9538dfc-e52c-4f24-a509-xxxxxxxxxxxx';

const Meeting = () => {
  const connection = useRoomConnection(MEETING_URL, {
      localMediaOptions: {
          audio: true,
          video: true,
      }
  });

  const {state, components, actions} = connection;
  const {localParticipant, remoteParticipants} = state;
  const {VideoView} = components;
  const {toggleCamera, toggleMicrophone} = actions;

  const [isCameraActive, setIsCameraActive] = React.useState(true);
  const [isMicrophoneActive, setIsMicrophoneActive] = React.useState(true);

  return (
    <>
    {localParticipant?.stream ? (
      <div className="participant">
        <VideoView
          stream={localParticipant?.stream}
          muted
          className="you" />

        <p className="controls">
          <button type="button" onClick={() => {
              setIsCameraActive((previous) => !previous);
              toggleCamera();
            }}
           >Toggle Camera</button>

           <button type="button" onClick={() => {
              setIsMicrophoneActive((previous) => !previous);
              toggleMicrophone();
              }}
	          >Toggle Microphone</button>
	        </p>

	      </div> 
			) : null
    }
    <div id="participants">
      {remoteParticipants?.length ?
        remoteParticipants.map((friend, index) => {
            return (
              <div className="participant" key={friend?.id}>
              {friend?.stream &&
                <VideoView stream={friend?.stream} className="friend" />
              }
              </div>
            )
        }) : null
      }
     </div>
    </>
  );
}

export default Meeting;

From here, you're ready to add CSS to change your meeting layout. Or you can replace the default browser buttons with custom icon components.

Whereby's Browser SDK is a truly "white-label" solution for video calling. It decouples the video stream from the standard Whereby UI so that you can create rich video conferencing, virtual classrooms, or telehealth experiences that reflect you or your brand.

Learn more

If you'd like to learn more about the Whereby Browser SDK, explore the following resources.

Get started for free or talk to us to learn more about using our SDK.

Other articles you might like