2. Create a Streaming Web App

Getting Started by Using the Web SDK

In Part 1 we reviewed how-to log into your Dolby.io Streaming Dashboard, create a publish token, start a broadcast, and playback that broadcast in the hosted web viewer or in an iframe, all without writing any code. We'll continue getting started by substituting the broadcast and playback components with a custom-built web application.

This tutorial is split into three sections:

2.0 Embed the streaming viewer in an iFrame

In Part 1 - Using the Streaming Dashboard, you may have noticed the Hosted Viewer iFrame. You can copy and paste the <iframe> directly into your own web application and replace the streamId and streamName with your own.


This is the simplest way to get up and running quickly with your own web application. This works well for long-running streams or one-time live events.

If you click the Customize button in the Playback Dashboard you'll see there are lots of options you can use to include or exclude playback behaviors. The How to Broadcast in Dashboard page goes through these options in more detail.

2.1 Playback from a custom web application

In the previous part, we were able to begin to broadcast a stream and playback that stream in a hosted web viewer application. For more complex projects, you may need more control over the end-user experience. To demonstrate this, we'll build a custom web application to playback and view the stream using the same publish token created from the dashboard.

a. Clone the Getting Started repository

Clone the repository: dolbyio-samples/stream-sdk-web-getting-started.

git clone https://github.com/dolbyio-samples/stream-sdk-web-getting-started.git
cd stream-sdk-web-getting-started/playback-app

This starter project includes a folder for the playback-app. The folder includes the scaffolding of a not-yet-functional single-page web application. This application is using Bootstrap to add basic layout and functional behaviors. Bootstrap is not a requirement, you can use other libraries that may fit your particular application needs and preferences. What's important is that we've added buttons, which we can assign behavior to as we continue.

View the app locally

There are many ways you can view static HTML in a web browser.

a) You can open the file directly from your operating system with a file:// path in your browser.

b) You can use a development web server like those available in python3 or node if you have them installed to view the app in your browser.

npx live-server
python3 -m http.server
open index.html

You'll be editing a single index.html file to add streaming capabilities so you may need to refresh the application as you make changes in each step that follows.

b. Include the Web SDK

To dynamically generate a viewer you should use the Web SDK in your application. You can do this by adding a <script> element in the <head> section to include the SDK from a hosted location such as a CDN.

<!-- Step 2.1b: Include Millicast Web SDK -->
<script src="https://cdn.jsdelivr.net/npm/@millicast/sdk/dist/millicast.umd.min.js"></script>


Using the Millicast SDK

Review the Web SDK documentation for additional installation methods such as with npm. The Streaming API used to be known as Millicast so the SDK uses that name when importing the library.

c. Configure account ID and stream name

In Part 1 we created a stream with a unique name such as myStreamName. You'll need to add that to the code along with the Account ID that is associated with the publishing token. You can find both of these values from the Dolby.io Dashboard.

// Step 2.1c: Set your account id and stream name while Getting Started
const yourStreamAccountId = 'ENTER ACCOUNT ID';
const yourStreamName = 'ENTER YOUR STREAM NAME';

// Callback to generate a subscriber token with credentials
const tokenGenerator = () => millicast.Director.getSubscriber({
      streamName: yourStreamName,
      streamAccountId: yourStreamAccountId

d. Attach a view

The View class is used to manage the WebRTC connection with the server that is distributing the real-time stream. The streaming-video-placeholder is the id of a <video> element within the application.

// Step 2.1d: Attach a millicast view to the placeholder node
const videoNode = document.getElementById('streaming-video-placeholder');
const millicastView = new millicast.View(yourStreamName, tokenGenerator);
millicastView.on('track', (event) => {
    console.log('Stream has started.');
    videoNode.srcObject = event.streams[0];
    videoNode.hidden = false;
    videoNode.autoplay = true;

e. Connect to the stream

The connect method can take a few different options which you can learn more about in the reference documentation.

// Step 2.1e: Start connection to a publishing stream
try {
    await millicastView.connect();
} catch (e) {
    if (!millicastView.isActive()) {
        console.log('Stream is not live, the broadcast will begin soon.');

    console.log('Connection failed:', e);

If you start broadcasting using the Dolby.io Dashboard as you did in Part 1, you will then have a simple web app with video playback to continue customizing.

2.2 Broadcast from a custom web application

For this section, you can use the hosted playback viewer or the playback-app you just built in the last section. This section will help you build a separate app that would be used to Capture and broadcast streaming content.

a. Clone the Getting Started repository

Clone the repository dolbyio-samples/stream-sdk-web-getting-started as described in the first section but this time we'll be working the with broadcast-app folder. You can view the app locally using the same tools described in the previous section.

git clone https://github.com/dolbyio-samples/stream-sdk-web-getting-started.git
cd stream-sdk-web-getting-started/broadcast-app

The Web SDK is pulled in with a <script> element from a CDN in the same way as is done for the playback-app.

b. Configure publishing token and stream name

You'll need to retrieve the Publishing Token from the Dolby.io dashboard that corresponds with the streamName used in the playback-app section.

// Step 2.2b: Set your account id and stream name while Getting Started
const yourPublishingToken = 'ENTER PUBLISHING TOKEN';
const yourStreamAccountId = 'ENTER ACCOUNT ID';
const yourStreamName = 'ENTER YOUR STREAM NAME';

const tokenGenerator = () => millicast.Director.getPublisher({
    token: yourPublishingToken, 
    streamName: yourStreamName,

// Callback to generate a publisher token with credentials
const publisher = new millicast.Publish(yourStreamName, tokenGenerator)

c. Attach media stream to broadcast

The getUserMedia() function is used to capture an incoming media stream from the user's camera and microphone. To verify that this is working, we provide a mirror of the audio and video in a video element. This is happening locally within the web browser.

To begin broadcasting, we must connect() the publisher to the mediaStream.

// Step 2.2c: Attach a millicast view to the placeholder node
const startStreaming = async () => {
    // Request access to the video camera and microphone
    const mediaStream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true

    // Provide mirror in a video element of the capture
    const videoNode = document.getElementById('streaming-video-placeholder');
    videoNode.srcObject = mediaStream;
    videoNode.hidden = false;
    videoNode.autoplay = true;

    // Broadcast captured audio and video
    const broadcastOptions = {
        mediaStream: mediaStream,
    try {
        await publisher.connect(broadcastOptions);
        console.log('Broadcast has begun.');

        // Example to playback with the hosted viewer
        const viewerUrl = `https://viewer.millicast.com?streamId=${yourStreamAccountId}/${yourStreamName}`;
        document.getElementById('viewer-url').innerHTML = `<a href="${viewerUrl}" target="_new">${viewerUrl}</a>`;
    } catch (e) {
        console.error('Failed to begin broadcast', e);

// Handle button click to begin
document.getElementById('btn-start').onclick = async () => {
    await startStreaming();

The viewerUrl provides a convenient link to the hosted playback viewer so that you can verify the broadcast is working.

d. Stop the broadcast

For a good end-user experience, you will want to stop() publishing when the broadcast is complete.

// Step 2.2d: Stop the broadcast
document.getElementById('btn-stop').onclick = () => {

Continue learning

These starter apps were kept simple for the purpose of getting started. You can re-use these samples in your preferred JavaScript framework such as React, VueJS, Angular, etc. as you customize the user experience of joining a stream, handling when a stream hasn't started, maintaining button state, etc.

Continue by exploring the Streaming Web SDK documentation for a guide on other functions as you continue building your own project.


400 (Bad Request)

When you try to connect to a stream that has not yet begun to broadcast, you may see a 400 (Bad Request) error. This is expected, so you will want to create a user experience that does not attempt to connect() prematurely, by first checking if a broadcast has begun.

POST https://director.millicast.com/api/director/subscribe 400 (Bad Request)