How to Integrate Image Capture in JavaScript Video Chat App?
Tags: javascript
Published: 2024-05-08 06:14:10

---
title: How to Integrate Image Capture in JavaScript Video Chat App?
published: true
date: 2024-05-03 05:49:42 UTC
tags: javascript,
canonical_url: https://www.videosdk.live/blog/integrate-image-capture-in-javascript-chat-app
---

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

## 📌 Introduction

Integrating image capture in a [JavaScript video chat app](https://www.videosdk.live/blog/video-calling-javascript) enhances user interaction and functionality. With this feature, users can take snapshots during video calls, adding a new dimension to their communication experience. By incorporating image capture, the app enables users to capture memorable moments or important information shared during the call. JavaScript's flexibility allows seamless integration of image capture, ensuring a smooth user experience across different devices and browsers.

**Benefits of Integrate Image Capture in JavaScript Video Chat App:**

1. **Enhanced Communication** : Image capture adds a visual element to video calls, improving communication and understanding.
2. **Memorable Moments** : Users can capture snapshots of important moments during the call, preserving memories.
3. **Increased Engagement** : Interactive features like image capture keep users engaged and active during video calls.

**Use Case of Integrate Image Capture in JavaScript Video Chat App:**

1. **Education:** Students can capture whiteboard content or diagrams shared during online classes for later review.
2. **Business Meetings:** Participants can capture key points discussed in meetings or presentations, ensuring clarity and accountability.
3. **Remote Collaboration:** Teams working remotely can capture design mockups, charts, or code snippets for collaborative brainstorming sessions.

This tutorial will guide you through a step-by-step process of how to integrate image capture functionality in a JavaScript chat App with [VideoSDK](https://www.videosdk.live/).

## 🚀 Getting Started with VideoSDK

To take advantage of Image Feature Integration functionality, we must use the capabilities that the VideoSDK offers. Before diving into the implementation steps, let's ensure you complete the necessary prerequisites.

### Create a VideoSDK Account

Go to your [VideoSDK dashboard](https://www.videosdk.live/signup?utm_source=organicseo&utm_medium=devto&utm_campaign=rtmp_livestream_javascript_app). This account gives you access to the required Video SDK token, which acts as an authentication key that allows your application to interact with VideoSDK functionality.

### Generate your Auth Token

Visit your VideoSDK dashboard and navigate to the "API Key" section to generate your auth token. This token is crucial in authorizing your application to use VideoSDK features. For a more visual understanding of the account creation and token generation process, consider referring to the [provided tutorial](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/authentication-and-token).

### Prerequisites

Before proceeding, ensure that your development environment meets the following requirements:

- VideoSDK Developer Account (if you do not have one, follow [VideoSDK Dashboard](https://www.videosdk.live/signup?utm_source=organicseo&utm_medium=devto&utm_campaign=rtmp_livestream_javascript_app))
- Have Node and NPM installed on your device.

## 🛠️ Install VideoSDK

Import VideoSDK using the `<script>` tag or install it using the following npm command. Make sure you are in your app directory before you run this command.

```js
// JavaScript
<html>
  <head>
    <!--.....-->
  </head>
  <body>
    <!--.....-->
    <script src="https://sdk.videosdk.live/js-sdk/0.0.83/videosdk.js"></script>
  </body>
</html>
```

**npm**

```js
npm install @videosdk.live/js-sdk
```

**Yarn**

```js
yarn add @videosdk.live/js-sdk
```

### Structure of the project

Your project structure should look like this.

```js
  root
   ├── index.html
   ├── config.js
   ├── index.js
```

You will be working on the following files:

- **index.html**: Responsible for creating a basic UI.
- **config.js**: Responsible for storing the token.
- **index.js**: Responsible for rendering the meeting view and the join meeting functionality.

## 🎥 Essential Steps to Implement Video Call Functionality

Once you've successfully installed VideoSDK in your project, you'll have access to a range of functionalities for building your video call application. Image Capture is one such feature that leverages VideoSDK's capabilities. It leverages VideoSDK's capabilities to identify the user with the strongest audio signal (the one speaking).

### Step 1: Design the user interface (UI)[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-1--design-the-user-interface-ui)

Create an HTML file containing the screens, `join-screen` and `grid-screen`.

```js
<!DOCTYPE html>
<html>
  <head> </head>

  <body>
    <div id="join-screen">
      <!-- Create new Meeting Button -->
      <button id="createMeetingBtn">New Meeting</button>
      OR
      <!-- Join existing Meeting -->
      <input type="text" id="meetingIdTxt" placeholder="Enter Meeting id" />
      <button id="joinBtn">Join Meeting</button>
    </div>

    <!-- for Managing meeting status -->
    <div id="textDiv"></div>

    <div id="grid-screen" style="display: none">
      <!-- To Display MeetingId -->
      <h3 id="meetingIdHeading"></h3>

      <!-- Controllers -->
      <button id="leaveBtn">Leave</button>
      <button id="toggleMicBtn">Toggle Mic</button>
      <button id="toggleWebCamBtn">Toggle WebCam</button>

      <!-- render Video -->
      <div class="row" id="videoContainer"></div>
    </div>

    <!-- Add VideoSDK script -->
    <script src="https://sdk.videosdk.live/js-sdk/0.0.83/videosdk.js"></script>
    <script src="config.js"></script>
    <script src="index.js"></script>
  </body>
</html>
```

### Step 2: Implement Join Screen[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-2--implement-join-screen)

Configure the token in the `config.js` file, which you can obtain from the [VideoSDK Dashboard](https://app.videosdk.live/login).

```js
// Auth token will be used to generate a meeting and connect to it
TOKEN = "Your_Token_Here";
```

Next, retrieve all the elements from the DOM and declare the following variables in the `index.js` file. Then, add an event listener to the join and create meeting buttons.

```js
// Getting Elements from DOM
const joinButton = document.getElementById("joinBtn");
const leaveButton = document.getElementById("leaveBtn");
const toggleMicButton = document.getElementById("toggleMicBtn");
const toggleWebCamButton = document.getElementById("toggleWebCamBtn");
const createButton = document.getElementById("createMeetingBtn");
const videoContainer = document.getElementById("videoContainer");
const textDiv = document.getElementById("textDiv");

// Declare Variables
let meeting = null;
let meetingId = "";
let isMicOn = false;
let isWebCamOn = false;

function initializeMeeting() {}

function createLocalParticipant() {}

function createVideoElement() {}

function createAudioElement() {}

function setTrack() {}

// Join Meeting Button Event Listener
joinButton.addEventListener("click", async () => {
  document.getElementById("join-screen").style.display = "none";
  textDiv.textContent = "Joining the meeting...";

  roomId = document.getElementById("meetingIdTxt").value;
  meetingId = roomId;

  initializeMeeting();
});

// Create Meeting Button Event Listener
createButton.addEventListener("click", async () => {
  document.getElementById("join-screen").style.display = "none";
  textDiv.textContent = "Please wait, we are joining the meeting";

  // API call to create meeting
  const url = `https://api.videosdk.live/v2/rooms`;
  const options = {
    method: "POST",
    headers: { Authorization: TOKEN, "Content-Type": "application/json" },
  };

  const { roomId } = await fetch(url, options)
    .then((response) => response.json())
    .catch((error) => alert("error", error));
  meetingId = roomId;

  initializeMeeting();
});
```

### Step 3: Initialize Meeting[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-3--initialize-meeting)

Following that, initialize the meeting using the `initMeeting()` function and proceed to join the meeting.

```js
// Initialize meeting
function initializeMeeting() {
  window.VideoSDK.config(TOKEN);

  meeting = window.VideoSDK.initMeeting({
    meetingId: meetingId, // required
    name: "Thomas Edison", // required
    micEnabled: true, // optional, default: true
    webcamEnabled: true, // optional, default: true
  });

  meeting.join();

  // Creating local participant
  createLocalParticipant();

  // Setting local participant stream
  meeting.localParticipant.on("stream-enabled", (stream) => {
    setTrack(stream, null, meeting.localParticipant, true);
  });

  // meeting joined event
  meeting.on("meeting-joined", () => {
    textDiv.style.display = "none";
    document.getElementById("grid-screen").style.display = "block";
    document.getElementById(
      "meetingIdHeading"
    ).textContent = `Meeting Id: ${meetingId}`;
  });

  // meeting left event
  meeting.on("meeting-left", () => {
    videoContainer.innerHTML = "";
  });

  // Remote participants Event
  // participant joined
  meeting.on("participant-joined", (participant) => {
    // ...
  });

  // participant left
  meeting.on("participant-left", (participant) => {
    // ...
  });
}
```

### Step 4: Create the Media Elements[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-4--create-the-media-elements)

In this step, Create a function to generate audio and video elements for displaying both local and remote participants. Set the corresponding media track based on whether it's a video or audio stream.

```js
// creating video element
function createVideoElement(pId, name) {
  let videoFrame = document.createElement("div");
  videoFrame.setAttribute("id", `f-${pId}`);
  videoFrame.style.width = "300px";
    

  //create video
  let videoElement = document.createElement("video");
  videoElement.classList.add("video-frame");
  videoElement.setAttribute("id", `v-${pId}`);
  videoElement.setAttribute("playsinline", true);
  videoElement.setAttribute("width", "300");
  videoFrame.appendChild(videoElement);

  let displayName = document.createElement("div");
  displayName.innerHTML = `Name : ${name}`;

  videoFrame.appendChild(displayName);
  return videoFrame;
}

// creating audio element
function createAudioElement(pId) {
  let audioElement = document.createElement("audio");
  audioElement.setAttribute("autoPlay", "false");
  audioElement.setAttribute("playsInline", "true");
  audioElement.setAttribute("controls", "false");
  audioElement.setAttribute("id", `a-${pId}`);
  audioElement.style.display = "none";
  return audioElement;
}

// creating local participant
function createLocalParticipant() {
  let localParticipant = createVideoElement(
    meeting.localParticipant.id,
    meeting.localParticipant.displayName
  );
  videoContainer.appendChild(localParticipant);
}

// setting media track
function setTrack(stream, audioElement, participant, isLocal) {
  if (stream.kind == "video") {
    isWebCamOn = true;
    const mediaStream = new MediaStream();
    mediaStream.addTrack(stream.track);
    let videoElm = document.getElementById(`v-${participant.id}`);
    videoElm.srcObject = mediaStream;
    videoElm
      .play()
      .catch((error) =>
        console.error("videoElem.current.play() failed", error)
      );
  }
  if (stream.kind == "audio") {
    if (isLocal) {
      isMicOn = true;
    } else {
      const mediaStream = new MediaStream();
      mediaStream.addTrack(stream.track);
      audioElement.srcObject = mediaStream;
      audioElement
        .play()
        .catch((error) => console.error("audioElem.play() failed", error));
    }
  }
}
```

### Step 5: Handle participant events[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-5--handle-participant-events)

Thereafter, implement the events related to the participants and the stream.

The following are the events to be executed in this step:

1. `participant-joined`: When a remote participant joins, this event will trigger. In the event callback, create video and audio elements previously defined for rendering their video and audio streams.
2. `participant-left`: When a remote participant leaves, this event will trigger. In the event callback, remove the corresponding video and audio elements.
3. `stream-enabled`: This event manages the media track of a specific participant by associating it with the appropriate video or audio element.

```js
// Initialize meeting
function initializeMeeting() {
  // ...

  // participant joined
  meeting.on("participant-joined", (participant) => {
    let videoElement = createVideoElement(
      participant.id,
      participant.displayName
    );
    let audioElement = createAudioElement(participant.id);
    // stream-enabled
    participant.on("stream-enabled", (stream) => {
      setTrack(stream, audioElement, participant, false);
    });
    videoContainer.appendChild(videoElement);
    videoContainer.appendChild(audioElement);
  });

  // participants left
  meeting.on("participant-left", (participant) => {
    let vElement = document.getElementById(`f-${participant.id}`);
    vElement.remove(vElement);

    let aElement = document.getElementById(`a-${participant.id}`);
    aElement.remove(aElement);
  });
}
```

### Step 6: Implement Controls[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/quick-start#step-6--implement-controls)

Next, implement the meeting controls such as toggleMic, toggleWebcam, and leave the meeting.

```js
// leave Meeting Button Event Listener
leaveButton.addEventListener("click", async () => {
  meeting?.leave();
  document.getElementById("grid-screen").style.display = "none";
  document.getElementById("join-screen").style.display = "block";
});

// Toggle Mic Button Event Listener
toggleMicButton.addEventListener("click", async () => {
  if (isMicOn) {
    // Disable Mic in Meeting
    meeting?.muteMic();
  } else {
    // Enable Mic in Meeting
    meeting?.unmuteMic();
  }
  isMicOn = !isMicOn;
});

// Toggle Web Cam Button Event Listener
toggleWebCamButton.addEventListener("click", async () => {
  if (isWebCamOn) {
    // Disable Webcam in Meeting
    meeting?.disableWebcam();

    let vElement = document.getElementById(`f-${meeting.localParticipant.id}`);
    vElement.style.display = "none";
  } else {
    // Enable Webcam in Meeting
    meeting?.enableWebcam();

    let vElement = document.getElementById(`f-${meeting.localParticipant.id}`);
    vElement.style.display = "inline";
  }
  isWebCamOn = !isWebCamOn;
});
```

You can check out the complete code [here](https://github.com/videosdk-live/quickstart/tree/main/js-rtc).

## Integrate Image Capture Feature

This guide provides instructions on capturing images of participants from a video stream. This capability proves particularly valuable in Video KYC scenarios, enabling the capture of images where users can hold up their identity for verification.

By using the `captureImage()` method of the `Participant` class, you can capture an image of a local participant from their video stream.

- You have the option to specify the desired height and width in the `captureImage()` function; however, these parameters are optional. If not provided, the VideoSDK will automatically use the dimensions of the local participant's webcamStream.
- The `captureImage()` function returns the image in the form of a `base64` string.

```js
let meeting;

// Initialize Meeting
meeting = VideoSDK.initMeeting({
  // ...
});

let isWebcamOn; // status of your webcam, true/false

async function imageCapture() {
  if (isWebcamOn) {
    const base64Data = await meeting.localParticipant.captureImage(); // captureImage will return base64 string
    console.log("base64", base64);
  } else {
    console.error("Camera must be on to capture an image");
  }
}
```

> **TIP:**  
> Rather than utilizing the `participants.get(participantId).captureImage()` method to capture an image of a remote participant, it is advisable to refer to the provided documentation for a more effective approach.   
>   
> The `participants.get(participantId).captureImage()` method captures an image from the current video stream being consumed from the remote participant. The alternative documentation is likely to provide a better and more appropriate method to achieve the desired result.

### How to capture an image of a remote participant?[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/handling-media/image-capturer#how-to-capture-image-of-remote-participant-)

- Before proceeding, it's crucial to understand [VideoSDK's temporary file storage system](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/collaboration-in-meeting/upload-fetch-temporary-file) and the underlying [pubsub mechanism](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/collaboration-in-meeting/pubsub).
- Here's a breakdown of the steps, using the names Participant A and Participant B for clarity:

#### Step 1: Initiate Image Capture Request[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/handling-media/image-capturer#step-1--initiate-image-capture-request)

- In this step, you have to first send a request to Participant B, whose image you want to capture, using Pubsub.
- To do that, you have to create a Pubsub topic called `IMAGE_CAPTURE` the `index.js` File.​
- Here, you will be using the `sendOnly` property of the `publish()` method. Therefore, the request will be sent to that participant only.

```js
let meeting;

// Initialize Meeting
meeting = VideoSDK.initMeeting({
  // ...
});

function sendRequest({ participantId }) {
  // Pass the participantId of the participant twhose image you want to capture 
  // Here, it will be Participant B's id, as you want to capture the the image of Participant B
  let message = "Sending request to capture image";
  meeting.pubSub
    .publish("IMAGE_CAPTURE", message, {
      persist: false,
      sendOnly: [participantId],
    })
    .then((res) => console.log(`response of publish : ${res}`))
    .catch((err) => console.log(`error of publish : ${err}`));
}
```

Place one button to capture an image of a remote participant in `index.js` file inside createVideoElement function.

```js
// creating video element
function createVideoElement(pId, name) {
// ...

  // Create wrapper div
  let wrapperDiv = document.createElement("div");
    
  // Create button element
  let buttonElement = document.createElement("button");
  buttonElement.setAttribute("id", `btnCaptureImage-${pId}`);
  buttonElement.textContent = "CaptureImage";
  buttonElement.classList.add("capture-button");
    
  // Append video and button elements to the wrapper div
  wrapperDiv.appendChild(videoElement);
  wrapperDiv.appendChild(buttonElement);

  // Append the wrapper div before the video element
  division.appendChild(wrapperDiv);

  // Set up event listener for hover effect

  wrapperDiv.addEventListener("mouseover", function () {
    buttonElement.style.display = "block";
  });

  wrapperDiv.addEventListener("mouseout", function () {
    buttonElement.style.display = "none";
  });

  wrapperDiv.style.width = `${videoElement.getAttribute("width")}px`;
  wrapperDiv.style.height = `${videoElement.getAttribute("height")}px`;

//...
}
```

Now on the capture Image button click the call `sendRequest()` in `index.js`

```js
// creating video element
function createVideoElement(pId, name) {
// ...
    
    buttonElement.addEventListener("click", async function () {
    if (pId == meeting.localParticipant.id) {
      const base64Data = await meeting.localParticipant.captureImage();
      base64 = "data:data:image/jpeg;base64," + base64Data;
      captureImageDiv.style.display = "block";
      captureImage.src = base64;
      captureImage.onload = function () {
        alert(this.width + "x" + this.height);
      };
    } else {
      let participantId = await participants.get(pId);
      sendRequest({ participantId: participantId.id });
    }
  });
}    
```

#### Step 2: Capture and Upload File[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/handling-media/image-capturer#step-2--capture-and-upload-file)

- To capture an image from the remote participant [Participant B], you have to subscribe to the pub-sub topic on the `meeting-joined` event of the `Meeting` class. When a participant receives an image capture request, this component uses the `captureImage` method of the `Participant` class to capture the image.

```js
let meeting;

// Initialize Meeting
meeting = VideoSDK.initMeeting({
  // ...
});

async function captureAndStoreImage() {
  // capture image
  const base64Data = await meeting.localParticipant.captureImage();
  console.log("base64Data", base64Data);
}

const _handleOnImageCaptureMessageReceived = (message) => {
  try {
    if (message.senderId !== meeting.localParticipant.id) {
      // capture and store image when message received
      captureAndStoreImage();
    }
  } catch (err) {
    console.log("error on image capture", err);
  }
};

meeting.on("meeting-joined", () => {
  // ...
  meeting.pubSub.subscribe("IMAGE_CAPTURE", (data) => {
    _handleOnImageCaptureMessageReceived(data);
  });
});
```

- The captured image is then stored in VideoSDK's temporary file storage system using the `uploadBase64File()` function of the `Meeting` class. This operation returns a unique `fileUrl` of the stored image.

```js
let meeting;

// Initialize Meeting
meeting = VideoSDK.initMeeting({
  // ...
});

async function captureAndStoreImage() {
  // capture image
  const base64Data = await meeting.localParticipant.captureImage();
  // upload image to videosdk storage system
  const fileUrl = await meeting.uploadBase64File({
    base64Data,
    token: "VIDEOSDK_TOKEN",
    fileName: "myImage.jpeg", // specify a name for image file with extension
  });

  console.log("fileUrl", fileUrl);
}
```

- Next, the `fileUrl` is sent back to the participant who initiated the request using the `IMAGE_TRANSFER` topic.

```js
async function captureAndStoreImage() {
  // ...

  const fileUrl = await meeting.uploadBase64File({
    base64Data,
    token: "VIDEOSDK_TOKEN",
    fileName: "myImage.jpeg", // specify a name for image file with extension
  });

  // publish image Transfer
  meeting.pubSub
    .publish("IMAGE_TRANSFER", fileUrl, {
      persist: false,
      sendOnly: [senderId],
    })
    .then((res) => console.log(`response of publish : ${res}`))
    .catch((err) => console.log(`error of publish : ${err}`));
}
```

#### Step 2: Fetch and Display Image[​](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/handling-media/image-capturer#step-2--fetch-and-display-image)

- Upon publishing on the `IMAGE_TRANSFER` topic, subscribe to the same topic within the `meeting-joined` event of the `Meeting` class. This will provide access to the `fileUrl` associated with the captured image. Once obtained, use the `fetchBase64File()` method of the `Meeting` class to retrieve the file in `base64` format from VideoSDK's temporary storage.

```js
async function captureImageAndDisplay(message) {
  const token = "VIDEOSDK_TOKEN";
  let base64 = await meeting.fetchBase64File({
    url: message.message,
    token,
  });
  console.log("base64", base64); // here is your image in a form of base64
}

meeting.on("meeting-joined", () => {
  // ...
  meeting.pubSub.subscribe("IMAGE_TRANSFER", (data) => {
    if (data.senderId !== meeting.localParticipant.id) {
      captureImageAndDisplay(data);
    }
  });
});
```

- With the `base64` data in hand, you can now display the image.

```js
let captureImage = document.getElementById("captureImage");

async function captureImageAndDisplay(message) {
  const token = "VIDEOSDK_TOKEN";
  let base64 = await meeting.fetchBase64File({
    url: message.message,
    token,
  });
  console.log("base64", base64); // here is your image in a form of base64

  base64 = "data:data:image/jpeg;base64," + base64;
  captureImage.src = base64;
}

<!-- -->
<img id="captureImage" />
```

> **NOTE:**  
> The file stored in the [VideoSDK's temporary file storage system](https://docs.videosdk.live/javascript/guide/video-and-audio-calling-api-sdk/collaboration-in-meeting/upload-fetch-temporary-file) will be automatically deleted once the current room/meeting comes to an end.

## 🔚 Conclusion

Integrating image capture into a JavaScript video call app significantly enhances its functionality and user experience. This feature not only adds a visual dimension to communication but also provides users with a valuable tool for capturing and preserving important moments, information, or visuals shared during the call.

VideoSDK's capabilities ensure seamless integration of image capture functionality with VideoSDK, providing a smooth user experience across different platforms and devices. By incorporating this feature, the JavaScript video call app becomes more versatile, empowering users with enhanced communication tools and fostering a more interactive and engaging environment.

Ready to get started? **[Sign up](https://www.videosdk.live/signup?utm_source=organicseo&utm_medium=devto&utm_campaign=rtmp_livestream_javascript_app)** today and take advantage of **10,000 free minutes** to experiment with image capture and explore the other powerful features VideoSDK offers.