Create dynamic meetings using track subscriptions
⚠️ Warning! This blog post is deprecated ⚠️
Please head to the track subscriptions docs (under the updateParticipant() method) to learn about using track subscriptions with the Daily call object.

Track subscriptions are NOT supported with Daily Prebuilt.


At we’re focused on making the experience of building video applications as developer-friendly as possible. That means creating easy to understand abstractions on top of underlying technologies such as WebRTC. That said, sometimes it’s helpful to allow more granular control of that underlying tech. Specifically, we want to make it easier for you to control various media tracks and who can see them at any given time.

Enter track subscriptions! Any participant can now “subscribe” to the tracks (microphone, camera, screenshare) of any other participant. This is useful for any case where it isn’t necessary for all participants to see or hear each other. It also saves on CPU cost since the browser only needs to decode tracks required by the client UI. Some potential applications include:

  • Randomized breakout sessions (without the need for another room)
  • Randomized audience samples for presenters
  • Introducing yourself to a group when you join

Let’s consider the suggested use case where the last person to join can introduce themselves.

Please join() the meeting, and say “Hello World”

We’ll use our pre-built UI, leveraging the participant-joined event, is_owner property, and setSubscribedTracks

The logic will be the following:

  • All participants will see (and hear) `owners`
  • All participants will see (and hear) the latest person who joined so they can say hello
  • All participants will see (and hear) no one else in the call

Getting Started

To get started make sure you have:

  • A copy of this gist
  • A room to use for testing [0]
  • A meeting token with `is_owner` set to `true` [1]

Copy the gist into the editor of your choice. At the top of the createRoom() function you should see INSERT_ROOM and INSERT_TOKEN. Replace those with the meeting room url and token mentioned above and save your changes.

Now if you open the HTML file in a browser you should see a working demo. One thing to note here is that clicking create a room does not actually create a room, it instead uses the room url that you added. We did this to ensure we had a way for everyone to enter the same room while using the additional controls in the demo.

Note: We recommend testing this out in incognito windows (or different simultaneous browsers) to make sure the meeting owner token is correctly detected (if you happen to be logged into your Daily account, it may consider you an owner without the token depending on your room settings). Also, since not all track subscriptions features are available in 1:1 calls, please test with three or more participants.

Getting back on track

First off we’re using the new daily-js constructor property subscribeToTracksAutomatically and setting it to false. This tells daily-js to start the call by subscribing to no other tracks which means you won’t immediately see or hear anyone. We’ll need to explicitly subscribe to tracks for them to be visible/audible in the meeting.

The easiest way to see this in action is to get a few participants in the meeting and try the subscribe and unsubscribe buttons. They use the new setSubscribeToTracksAutomatically() instance method. This allows you to toggle your track subscriptions for all participants while in a call. While this all or nothing approach has its uses, it may be more practical to selectively subscribe to a participant’s tracks.

You’ll notice in the callback for the joined-meeting event we’re calling subscribeToOwnerTracks(). Let’s have a look at that function and see what’s going on.

function subscribeToOwnerTracks() {
    const participants = callFrame.participants(); 
    let idsToBeSubscribed = [];  
    // add non local owners to to-be-subscribed list
    for (let id in participants) {
      let p = participants[id]
      if (p.owner === true && p.local === false) {

    // subscribe to list 
   idsToBeSubscribed.forEach((id) => {
          setSubscribedTracks: true

Here we’re getting a list of participants by calling the participants() instance method. We’re then iterating over that list and storing the IDs of (non-local) owners in the idsToBeSubscribed array. We are then iterating over this array and calling updateParticipant for each of the IDs and setting their setSubscribedTracks property to true. This tells daily-js to subscribe to all of this participant’s tracks. This is equivalent to:

setSubscribedTracks : { audio: true, video: true, screenVideo: true}

This allows you to selectively subscribe to a participant’s individual media tracks.

So we’ve covered how we’re subscribing to owner tracks. Finally, let’s take a look at how we’re subscribing to guest tracks as they join and then subsequently unsubscribing.

You say hello, I say goodbye

We start by adding a custom callback for the participant-joined event called, you guessed it, participantJoined.

callFrame.on('participant-joined', participantJoined)

function participantJoined(e) {
 // subscribe to latest participant
       setSubscribedTracks: true

   // unsubscribe from latest after 30 seconds if they aren't an owner
   if (!e.participant.owner) {
     setTimeout( () => {
           setSubscribedTracks: false
       }, 30000)

Just like before, we’re calling updateParticipant. In this case, it’s with the ID of the participant that just joined the call. Then, if this participant is not an owner, we call updateParticipant again after 30 seconds (via setTimeout) to unsubscribe, by setting setSubscribedTracks to false.


So with just a few new lines of code, we’ve added the ability to dynamically control who can see each other in a call. In this case, we’ve created a relatively easy way to make more engaging and dynamic large meetings.

Next steps

Here are a just a few thoughts on how to enhance what we’ve gone through today:

  • Build a fully custom UI using callObject mode
  • Allow an owner to control other participants’ subscriptions when someone needs to speak (audience questions perhaps!)
  • Create dynamic virtual breakout rooms

In future posts we’ll explore features like pagination and different host/guest views. Stay tuned!

[0] Try creating one using our new dashboard!

[1] See our article on room access control to learn more

Never miss a story

Get the latest direct to your inbox.