# Quickstart (/en/realtime-media/interactive-live-streaming/quickstart/web)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Explore sample implementations to quickly integrate Conversational AI.

    * [RTC SDK API examples](https://github.com/AgoraIO/API-Examples-Web): Sample projects for the Agora RTC Web SDK 4.x, covering basic, advanced examples for Vue and React.

    This page provides a step-by-step guide on how to create a basic Interactive Live Streaming app using the Agora Video SDK.

    ## Understand the tech [#understand-the-tech-3]

    To start a Interactive Live Streaming session, implement the following steps in your app:

    * **Initialize the Agora Engine**: Before calling other APIs, create and initialize an Agora Engine instance.

    * **Join a channel**: Call methods to create and join a channel.

      * **Join as a host**: A live streaming event has one or more hosts. A host publishes audio and video to the channel. Hosts can also subscribe to streams from other hosts.

      * **Join as audience**: Audience members can only subscribe to streams published by hosts.

    * **Send and receive audio and video**: Hosts publish streams to the channel. Audience members subscribe to audio and video streams published by hosts.

    ![Streaming workflow](https://assets-docs.agora.io/images/video-sdk/get-started-ils-bs.svg)

    ## Prerequisites [#prerequisites-3]

    * A [supported browser](/en/realtime-media/interactive-live-streaming/reference/supported-platforms).
      Agora strongly recommends using the latest stable version of Google Chrome.

    * [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)

    * A camera and a microphone

    * A valid Agora account and project. Please refer to [Agora account management](manage-agora-account.md) for details.

    ## Set up your project [#set-up-your-project-3]

    This section shows you how to set up your Web project and install the Agora Video SDK.

    **Create a new project**
    To initialize a new Vite project, take the following steps:

    1. Open a terminal and run the following command:

       ```bash
       npm create vite@latest agora_web_quickstart -- --template vanilla
       ```

    This creates a new folder named `agora_web_quickstart` and initializes a Vite project inside it using the `vanilla` JavaScript template.

    1. Navigate to the newly created folder. Download and set up dependencies for your project:

       ```bash
       cd agora_web_quickstart
       npm install
       ```

    2. Create a user interface for your project. The UI consists of buttons to join and leave a channel. Refer to [Create a user interface](#create-a-user-interface) to get a bare bones html layout.

    **Add to an existing project**
    To add Interactive Live Streaming to your existing project, take the following steps:

    2. Create a JavaScript file in your project's `src` folder to add `AgoraRTCClient` code that implements specific application logic.

    3. Add an HTML file to your project to create a user interface. The UI consists of buttons to join and leave a channel. Refer to [Create a user interface](#create-a-user-interface) to get a bare bones HTML layout.

    4. Include the JavaScript file in your HTML file.

       ```html
       <script type="module" src="/src/main.js"></script>
       ```

    ### Install the SDK [#install-the-sdk-3]

    Add the Video SDK to your project:

    ```bash
    npm install agora-rtc-sdk-ng
    ```

    ## Implement Interactive Live Streaming [#implement-interactive-live-streaming-3]

    This section guides you through the implementation of basic real-time audio and video interaction in your app.

    ![image](https://assets-docs.agora.io/images/video-sdk/ils-quick-start-sequence-web.svg)

    This guide includes [complete sample code](#complete-sample-code) that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps.

    ### Import the `AgoraRTC` SDK [#import-the-agorartc-sdk]

    ```js
    import AgoraRTC from "agora-rtc-sdk-ng";
    ```

    ### Initialize an instance of `AgoraRTCClient` [#initialize-an-instance-of-agorartcclient]

    Call [`createClient`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createclient) to initialize an `AgoraRTCClient` object.
    Set the [Channel mode](#channel-modes) and [Video encoding format](#video-encoding-formats) based on your use case.

    For Interactive Live Streaming Set `mode` to `live`.

    ```javascript
    // RTC client instance
    let client = null;

    // Initialize the AgoraRTC client
    function initializeClient() {
      client = AgoraRTC.createClient({ mode: "live", codec: "vp8", role: "host" });
      setupEventListeners();
    }
    ```

    ### Join a channel [#join-a-channel-3]

    To join a channel, call `join` with the following parameters:

    * **App ID**: The [App ID](manage-agora-account.md) for your project.

    * **Channel name**: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.

    * **Authentication token**: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a [token server](build/authenticate-users/deploy-token-server.mdx) in your security infrastructure. For the purpose of this guide [Generate a temporary token](manage-agora-account.md).

    * **User ID**: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to `0` when joining a channel, the SDK generates a random number for the user ID.

    When you join as a host, you can publish local media streams in the channel; you can also subscribe to streams published by other hosts. As an audience member, you may only subscribe to media streams published by hosts.

    * Join as a host

      ```js
      // Join as a host
      async function joinAsHost() {
        await client.join(appId, channel, token, uid);
        // A host can both publish tracks and subscribe to tracks
        client.setClientRole("host");
        // Create and publish local tracks
        await createLocalMediaTracks();
        await publishLocalTracks();
        displayLocalVideo();
      }
      ```

    * Join as audience

      To join a channel as an audience member, first call `join`, then use `setClientRole` to set the role. Listen for the `user-published` callback to play the tracks published in the channel.

      ```js
      // Join as audience
      async function joinAsAudience() {
        await client.join(appId, channel, token, uid);

        // Set ultra-low latency level for interactive live streaming
        let clientRoleOptions = { level: 2 };
        // Audience can only subscribe to tracks
        client.setClientRole("audience", clientRoleOptions);
      }
      ```

    ### Create local media tracks [#create-local-media-tracks]

    To set up the necessary local media tracks:

    * Call `createMicrophoneAudioTrack` to create a local audio track.
    * Call `createCameraVideoTrack` to create a local Video track.

    ```javascript
    // Declare variables for local tracks
    let localAudioTrack = null;
    let localVideoTrack = null;

    // Create local audio and video tracks
    async function createLocalMediaTracks() {
      localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
      localVideoTrack = await AgoraRTC.createCameraVideoTrack();
    }
    ```

    ### Publish local media tracks [#publish-local-media-tracks]

    To make the created audio and video tracks available for other users in the channel, use the `publish` method.

    ```javascript
    async function publishLocalTracks() {
      await client.publish([localAudioTrack, localVideoTrack]);
    }
    ```

    See [Local audio and video tracks](#local--tracks) to learn more about local tracks.

    ### Set up event listeners [#set-up-event-listeners]

    Use the `on` method to register event listeners for SDK events. The SDK triggers the `user-published` event when a user publishes an audio track in the channel. Similarly, it triggers the `user-unpublished` event when a user leaves the channel, goes offline, or unpublishes a media track.

    ```javascript
    // Handle client events
    function setupEventListeners() {
      // Declare event handler for "user-published"
      client.on("user-published", async (user, mediaType) => {
        // Subscribe to media streams
        await client.subscribe(user, mediaType);
        if (mediaType === "video") {
          // Specify the ID of the DOM element or pass a DOM object.
          user.videoTrack.play("<Specify a DOM element>");
        }
        if (mediaType === "audio") {
          user.audioTrack.play();
        }
      });

      // Handle the "user-unpublished" event to unsubscribe from the user's media tracks
      client.on("user-unpublished", async (user) => {
        const remotePlayerContainer = document.getElementById(user.uid);
        remotePlayerContainer && remotePlayerContainer.remove();
      });
    }
    ```

    * After successfully unsubscribing, the SDK releases the corresponding `RemoteTrack` object. This automatically removes the video playback element and stops audio playback.
    * If a remote user actively stops publishing, the local user receives the `user-unpublished` callback. Upon receiving this callback, the SDK automatically releases the corresponding `RemoteTrack` object, so you do not need to call `unsubscribe` again.
    * The `unsubscribe` method is asynchronous and should be used with `Promise` or `async/await`.

    <CalloutContainer type="info">
      <CalloutDescription>
        To ensure that you receive all Video SDK events, set up event listeners before joining a channel.
      </CalloutDescription>
    </CalloutContainer>

    For more information about other `AgoraRTCClient` events, refer to the [API reference](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_channel_media_relay_event).

    ### Display the local video [#display-the-local-video-3]

    To play the local video, use the `play` method of the local video track. Pass an element ID or a DOM element from your UI where you want to render the video.

    ```javascript
    // Display local video
    function displayLocalVideo() {
      const localPlayerContainer = document.createElement("div");
      localPlayerContainer.id = uid;
      localPlayerContainer.textContent = `Local user ${uid}`;
      localPlayerContainer.style.width = "640px";
      localPlayerContainer.style.height = "480px";
      document.body.append(localPlayerContainer);
      localVideoTrack.play(localPlayerContainer);
    }
    ```

    ### Display remote video [#display-remote-video-3]

    To display the remote video, call the `play` method of the remote user's `videoTrack` and pass in either the element ID or a DOM element from your UI where you want to render the video.

    ```js
    // Display remote user's video
    function displayRemoteVideo(user) {
      const remotePlayerContainer = document.createElement("div");
      remotePlayerContainer.id = user.uid.toString();
      remotePlayerContainer.textContent = `Remote user ${user.uid}`;
      remotePlayerContainer.style.width = "640px";
      remotePlayerContainer.style.height = "480px";
      document.body.append(remotePlayerContainer);
      user.videoTrack.play(remotePlayerContainer);
    }
    ```

    ### Leave the channel [#leave-the-channel]

    To exit the channel, close local audio and video tracks and call `leave`.

    ```javascript
    // Leave the channel and clean up
    async function leaveChannel() {
      // Stop the local media tracks to release the microphone and camera resources
      if (localAudioTrack) {
        localAudioTrack.close();
        localAudioTrack = null;
      }
      if (localVideoTrack) {
        localVideoTrack.close();
        localVideoTrack = null;
      }
      // Leave the channel
      await client.leave();
    }
    ```

    ### Complete sample code [#complete-sample-code-3]

    A complete code sample demonstrating the basic process of real-time interaction is provided here for your reference. To use the sample, copy the following code to the JavaScript file in the project's `src` folder.

    <Accordions>
      <Accordion title="Complete sample code for real-time Interactive Live Streaming">
        ```js
        import AgoraRTC from "agora-rtc-sdk-ng";

        // RTC client instance
        let client = null;

        // Declare variables for local tracks
        let localAudioTrack = null;
        let localVideoTrack = null;

        // Connection parameters
        let appId = "<-- Insert app ID -->";
        let channel = "<-- Insert channel name -->";
        let token = "<-- Insert token -->";
        let uid = 0; // User ID

        // Initialize the AgoraRTC client
        function initializeClient() {
          client = AgoraRTC.createClient({ mode: "live", codec: "vp8", role: "host" });
          setupEventListeners();
        }

        // Handle client events
        function setupEventListeners() {
          client.on("user-published", async (user, mediaType) => {
            await client.subscribe(user, mediaType);
            console.log("subscribe success");
            if (mediaType === "video") {
              displayRemoteVideo(user);
            }
            if (mediaType === "audio") {
              user.audioTrack.play();
            }
          });
          client.on("user-unpublished", async (user) => {
            const remotePlayerContainer = document.getElementById(user.uid);
            remotePlayerContainer && remotePlayerContainer.remove();
          });
        }

        // Create and publish local tracks
        async function createLocalTracks() {
          localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
          localVideoTrack = await AgoraRTC.createCameraVideoTrack();
        }

        // Display local video
        function displayLocalVideo() {
          const localPlayerContainer = document.createElement("div");
          localPlayerContainer.id = uid;
          localPlayerContainer.textContent = `Local user ${uid}`;
          localPlayerContainer.style.width = "640px";
          localPlayerContainer.style.height = "480px";
          document.body.append(localPlayerContainer);
          localVideoTrack.play(localPlayerContainer);
        }

        // Join as a host
        async function joinAsHost() {
          await client.join(appId, channel, token, uid);
          // A host can both publish tracks and subscribe to tracks
          client.setClientRole("host");
          // Create and publish local tracks
          await createLocalTracks();
          await publishLocalTracks();
          displayLocalVideo();
          disableJoinButtons();
          console.log("Host joined and published tracks.");
        }

        // Join as audience
        async function joinAsAudience() {
          await client.join(appId, channel, token, uid);
          // Set ultra-low latency level
          let clientRoleOptions = { level: 2 };
          // Audience can only subscribe to tracks
          client.setClientRole("audience", clientRoleOptions);
          disableJoinButtons();
          console.log("Audience joined.");
        }

        // Publish local tracks
        async function publishLocalTracks() {
          await client.publish([localAudioTrack, localVideoTrack]);
        }

        // Display remote user's video
        function displayRemoteVideo(user) {
          const remotePlayerContainer = document.createElement("div");
          remotePlayerContainer.id = user.uid.toString();
          remotePlayerContainer.textContent = `Remote user ${user.uid}`;
          remotePlayerContainer.style.width = "640px";
          remotePlayerContainer.style.height = "480px";
          document.body.append(remotePlayerContainer);
          user.videoTrack.play(remotePlayerContainer);
        }

        // Leave the channel
        async function leaveChannel() {
          if (localAudioTrack) {
            localAudioTrack.close();
            localAudioTrack = null;
          }
          if (localVideoTrack) {
            localVideoTrack.close();
            localVideoTrack = null;
          }
          const localPlayerContainer = document.getElementById(uid);
          localPlayerContainer && localPlayerContainer.remove();
          client.remoteUsers.forEach((user) => {
            const playerContainer = document.getElementById(user.uid);
            playerContainer && playerContainer.remove();
          });
          await client.leave();
          enableJoinButtons();
          console.log("Left the channel.");
        }

        // Disable join buttons
        function disableJoinButtons() {
          document.getElementById("host-join").disabled = true;
          document.getElementById("audience-join").disabled = true;
        }

        // Enable join buttons
        function enableJoinButtons() {
          document.getElementById("host-join").disabled = false;
          document.getElementById("audience-join").disabled = false;
        }

        // Set up event listeners for buttons
        function setupButtonHandlers() {
          document.getElementById("host-join").onclick = joinAsHost;
          document.getElementById("audience-join").onclick = joinAsAudience;
          document.getElementById("leave").onclick = leaveChannel;
        }

        // Start live streaming
        function startBasicLiveStreaming() {
          initializeClient();
          window.onload = setupButtonHandlers;
        }
        startBasicLiveStreaming();
        ```
      </Accordion>
    </Accordions>

    ### Create a user interface [#create-a-user-interface-3]

    Open `index.html` in the project's root folder and replace the contents with the following code to implement a basic client user interface:

    **Sample code to create the user interface**

    ```html
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <title>Agora Web SDK Quickstart</title>
      </head>
      <body>
        <h2 class="left-align">Agora Web SDK Quickstart</h2>
        <div class="row">
          <div>
            <button type="button" id="host-join">Join as host</button>
            <button type="button" id="audience-join">Join as audience</button>
            <button type="button" id="leave">Leave</button>
          </div>
        </div>
        <!-- Include the JavaScript file -->
        <script type="module" src="/src/main.js"></script>
      </body>
    </html>
    ```

    ## Test the sample code [#test-the-sample-code-3]

    Take the following steps to run and test the sample code:

    1. In your `.js` file, update the values for `appId`, and `token` with values from Agora Console. Use the same `channel` name you used to generate the token.

    2. To start the development server, use the following command:

       ```bash
       npm run dev
       ```

    3. Open your browser and navigate to the URL displayed in your terminal, for example, `http://localhost:5173`.

    You see the following page:

    ![image](https://assets-docs.agora.io/images/video-sdk/quickstart-ui-web-ils.png)

    4. On a second device, repeat the previous steps to install and launch the app. Alternatively, use the [Web demo](https://webdemo.agora.io/basicVideoCall/index.html) or clone the [sample project on Github](https://github.com/AgoraIO/API-Examples-Web) to join the same channel and test the following use-cases:

       * If users on both devices join the channel as hosts, they can see and hear each other.
       * If one user joins as host and the other as audience, the host can see themselves; the audience can see the host in the remote video view and hear the host.

    <CalloutContainer type="info">
      <CalloutDescription>
        * Run the web app on a local server (localhost) for testing purposes only. When deploying to a production environment, use the HTTPS protocol.
        * Due to browser security policies that restrict HTTP addresses to 127.0.0.1, the Agora Web SDK only supports HTTPS protocol and `http://localhost` (`http://127.0.0.1`). Please do not use the HTTP protocol to access your project, except for `http://localhost` (`http://127.0.0.1`).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-3]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    * If a firewall is deployed in your network environment, refer to [Connect with Cloud Proxy](build/optimize-quality-and-connection/cloud-proxy.mdx) to use Agora services normally.

    ### Next steps [#next-steps-3]

    After implementing the quickstart sample, read the following documents to learn more:

    * To ensure communication security in a test or production environment, best practice is to obtain and use a token from an authentication server. For details, see [Secure authentication with tokens](build/authenticate-users/use-tokens.mdx).

    ### Sample project [#sample-project-3]

    * [Build a NextJS Video Call App](https://www.agora.io/en/blog/build-a-next-js-video-call-app/)

    * Agora provides open source sample projects on [GitHub](https://github.com/AgoraIO/API-Examples-Web) for your reference. Download or view the [basicVideoCall](https://github.com/AgoraIO/API-Examples-Web/tree/main/src/example/basic/basicVideoCall) project for a more detailed example.

    ### API reference [#api-reference-3]

    * [`AgoraRTC.createClient`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createclient)
    * [`IAgoraRTCRemoteUser`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcremoteuser.html)
    * [`play`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iremoteaudiotrack.html#play)
    * [`join`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#join)
    * [`createMicrophoneAudioTrack`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createmicrophoneaudiotrack)
    * [`createCameraVideoTrack`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createcameravideotrack)
    * [`publish`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#publish)
    * [AgoraRTCClient events](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#event_channel_media_relay_event)

    ### Channel modes [#channel-modes]

    The Video SDK supports the following channel modes:

    * `rtc`: Communication use-case
    * `live`: Live broadcast use-case

    #### Communication use-case [#communication-use-case]

    It is suitable for use-cases where all users in the channel need to communicate with each other and the total number of users is not too large, such as multi-person conferences and online chats.

    #### Live broadcast use-case [#live-broadcast-use-case]

    It is suitable for use-cases where there are few publishers but many subscribers. In this use-case, the SDK defines two user roles: audience (default) and host. Hosts can send and receive audio and video, but audience cannot send and may only receive audio and video. You can specify user roles by setting the parameters `createClient` of role, or you can call `setClientRole` to dynamically modify user roles.

    ### Video encoding formats [#video-encoding-formats]

    You can set the `codec` parameter in the `createClient` method to the following video encoding formats:

    * `vp8` (VP8)
    * `h264` (H.264)
    * `vp9` (VP9)

    This setting only affects the video encoding format of the host. For the audience, as long as their device and browser support the decoding of this format, the subscription can be completed normally.

    Support for these formats may vary across browsers and devices. The following table lists the `codec` formats supported by different browsers for reference:

    | Browser            | VP8 | H.264                | VP9                     |
    | :----------------- | --- | -------------------- | ----------------------- |
    | Desktop Chrome 58+ | ✔   | ✔                    | ✔                       |
    | Firefox 56+        | ✔   | ✔                    | ✔(Requires Firefox 69+) |
    | Safari 12.1+       | ✔   | ✔                    | ✔(Requires Safari 16+)  |
    | Safari \< 12.1     | ✘   | ✔                    | ✘                       |
    | AndroidChrome 58+  | ✔   | No clear information | ✔(Requires Chrome 68+)  |

    <CalloutContainer type="info">
      <CalloutDescription>
        * H.264 support on Firefox depends on the `OpenH264` video codec plug-in from Cisco Systems, Inc.
        * For Chrome, support for H.264 on Android devices varies based on device hardware compatibility with hardware codecs mandated by Chrome.
      </CalloutDescription>
    </CalloutContainer>

    ### Local audio and video tracks [#local-audio-and-video-tracks]

    The SDK uses a hierarchy where all local track objects derive from the `LocalTrack` base class. This class defines the common behavior for all local tracks. Specific track types, such as `LocalAudioTrack` and `LocalVideoTrack` inherit from `LocalTrack` and extend its functionality.

    To publish a local track, you call the `publish` method of the client with the `LocalTrack` object as an input parameter. This approach makes publishing a track independent of how you create your local track.

    There are two main types of local tracks: `LocalAudioTrack` and `LocalVideoTrack` for publishing audio and video, respectively. Each type of `LocalTrack` comes with its own set of tools. For example, `LocalAudioTrack` lets you control the volume, while `LocalVideoTrack` has functions for customizing video.

    The SDK includes more specific classes based on `LocalAudioTrack` and `LocalVideoTrack`. For example, the `CameraVideoTrack`, is a type of `LocalVideoTrack` that you can use to publish video from your camera. It comes with extra features for controlling the camera and adjusting video quality.

    The following diagram shows the relationship between the `LocalTrack` classes:

    ![ILocalTrack](https://assets-docs.agora.io/images/video-sdk/ILocalTrack-web.png)

    ### Other integration methods [#other-integration-methods]

    When you use `npm` to install the Web SDK, you can enable tree shaking to reduce the size of the app after integration. For details, see [Using tree shaking](build/optimize-quality-and-connection/app-size-optimization.mdx).

    In addition to using `npm` to install the Web SDK, you can also use the following methods:

    * In the project HTML file, add the following tag to obtain the SDK from CDN:

      ```html
      <script src="https://download.agora.io/sdk/release/AgoraRTC_N-4.24.5.js"></script>
      ```

    * Download the Video SDK package locally, save the `.js` files in the SDK package to the project directory, and then add the following tag to the project HTML file:

      ```html
      <script src="./AgoraRTC_N-4.24.5.js"></script>
      ```

    Visit the [Download](/en/api-reference/sdks?product=video\&platform=web) page to obtain the link for the latest SDK version.

    ### Frequently asked questions [#frequently-asked-questions-2]

    **Why do I get a `digital envelope routines::unsupported` error when running the quickstart project locally?**

    This issue arises in projects configured with `webpack` for local execution due to changes in Node.js 16 and above. The modifications in Node.js, particularly its dependency on OpenSSL (detailed in the [node issue](https://github.com/nodejs/node/issues/29817)), impact the local development environment dependencies of the project. Refer to the [webpack issue](https://github.com/webpack/webpack/issues/14532) for details.

    Use one of the following solutions to resolve the issue:

    * Run the following command to set a temporary environment variable (Recommended):

      ```bash
      export NODE_OPTIONS=--openssl-legacy-provider
      ```

    * Temporarily switch to a lower version of Node.js.

    ### See also [#see-also-3]

    * [Error codes](/en/realtime-media/video/reference/error-codes)

    * [Connection status management](build/optimize-quality-and-connection/connection-status-management.mdx)

    
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
