Overview
Daily’s client SDK for JavaScript is calleddaily-js. The daily-js SDK can be used to build custom video or audio calling applications or embed and control Daily Prebuilt.
With this library you can:
- Initialize your call settings
- Join a room
- Manage call lifecycle and participant state
- Respond to in-call events
- Customize call layout and UI (Daily Prebuilt)
Installing daily-js
To use daily-js, you can load the library in a <script> tag or bundle with webpack and other tools.
Loading the library in a script tag
You can use this library from a<script> tag, as a CommonJS-style module with require, or as an ES6-style module with import (including within a <script type="module"> context).
The easiest way to get started is to load this library from unpkg, and add a couple of lines of code to your web page or app.
Bundling with webpack and other tools
Of course, you can also use a bundler like webpack or rollup.Getting started
This guide provides an overview of how to build a custom video or audio calling application usingdaily-js. For details on the methods and events mentioned in this guide, see the daily-js reference documentation.
If you prefer to jump right in, you can get the associated code and run the demo.

If you’re interested in learning how to use daily-js to control Daily Prebuilt, check out the Prebuilt guide for demos and sample code.
Prerequisites
Create a Daily account
Before you get started, you’ll need to sign up for your free Daily account. You get 10,000 free minutes every month, so you can try out Daily without any cost.Create a Daily room
Begin by navigating to Daily’s developer dashboard and creating a new Daily room. If you need guidance, you can follow the steps in our room creation guide. Once you’ve created your room, make note of the URL. You’ll be using that later.Create a call client
Daily’s call client is your main interface into Daily functionality. It’s the thing that your code will invoke to do anything: start a call, leave a call, listen for participants coming and going, get video and audio to play, etc. A call client can be created with:DailyCallManager class which is used to initialize the object, set up event listeners and handlers, manage tracks, and manage devices.
Set up event listeners
Before joining the room, we’ll continue initializing our application by setting up event listeners. In this app, we’re concerned with handling participant state changes, specifically regarding audio / video tracks and local camera / microphone permissions.daily-js follows the EventEmitter pattern to add event callbacks. To set up a listener, you can call on(). You can call off() to remove event callbacks. For example, you can call:
setupEventListeners() method:
'active-speaker-change'to indicate when the active speaker in the call changes'error'to handle any errors (in this case, we’ll just console log them)'joined-meeting'to set up any initial call state and UI- ”left-meeting” to reset the DOM and related call state and UI
'participant-joined'to update call state or UI when another participant joins'participant-left'to update call state or UI when another participant leaves'participant-updated'to update call state or UI when the any participant change occurs
daily-js emits in the reference docs.
Join a room
Now that the call client is set up and initialized, we’re ready to join a room. This can be done as follows:join() can take a number of different arguments to configure the client for the upcoming call. Refer to our reference documentation for more information.
In our getting started demo, we join a room with either a url only or a url andtoken property. You can modify the code to experiment with different properties to see how they affect the call.
By default, the call to
join() runs several operations automatically to make it easy to get started:- Calls
getUserMedia()and configures your camera devices for 720p 30fps video - Enables the camera and microphone
- Publishes camera and microphone tracks
- Subscribes to media from all remote participants
getUserMedia() call and publishing the camera video is deferred until the camera is enabled.daily-js offers complete flexibility for all of these items. To learn more, check out our guides, demos, blog, and reference docs.Can’t find what you’re looking for? Try the Ask AI feature on the bottom right of the docs page, post a question to our community, or contact us. We’re glad to help!Handle tracks
When the local client or remote participants join a room, performs an action like unmute their microphone, or leaves a call, media tracks may be started or stopped. Track state is contained withinparticipants().
You can listen for changes to tracks through participant events: 'participant-joined', 'participant-updated', and 'participant-left'.
For even more details on this topic, check out our blog post on handling media tracks.
In our getting started demo, there are two handlers for these three events:
handleParticipantJoinedOrUpdated()handles the'participant-joined'and'participant-updated'events. This method is responsible for creating HTML elements for the video track, attaching and playing tracks, destroying tracks, updating participant count, and updating device states.handleParticipantLeft()handles the'participant-left'event. This method is responsible for destroying the video and audio tracks and related UI elements when a participant leaves the call.
- When a participant joins, add HTML elements where their video will be placed once a track is available. For video apps, this step can be taken even if the participant keeps their camera off during the call as the visual elements give the user presence during a call.
- When a
persistentTrackis available, set the corresponding<audio>or<video>element’ssrcObjectto theMediaStreamTrackand play it. - For video tracks, based on the track’s state, show or hide the video element.
handleParticipantJoinedOrUpdated() works:
startOrUpdateTrack()is responsible for setting the target<video>element’ssrcObjectto theMediaStreamTrackand playing it. The three scenarios the logic accounts for are:
- The track is new, so a new
srcObjectneeds to be provided. - The track has updated, so the
srcObjectneeds to be updated to the newMediaStreamTrack. - The track is already attached, so take no action.
MediaStreamTrack is attached and that your code is not unnecessarily calling play(), which can result in a video flicker or audio blip.
updateVideoUi()is responsible for changing the visual appearance of the video track, like showing or hiding it. In the demo code, the video track is shown when it’splayableand hidden when it’soff,interrupted, orblocked. You can customize the UI as needed in your application. For example, if the video track isblocked, you may want to notify the user and provide them with recovery steps.
destroyTracks()is responsible for setting thesrcObjecttonulland removing the corresponding track from the DOM.destroyTracks()is called when there is no longer a persistentTrack available for a given track type. This can happen when the local user turns off their camera or when a screen share is stopped.
'participant-left' event is emitted. The demo application’s handler for this event is called handleParticipantLeft(). This handler is responsible for:
- Cleaning up the media tracks: To do this, the application reuses the
destroyTracks()method from above. - Removing related elements from the DOM: To do this, the application removes the participant’s video-container from the DOM.
Control local media devices
You can obtain the state for the local participant’s camera and microphone by calling thelocalVideo() and localAudio() methods, respectively. Separately, you can control the local client’s camera and microphone using the setLocalVideo() and setLocalAudio() methods. When a device’s state changes, a corresponding 'participant-updated' event is emitted. You can handle this event to make relevant changes to device controls in your UI.
In our getting started demo, there are camera and microphone buttons used to turn the devices on and off. There is also a text field indicating the state of the buttons. Here’s an example of how the demo app controls the devices and updates the UI:
- Controlling the camera, which is initiated by clicking the “Camera” button:
- Controlling the microphone, which is initiated by clicking the “Microphone” button:
- Updating the device UI, which is called by the
handleParticipantJoinedOrUpdated()handler:
Change selected local media devices
Usingdaily-js, you can build a device selector to allow users to select which camera and microphone device to use during the call.
To start, you can select which devices are available to the user with the enumerateDevices() method. This will return to you the videoinput, audioinput, and audiooutput devices available to the user.
You’ll also want to know which device, if any, the user has currently selected. For that, you can call the getInputDevices() method, which will return the currently selected camera, microphone, and speaker devices.
Lastly, you can use the setInputDevicesAsync() method to select an video or audio device to use.
In our getting started demo, we set up the device selector after receiving the 'joined-meeting' event, which indicates that the user is connected to the call. Here’s example code showing how this is done:
'available-devices-updated' event. This event will return devices using the same format as the enumerateDevices() method.
Leave a room
Once the meeting is finished, the client can leave the meeting room by callingleave(). When leaving, be sure to set srcObjects to null to release media resources.
After leaving a meeting, the call object can be reused to join() another meeting, if you’d like to maintain the state of the call object. Once you’ve finished with the call object, we recommend calling destroy() to free all resources associated with it. Want more info? See our blog post covering leave() and destroy() best practices.
In our getting started demo, when we call leave(), we also remove audio and video elements from the DOM and reset status fields. For example:
'left-meeting' event by destroying tracks and resetting the UI. That includes:
- Disabling the toggle camera and mic buttons
- Resetting the camera and mic selectors
- Updating the call state (e.g. participant count and active speaker information) in the UI
- Removing all video containers
Wrapping up
And with that, you have a basic video calling app! Hopefully this helps to jump start your development building video and audio calling apps with Daily.Demos
If you’re interested in seeing the demo code used in the getting started guide above, you can find it on GitHub. We have many other demos, tutorials, and blog posts available to help teach you how to usedaily-js. Here are some recommendations to get you started:
Custom application demos
- Build a call lobby to control meeting access
- Build a custom app with Daily’s React SDK
- Learn how build larger, more efficient calls using track subscriptions
- Build a spatial video and audio application
- Build an audio-only application