Build a custom video chat with ReactJS and ApiRTC
Tags: webrtc, react, javascript, beginners
Published: 2023-01-02 10:30:33

**Build a custom video chat with ReactJS and ApiRTC from scratch in 15min.**

This post is part of the ApiRTC Wildcard series on how to build video communication applications using ApiRTC’s real-time video and audio APIs.

ApiRTC’s Javascript library, apirtc.js, enables you to add video and audio communication capabilities to any web application.

In this article, you will go through the steps to use the apirtc.js library to build a real-time video chat ReactJS application.

Here is what the final app will look like:

![Get a reactJS video communication application](https://apirtc.com/wp-content/uploads/2022/12/image_final-1024x576.png)

* * *

## Full source code of this ReactJs video conference bootstrap

You can find the source code of this tutorial on the ApiRTC GitHub space: [https://github.com/ApiRTC/apirtc-react](https://github.com/ApiRTC/apirtc-react)

If you’re curious about creating a video chat app but without ReactJS, you can read our [How to build a simple web app with apirtc.js](https://apirtc.com/blog/tutorials/building-a-simple-webrtc-browser-based-video-application/) article.

* * *

## Get yourself ready to build your first custom video chat with ReactJS and ApiRTC

### ApiRTC Cloud account set up and ready

This tutorial requires you to have an active account on ApiRTC Cloud: [Create an ApiRTC Cloud account](https://cloud.apirtc.com/register).

Once you are connected, you can get your API key from your dashboard or in the [Credential section](https://cloud.apirtc.com/enterprise/api).

### NodeJS and NPM installed

We use NPM to install ReactJS and all the dependencies, which use [NodeJS](https://nodejs.org/en/download/) to run. You must have NodeJS and NPM installed on your machine in their latest LTS versions.

> This tutorial uses Linux-based commands. Please [tell us](https://apirtc.com/contact-us/) if you would like other OS to be documented as well.

* * *

## Setting up the tutorial environment

### Create a folder containing a ReactJS boilerplate using the `create-react-app`npm package

Type the `npx` command to temporarly download and run the create-react-app package to generate a ReactJS boilerplate application with just the minimum:

```shell
npx create-react-app my_apirtc_react_app
cd my_apirtc_react_app
```

You sould get something like below:[![npm install command for apirc](https://apirtc.com/wp-content/uploads/2022/12/image_npm_install.png)](https://apirtc.com/wp-content/uploads/2022/12/image_npm_install.png)

### Add the apirtc.js video and audio library module to the ReactJS app

Run the following command in your project folder:

```shell
npm install @apirtc/apirtc
```

You should obtain something similar to the following in your `package.json` file

[![get video communication in your package.json](https://apirtc.com/wp-content/uploads/2022/12/image_package.json_.png)](https://apirtc.com/wp-content/uploads/2022/12/image_package.json_.png)  
Package.json should contain a reference to the apirtc library.

If you run a `npm start` command, you should obtain the following:

[![reactjs start new video app](https://apirtc.com/wp-content/uploads/2022/12/image_npm_start.png)](https://apirtc.com/wp-content/uploads/2022/12/image_npm_start.png)  
Your ReactJS application is started!

You are now ready to start implementing your first video communication app using ReactJS and ApiRTC library.

* * *

## Create the Conversation component

ReactJS manages the rendering life cycle of the application by using Component. We create the Conversation component responsible for

- recording and managing the state of the video conversation
- rendering the HTML markup that will contain the display of local and remote video streams.

```shell
cd src
mkdir Components
cd Components
touch ConversationComponent.jsx
```

### Make the component render HTML

In the `ConversationComponent.jsx` file insert the following:

```jsx
import { UserAgent } from '@apirtc/apirtc';
import React, { useState, useRef } from 'react';

export default function ConversationComponent() 
  return (
    <div>
        <h2>Remote videos</h2>
        <div id="remote-container">
          {/* <!-- This is where the remote video streams will be added --> */}
        </div>
        <div id="local-container">
          <h2>Local video</h2>
          <p><span id="local-stream-id"></span></p>
          {/* <!-- This is where we are going to display our local video stream --> */}
          <video id="local-video-stream" autoPlay muted></video>
        </div>
      </div>
    </div>)
}
```

Remove everything inside of the `<header>` markup of the App.js file and replace it by a `<ConversationComponent>` markup and add the import at the top of the file.

It should now look like this:

```jsx
import ConversationComponent from "./Components/ConversationComponent"

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <ConversationComponent></ConversationComponent>
      </header>
    </div>
  );
}

export default App;

```

Start the app with the `npm start` command and navigate to [http://localhost:3000/](http://localhost:3000/).

[![reactJS video chat application layout](https://apirtc.com/wp-content/uploads/2022/12/image_step1-1.png)](https://apirtc.com/wp-content/uploads/2022/12/image_step1-1.png)

Hooray, you’ve got your app layout!

> You might have some warning prompted while starting the app: no worries, delete logo.svg import and all will be fine.

* * *

## Add video communication capability to the ReactJS app

`ConversationComponent` will implement the logic described as followed (click to get a detailed view):

[![videio communication application workflow](https://apirtc.com/wp-content/uploads/2022/12/mermaid-diagram-2022-12-27-143913-1024x788.png)](https://apirtc.com/wp-content/uploads/2022/12/mermaid-diagram-2022-12-27-143913.png)

### Add the basic video communication workflow

Declare a `startConversation()` method in the `ConversationComponent` function, which will handle the whole connection process.

> Be mindful to replace `#YOUR_OWN_API_KEY#` with your own API key to be found at [https://cloud.apirtc.com/enterprise/api](https://cloud.apirtc.com/enterprise/api)

```jsx
const conversationRef = useRef(null);
const [conversationName, setConversationName] = useState("")

 var startConversation = function () {
    var localStream = null;

    /**
     * Get your free account on https://cloud.apirtc.com/ 
     * and replace the value below with your own apikey value 
     * to be found at https://cloud.apirtc.com/enterprise/api
     */

    var apikey = "#YOUR_OWN_API_KEY#"

    //Configure the User Agent using the apikey.
    var ua = new UserAgent({
      uri: 'apiKey:' + apikey
    })

    //Connect the UserAgent and get a session
    ua.register().then((session) => {

      var conversationName = "CONVERSATION_NAME"

      const conversation = session.getOrCreateConversation(conversationName, { meshOnlyEnabled: true })

      setConversationName(conversation.getName())

      conversationRef.current = conversation

      //Instantiate a local video stream object
      ua.createStream({
        constraints: {
          audio: true,
          video: true
        }
      })
        .then((stream) => {

          // Save local stream in a variable accessible to eventhandlers
          localStream = stream;

          //Display the local video stream
          stream.attachToElement(document.getElementById('local-video-stream'));
          document.getElementById('local-stream-id').innerHTML = ua.getUsername()

          //Join the conversation
          conversation.join()
            .then((response) => {

              //Publish the local stream to the conversation
              conversation
                .publish(localStream)
                .then((stream) => {
                  console.log("Your local stream is published in the conversation", stream);
                })
                .catch((err) => {
                  console.error("publish error", err);
                });
            }).catch((err) => {
              console.error('Conversation join error', err);
            });

        }).catch((err) => {
          console.error('create stream error', err);
        });
    });
  }
```

For testing purposes, we are going to call the `startConversation` method when we click on the “Start the Conversation” button. Add the following button markup rendered by the `ConversationComponent`:

```jsx
<div>
   <button id="startConversation" onClick={startConversation}>Start Conversation</button>
</div>
<div>
   <p>Conversation Name: <span id="conversationNameLabel">{conversationName}</span></p> 
</div>

```

`npm start` in your project folder and navigate to the `http://localhost:3000` address.

Clap your hands if you see yourself 👏

[![reactJS video API application](https://apirtc.com/wp-content/uploads/2022/12/image_step1.png)](https://apirtc.com/wp-content/uploads/2022/12/image_step1.png)

### Add participants’ remote video streams to your application

We are halfway to finalizing our app! Keep up the good work buddy ! 👍

Here is the logic to manage the remote video streams:

- Each time a new stream is detected 👉 subscribe to every event thrown by this stream
- Each time a new stream is added to the conversation 👉 add the video stream to the interface
- Each time a new stream is removed from the conversation 👉 remove the video stream from the interface

We are going to use `Conversation.streamListChanged`, `Conversation.streamAdded` and `Conversation.streamRemoved` events to trigger these actions.

#### Insert event handlers

Declare event handler functions as variables of the ConversationComponent function:

```jsx
//streamListchanged: subscribe to new remote streams published in the conversation and get future events triggered by this stream
  var onStreamListChangedHandler = function (streamInfo) {
    if (streamInfo.listEventType === 'added' && streamInfo.isRemote) {

      if (conversationRef.current)
        conversationRef.current.subscribeToStream(streamInfo.streamId)
          .then((stream) => {
            console.log('subscribeToStream success', streamInfo);
          }).catch((err) => {
            console.error('subscribeToStream error', err);
          });
    }
  }

  //streamAdded: Display the newly added stream
  var onStreamAddedHandler = function (stream) {
    if (stream.isRemote) {
      stream.addInDiv('remote-container', 'remote-media-' + stream.streamId, {}, false);
    }
  }

  //streamRemoved: Remove the participant's display from the UI
  var onStreamRemovedHandler = function (stream) {
    if (stream.isRemote) {
      stream.removeFromDiv('remote-container', 'remote-media-' + stream.streamId)
    }
  }
```

#### Declare video streams listeners

And then, declare the listeners just before the `ua.createStream` method call in the `startConversation` function:

```jsx
conversation.on("streamListChanged", onStreamListChangedHandler)
conversation.on("streamAdded", onStreamAddedHandler)
conversation.on("streamRemoved", onStreamRemovedHandler)
```

####  Open 2 tabs with the app running, you should see yourself twice!

> Turn off your sound output or microphone as it creates feedback and a shrieking sound.

 

[![screenshot of video chat application](https://apirtc.com/wp-content/uploads/2022/12/image_step2.png)](https://apirtc.com/wp-content/uploads/2022/12/image_step2.png)  
If you see yourself twice, you’re on a good way!

To sum up here is what ConversationComponent.jsx should look like at this step:

```jsx
import { UserAgent } from '@apirtc/apirtc';
import React, { useState, useRef } from 'react';

export default function ConversationComponent() {

  const conversationRef = useRef(null);
  const [conversationName, setConversationName] = useState("")

  //streamListchanged: subscribe to new remote stream published in the conversation and get future events triggered by this stream
  const onStreamListChangedHandler = function (streamInfo) {
    if (streamInfo.listEventType === 'added' && streamInfo.isRemote) {

      if (conversationRef.current)
        conversationRef.current.subscribeToStream(streamInfo.streamId)
          .then((stream) => {
            console.log('subscribeToStream success', streamInfo);
          }).catch((err) => {
            console.error('subscribeToStream error', err);
          });
    }
  }

  //streamAdded: Display the newly added stream
  const onStreamAddedHandler = function (stream) {
    if (stream.isRemote) {
      stream.addInDiv('remote-container', 'remote-media-' + stream.streamId, {}, false);
    }
  }

  //streamRemoved: Remove the participant's display from the UI
  const onStreamRemovedHandler = function (stream) {
    if (stream.isRemote) {
      stream.removeFromDiv('remote-container', 'remote-media-' + stream.streamId)
    }
  }

  const startConversation = function () {
    var localStream = null;

    /**
     * Get your free account on https://cloud.apirtc.com/ 
     * and replace the value below with your own apikey value 
     * to be found at https://cloud.apirtc.com/enterprise/api
     */

    const apikey = "INSERT_YOUR_OWN_APIKEY_HERE" //"#YOUR_OWN_API_KEY#"

    //Configure the User Agent using the apikey.
    const ua = new UserAgent({
      uri: 'apiKey:' + apikey
    })

    //Connect the UserAgent and get a session
    ua.register().then((session) => {

      const conversationName = "CONVERSATION_NAME"

      const conversation = session.getOrCreateConversation(conversationName, { meshOnlyEnabled: true })

      setConversationName(conversation.getName())

      conversationRef.current = conversation

      conversation.on("streamListChanged", onStreamListChangedHandler)
      conversation.on("streamAdded", onStreamAddedHandler)
      conversation.on("streamRemoved", onStreamRemovedHandler)

      //Instantiate a local video stream object
      ua.createStream({
        constraints: {
          audio: true,
          video: true
        }
      })
        .then((stream) => {

          // Save local stream in a constiable accessible to eventhandlers
          localStream = stream;

          //Display the local video stream
          stream.attachToElement(document.getElementById('local-video-stream'));
          document.getElementById('local-stream-id').innerHTML = ua.getUsername()

          //Join the conversation
          conversation.join()
            .then((response) => {

              conversation
                .publish(localStream)
                .then((stream) => {
                  console.log("Your local stream is published in the conversation", stream);
                })
                .catch((err) => {
                  console.error("publish error", err);
                });
            }).catch((err) => {
              console.error('Conversation join error', err);
            });

        }).catch((err) => {
          console.error('create stream error', err);
        });
    });
  }

  return (
    <div>
      <div>
         <button id="startConversation" onClick={startConversation}>Start Conversation</button>
      </div>
      <div>
        <p>Conversation Name: <span id="conversationNameLabel">{conversationName}</span></p>
      </div>
      <div>
        <h2>Remote videos</h2>
        <div id="remote-container">
          {/* <!-- This is where the remote video streams will be added --> */}
        </div>
        <div id="local-container">
          <h2>Local video</h2>
          <p><span id="local-stream-id"></span></p>
          {/* <!-- This is where we are going to display our local video stream --> */}
          <video id="local-video-stream" autoPlay muted></video>
        </div>
      </div>
    </div>)
}

```

 

Great folks, you finised to build a custom video chat with ReactJS and ApiRTC!

**Good work, you can give yourself a treat!
![🎉](https://s.w.org/images/core/emoji/14.0.0/72x72/1f389.png)**

* * *

## Going further

- Go deeper into ApiRTC with the [Developer Portal](https://dev.apirtc.com)
- Discover what you can do with the video and audio ApiRTC APIs by checking the [code examples on GitHub](https://github.com/ApiRTC/ApiRTC-examples).

The post [Build a custom video chat with ReactJS and ApiRTC](https://apirtc.com/blog/tutorials/custom-video-chat-reactjs-apirtc/) appeared first on [Apirtc](https://apirtc.com).