All Products
Search
Document Center

ApsaraVideo Live:Get started with the Alibaba Cloud ARTC Web SDK

Last Updated:Dec 01, 2025

The Alibaba Cloud ARTC Web SDK is a development kit for web-based real-time communication. It allows developers to quickly add high-quality audio and video calls, real-time messaging, and other interactive features to their web applications. This topic describes how to build your first ARTC application.

Step 1: Create an application

  1. Log on to the ApsaraVideo Live console.

  2. In the navigation pane on the left, click Live + > ApsaraVideo Real-time Communication > Applications.

  3. Click Create Application.

  4. Enter a custom Instance Name, select the Terms of Service checkbox, and then click Purchase Now.

  5. After a success message appears, refresh the Application Management page to view your new ApsaraVideo Real-time Communication application.

    Note

    Creating an application is free. You are charged on a pay-as-you-go basis for your actual usage. For more information, see ApsaraVideo Real-time Communication pricing.

Step 2: Get the App ID and AppKey

After you create the application, find it in the application list. In the Actions column, click Manage to go to the Basic Information page. On this page, you can find the Application ID and AppKey.

image

Step 3: Integrate the SDK

  1. Integrate the SDK.

    Integrate using a script tag

    In your HTML page, import the SDK script.

    <script src="https://g.alicdn.com/apsara-media-box/imp-web-rtc/7.1.9/aliyun-rtc-sdk.js"></script>

    Integrate using npm

    In your project, install the SDK using npm.

    npm install aliyun-rtc-sdk --save
  2. Initialize the engine.

    // Choose one of the following two import methods.
    // Use this import statement if you are using the npm package.
    import AliRtcEngine from 'aliyun-rtc-sdk';
    // Use this import statement if you are using a script tag.
    const AliRtcEngine = window.AliRtcEngine;
    
    // Check the environment.
    const checkResult = await AliRtcEngine.isSupported();
    if (!checkResult.support) {
      // The current environment is not supported. Prompt the user to switch to or upgrade their browser.
    }
    
    // Create an engine instance. You can save it as a global variable.
    const aliRtcEngine = AliRtcEngine.getInstance();
    
  3. After you create the AliRtcEngine instance, listen for and handle related events.

    // The current user leaves the channel.
    aliRtcEngine.on('bye', (code) => {
      // The code parameter indicates the reason. For more information, see the API reference.
      console.log(`bye, code=${code}`);
      // Add your business logic here, such as exiting the call page.
    });
    
    // Listen for remote users coming online.
    aliRtcEngine.on('remoteUserOnLineNotify', (userId, elapsed) => {
      console.log(`User ${userId} joined the channel in ${elapsed} seconds`);
      // Add your business logic here, such as displaying the module for this user.
    });
    
    // Listen for remote users going offline.
    aliRtcEngine.on('remoteUserOffLineNotify', (userId, reason) => {
      // The reason parameter indicates the reason. For more information, see the API reference.
      console.log(`User ${userId} left the channel. Reason code: ${reason}`);
      // Add your business logic here, such as destroying the module for this user.
    });
    
    // Listen for changes in remote stream subscription.
    aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
      // The oldState and newState parameters are of the AliRtcSubscribeState type. Valid values: 0 (Init), 1 (Unsubscribed), 2 (Subscribing), and 3 (Subscribed).
      // The interval parameter indicates the time interval between the two states in milliseconds.
      console.log(`The subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}`);
      // Add the logic to watch the remote stream here.
      // When newState becomes 3, you can call setRemoteViewConfig to play the remote stream.
      // When newState becomes 1, you can stop the playback.
    });
    
    // Listen for authentication information expiration.
    aliRtcEngine.on('authInfoExpired', () => {
      // This callback is triggered when the authentication information expires.
      // You need to obtain a new token and other data, and then call the refreshAuthInfo operation to update the authentication data.
      aliRtcEngine.refreshAuthInfo({
        userId,
        token,
        timestamp
      });
    });
    
    // Listen for when user authentication information is about to expire.
    aliRtcEngine.on('authInfoWillExpire', () => {
      // This callback is triggered 30 seconds before the authentication information expires. Update the authentication information promptly after you receive this callback.
      // If you want to stay in the session, obtain a new token and other data, and then call joinChannel to rejoin the channel.
    });
    
  4. (Optional) Set the channel mode. The default mode is call mode. For more information, see Set the channel mode and user role.

    // Set the channel mode. Valid string values: communication (call mode) and interactive_live (interactive mode).
    aliRtcEngine.setChannelProfile('interactive_live');
    // Set the user role. This setting takes effect only in interactive mode.
    // Valid string values: interactive (interactive role, allows stream ingest and pulling) and live (viewer role, only allows stream pulling).
    aliRtcEngine.setClientRole('interactive');
  5. Join a channel. For information about how to calculate a token, see Token-based authentication. You can choose to join a channel with a single parameter or multiple parameters as needed.

    • Join with a single parameter

      const userName = 'TestUser1'; // You can change this to your username. Chinese characters are supported.
      
      try {
        // You need to implement fetchToken to get the Base64Token from the server.
        const base64Token = await fetchToken();
        await aliRtcEngine.joinChannel(base64Token, userName);
        // Joined the channel successfully. You can perform other operations.
      } catch (error) {
        // Failed to join the channel.
      }
    • Join with multiple parameters

      // For more information, see the Token-based authentication topic. Generate authentication information from the server or locally.
      // Note: For data security, do not release the token calculation logic that includes the appKey to users under any circumstances.
      const appId = 'yourAppId'; // Get this from the console.
      const appKey = 'yourAppKey'; // Get this from the console. Note: Do not expose your AppKey in a production environment.
      const channelId = 'AliRtcDemo'; // You can change this to your channel ID. Only letters and digits are supported.
      const userId = 'test1'; // You can change this to your user ID. Only letters and digits are supported.
      const userName = 'TestUser1'; // You can change this to your username. Chinese characters are supported.
      const timestamp = Math.floor(Date.now() / 1000) + 3600; // Expires in one hour.
      
      try {
        const token = await generateToken(appId, appKey, channelId, userId, timestamp);
        // Join the channel. Parameters such as token and nonce are usually returned by the server.
        // Note: When you call this operation, make sure that the channelId, userId, appId, and timestamp parameters are the same as those used to generate the token.
        await aliRtcEngine.joinChannel({
          channelId,
          userId,
          appId,
          token,
          timestamp,
        }, userName);
        // Joined the channel successfully. You can perform other operations.
      } catch (error) {
        // Failed to join the channel.
      }
  6. Preview and ingest the stream. By default, after you join a channel, local audio and video data is automatically captured and pushed to the Alibaba Cloud Global Real-time Transport Network (GRTN). You can preview your local video feed as follows.

    1. In the HTML code, add a VIDEO element with its id set to localPreviewer.

      <video
        id="localPreviewer"
        muted
        style="display: block;width: 320px;height: 180px;background-color: black;"
      ></video>
    2. Call the setLocalViewConfig method and pass the element ID to start the preview.

      // The first parameter can be an HTMLVideoElement or its element ID. Pass null to stop the preview.
      // The second parameter can be 1 (preview camera stream) or 2 (preview screen sharing stream).
      aliRtcEngine.setLocalViewConfig('localPreviewer', 1);
  7. Subscribe to remote audio and video streams. By default, after you join a channel, you are automatically subscribed to the audio and video streams of other streamers. Audio streams play automatically. To watch a camera or screen stream, you must call the setRemoteViewConfig operation to enable it.

    1. In the HTML code, add a DIV element with its id set to remoteVideoContainer to serve as a container.

      <div id="remoteVideoContainer"></div>
    2. After you receive an event about a remote video stream subscription change, call the setRemoteViewConfig operation to play the stream if it is subscribed to. If the stream is unsubscribed, remove it.

      // Store the Video element.
      const remoteVideoElMap = {};
      // The remote container element.
      const remoteVideoContainer = document.querySelector('#remoteVideoContainer');
      
      function removeRemoteVideo(userId) {
        const el = remoteVideoElMap[userId];
        if (el) {
          aliRtcEngine.setRemoteViewConfig(null, userId, 1);
          el.pause();
          remoteVideoContainer.removeChild(el);
          delete remoteVideoElMap[userId];
        }
      }
      
      // This is the same as the videoSubscribeStateChanged example in the "Listen for events" step.
      aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
        // The oldState and newState parameters are of the AliRtcSubscribeState type. Valid values: 0 (Init), 1 (Unsubscribed), 2 (Subscribing), and 3 (Subscribed).
        // The interval parameter indicates the time interval between the two states in milliseconds.
        console.log(`The subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}`);
        // Example
        if (newState === 3) {
          const video = document.createElement('video');
          video.autoplay = true;
          video.setAttribute('style', 'display: block;width: 320px;height: 180px;background-color: black;');
          remoteVideoElMap[userId] = video;
          remoteVideoContainer.appendChild(video);
          // The first parameter is an HTMLVideoElement.
          // The second parameter is the remote user ID.
          // The third parameter can be 1 (preview camera stream) or 2 (preview screen sharing stream).
          aliRtcEngine.setRemoteViewConfig(video, userId, 1);
        } else if (newState === 1) {
          removeRemoteVideo(userId);
        }
      });
  8. End the process.

    // Stop the local preview.
    await aliRtcEngine.stopPreview();
    // Leave the channel.
    await aliRtcEngine.leaveChannel();
    // Destroy the instance.
    aliRtcEngine.destroy();

Quick demo

Important

The JavaScript part of the quick demo code includes the generateToken method for calculating a token. For security reasons, do not expose this code or your AppKey in a client-side JavaScript file. This can lead to information leaks and security vulnerabilities. We recommend that you generate tokens on your server and retrieve them on the frontend by making an authenticated API call.

Prerequisites

To run the quick demo, you need to start an HTTP service in your development environment. If you have not installed the http-server npm package, run the npm install --global http-server command to install it globally.

Step 1: Create a directory

Create a demo folder and then create the quick.html and quick.js files with the following directory structure.

- demo
  - quick.html
  - quick.js

Step 2: Edit quick.html

Copy the following code into quick.html and save the file.

Sample code

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>aliyun-rtc-sdk quick start</title>
    <link rel="stylesheet" href="https://g.alicdn.com/code/lib/bootstrap/5.3.0/css/bootstrap.min.css" />
    <style>
      .video {
        display: inline-block;
        width: 320px;
        height: 180px;
        margin-right: 8px;
        margin-bottom: 8px;
        background-color: black;
      }
    </style>
  </head>
  <body class="container p-2">
    <h1>aliyun-rtc-sdk quick start</h1>

    <div class="toast-container position-fixed top-0 end-0 p-3">
      <div id="loginToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-header">
          Logon MessageUser OnlineUser Offline

Step 3: Edit quick.js

Copy the following code into quick.js, and paste your App ID and AppKey into the specified variables in the code. Then, save the file.

Sample code

function hex(buffer) {
  const hexCodes = [];
  const view = new DataView(buffer);
  for (let i = 0; i < view.byteLength; i += 4) {
    const value = view.getUint32(i);
    const stringValue = value.toString(16);
    const padding = '00000000';
    const paddedValue = (padding + stringValue).slice(-padding.length);
    hexCodes.push(paddedValue);
  }
  return hexCodes.join('');
}
async function generateToken(appId, appKey, channelId, userId, timestamp) {
  const encoder = new TextEncoder();
  const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`);

  const hash = await crypto.subtle.digest('SHA-256', data);
  return hex(hash);
}

function showToast(baseId, message) {
  $(`#${baseId}Body`).text(message);
  const toast = new bootstrap.Toast($(`#${baseId}`));

  toast.show();
}

// Enter your App ID and AppKey.
const appId = '';
const appKey = '';
AliRtcEngine.setLogLevel(0);
let aliRtcEngine;
const remoteVideoElMap = {};
const remoteVideoContainer = document.querySelector('#remoteVideoContainer');

function removeRemoteVideo(userId, type = 'camera') {
  const vid = `${type}_${userId}`;
  const el = remoteVideoElMap[vid];
  if (el) {
    aliRtcEngine.setRemoteViewConfig(null, userId, type === 'camera' ? 1: 2);
    el.pause();
    remoteVideoContainer.removeChild(el);
    delete remoteVideoElMap[vid];
  }
}

function listenEvents() {
  if (!aliRtcEngine) {
    return;
  }
  // Listen for remote users coming online.
  aliRtcEngine.on('remoteUserOnLineNotify', (userId, elapsed) => {
    console.log(`User ${userId} joined the channel in ${elapsed} seconds`);
    // Add your business logic here, such as displaying the module for this user.
    showToast('onlineToast', `User ${userId} is online`);
  });

  // Listen for remote users going offline.
  aliRtcEngine.on('remoteUserOffLineNotify', (userId, reason) => {
    // The reason parameter indicates the reason. For more information, see the API reference.
    console.log(`User ${userId} left the channel. Reason code: ${reason}`);
    // Add your business logic here, such as destroying the module for this user.
    showToast('offlineToast', `User ${userId} is offline`);
    removeRemoteVideo(userId, 'camera');
    removeRemoteVideo(userId, 'screen');
  });

  aliRtcEngine.on('bye', code => {
    // The code parameter indicates the reason. For more information, see the API reference.
    console.log(`bye, code=${code}`);
    // Add your business logic here, such as exiting the call page.
    showToast('loginToast', `You have left the channel. Reason code: ${code}`);
  });

  aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
    // The oldState and newState parameters are of the AliRtcSubscribeState type. Valid values: 0 (Init), 1 (Unsubscribed), 2 (Subscribing), and 3 (Subscribed).
    // The interval parameter indicates the time interval between the two states in milliseconds.
    console.log(`The subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}`);
    const vid = `camera_${userId}`;
    // Example
    if (newState === 3) {
      const video = document.createElement('video');
      video.autoplay = true;
      video.className = 'video';
      remoteVideoElMap[vid] = video;
      remoteVideoContainer.appendChild(video);
      // The first parameter is an HTMLVideoElement.
      // The second parameter is the remote user ID.
      // The third parameter can be 1 (preview camera stream) or 2 (preview screen sharing stream).
      aliRtcEngine.setRemoteViewConfig(video, userId, 1);
    } else if (newState === 1) {
      removeRemoteVideo(userId, 'camera');
    }
  });

  aliRtcEngine.on('screenShareSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
    // The oldState and newState parameters are of the AliRtcSubscribeState type. Valid values: 0 (Init), 1 (Unsubscribed), 2 (Subscribing), and 3 (Subscribed).
    // The interval parameter indicates the time interval between the two states in milliseconds.
    console.log(`The subscription state of the screen stream from remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}`);
    const vid = `screen_${userId}`;
    // Example    
    if (newState === 3) {
      const video = document.createElement('video');
      video.autoplay = true;
      video.className = 'video';
      remoteVideoElMap[vid] = video;
      remoteVideoContainer.appendChild(video);
      // The first parameter is an HTMLVideoElement.
      // The second parameter is the remote user ID.
      // The third parameter can be 1 (preview camera stream) or 2 (preview screen sharing stream).
      aliRtcEngine.setRemoteViewConfig(video, userId, 2);
    } else if (newState === 1) {
      removeRemoteVideo(userId, 'screen');
    }
  });
}

$('#loginForm').submit(async e => {
  // Prevent the default form submission action.
  e.preventDefault();
  const channelId = $('#channelId').val();
  const userId = $('#userId').val();
  const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3;

  if (!channelId || !userId) {
    showToast('loginToast', 'Incomplete data');
    return;
  }

  aliRtcEngine = AliRtcEngine.getInstance();
  listenEvents();

  try {
    const token = await generateToken(appId, appKey, channelId, userId, timestamp);
    // Set the channel mode. Valid string values: communication (call mode) and interactive_live (interactive mode).
    aliRtcEngine.setChannelProfile('communication');
    // Set the user role. This setting takes effect only in interactive mode.
    // Valid string values: interactive (interactive role, allows stream ingest and pulling) and live (viewer role, only allows stream pulling).
    // aliRtcEngine.setClientRole('interactive');
    // Join the channel. Parameters such as token and nonce are usually returned by the server.
    await aliRtcEngine.joinChannel(
      {
        channelId,
        userId,
        appId,
        token,
        timestamp,
      },
      userId
    );
    showToast('loginToast', 'Joined the channel successfully');
    $('#joinBtn').prop('disabled', true);
    $('#leaveBtn').prop('disabled', false);

    // Preview
    aliRtcEngine.setLocalViewConfig('localPreviewer', 1);
  } catch (error) {
    console.log('Failed to join the channel', error);
    showToast('loginToast', 'Failed to join the channel');
  }
});

$('#leaveBtn').click(async () => {
  Object.keys(remoteVideoElMap).forEach(vid => {
    const arr = vid.split('_');
    removeRemoteVideo(arr[1], arr[0]);
  });
  // Stop the local preview.
  await aliRtcEngine.stopPreview();
  // Leave the channel.
  await aliRtcEngine.leaveChannel();
  // Destroy the instance.
  aliRtcEngine.destroy();
  aliRtcEngine = undefined;
  $('#joinBtn').prop('disabled', false);
  $('#leaveBtn').prop('disabled', true);
  showToast('loginToast', 'Left the channel');
});

Step 4: Run the demo

  1. In the terminal, go to the demo folder and run http-server -p 8080 to start an HTTP service.

  2. Open a new tab in your browser and go to localhost:8080/quick.html. On the page, enter a Channel ID and a User ID, and then click Join Channel.

  3. Open another new tab in your browser and go to localhost:8080/quick.html. On the page, enter the same channel ID as in the previous step and a different user ID, and then click Join Channel.

  4. The media stream from the other user is automatically subscribed to and appears on the page.