Update call participants’ displayed names with the Daily API

We’re noticing a pretty popular trend here at Daily: people are joining more and more calls online with people they haven’t met yet, attending webinars, joining audio communities, and other new virtual experiences.  

A common feature request from developers building these platforms is a way for participants to enter and display their names.

We shipped setUserName() to make this easier to implement. While before you could create a meeting token to add or update a participant’s name (and you still can!), you can now give call participants the ability to input or change their own names via setUserName().

This method updates the participant’s user_name property on the Daily participants object. In the Daily prebuilt UI, this automatically changes the built-in name overlay. When building on top of the Daily call object, the updated information can be retrieved from .participants() and rendered however suits your custom video or audio call UI.

Let’s have a look at both use cases.

Change a participant’s displayed name in the Daily prebuilt UI

Gif of video call screen where the other participant has camera off and their name changes from Kimberlee to Kim-bear-emoji-lee
setUserName() lets a participant change their name depending on the meeting.

In addition to text chat, local video and participant bar toggling, screen share, and many more configurable out-of-the-box features, the Daily prebuilt UI includes a name overlay on top of a participant’s video stream.

If you have a three-syllable-or-longer name like I do, you might often get asked, "Do you prefer [name] or [nickname]?" For me, it depends on my mood and context. On work calls I go by Kimberlee, but on catch ups with friends I might prefer Kimee or Kim🐻lee.

To give participants the ability to change the username that other participants see, you’ll need to provide an input field along with a button outside the Daily callframe. That could something look like:

<!-- Rest of your HTML here -->

 <label for="name-change"></label>
 <input
    type="text"
    id="name-change"
    placeholder="Enter your new name"
 />
 <button onclick="changeLocalParticipantName()">Change name</button>

<!-- Rest of your HTML here -->

Where changeLocalParticipantName() passes the input value to callFrame.setUserName():

function changeLocalParticipantName() {
  const nameChange = document.getElementById('name-change');
  callFrame.setUserName(nameChange.value);
}

To set the participant name for only this meeting, like to change my name to "Kimberlee" only on work-related calls, we could also pass an optional object argument with thisMeetingOnly set to true, for example:

callFrame.setUserName(nameChange.value, {thisMeetingOnly: true});

That’s how to update participant names with setUserName() in the prebuilt UI. Now, let's look at how to do the same in a custom UI built on the Daily call object.

Call setUserName() with the Daily call object to update a custom call UI

Screenshot of audio community app with square representing speaker named Bort and menu to make moderator, make listener, or remove from call
In our Party Line demo audio app, we use setUserName() to organize participants by role in the UI.

In our Party Line demo audio app, we created a few different roles for call participants: listeners, speakers, and moderators.  

To avoid building and maintaining a separate backend for the demo, we worked up a fast solution to manage those roles via setUserName(). In production applications, you’ll want to build your own system to persist this kind of data, but if you’re just looking to test or prototype quickly, this workaround might be useful (read on!).

The person who creates the call is automatically a moderator, with the power to "promote" listeners to speakers, and speakers to moderators. When a moderator promotes a participant, sendAppMessage() notifies the promotee with a direct message.

const changeAccountType = useCallback(
    (participant, accountType) => {
      if (!participant || ![MOD, SPEAKER, LISTENER].includes(accountType))
        return;
 
      const msg =
        accountType === MOD
          ? MSG_MAKE_MODERATOR
          : accountType === SPEAKER
          ? MSG_MAKE_SPEAKER
          : MSG_MAKE_LISTENER;

      callFrame.sendAppMessage(
        { userName, id: participant?.user_id, msg },
        participant?.session_id
      );
    },
    [getAccountType, displayName, handleMute, callFrame]
  );
Head over to our party-line repository if you’re curious about what messages we stored in those constants and for the full codebase (we’re stripping out some fun, but not directly relevant, things in a few of these snippets).

Then, we call setUsername() to add the updated participant’s new role to the end of their name. This updates the participant’s user_name on the Daily participants object, and fires a corresponding participant-updated event. Other call participants can then pick up on the change, and the UI can update accordingly in each client.

const updateUsername = useCallback(
    (newAccountType) => {
      if (![MOD, SPEAKER, LISTENER].includes(newAccountType)) return;
      /**
       * In case the user had their hand raised, let's make
       * sure to remove that emoji before updating the account type.
       */
      const split = callFrame?.participants()?.local?.user_name.split("✋ ");
      const handRemoved = split.length === 2 ? split[1] : split[0];

      const display = displayName(handRemoved);
      /**
       * The display name is what the participant provided on sign up.
       * We append the account type to their user name so to update
       * the account type we can update the last few letters.
       */
      callFrame.setUserName(`${display}_${newAccountType}`);
    },
    [callFrame]
  );

You might notice in the snippet above that we do two things before we make that setUserName() call.

First, we check for a raised hand.

A participant can raise their hand as a listener to indicate that they’d like to be made a speaker. Our raiseHand() function also calls setUserName(), adding a  "✋" in front of the participant’s name.

const raiseHand = useCallback(
    (p) => {
      if (!callFrame) return;
      callFrame.setUserName(`✋ ${p?.user_name}`);
      setUpdateParticipants(`raising-hand-${p?.user_id}-${Date.now()}`);
    },
    [callFrame]
 );

Lowering a hand works much the same way:

const lowerHand = useCallback(
    (p) => {
      if (!callFrame) return;
      const split = p?.user_name.split("✋ ");
      const username = split.length === 2 ? split[1] : split[0];
      callFrame.setUserName(username);
    },
    [callFrame]
 );

Back in updateUserName() we check to see if a participant has their hand raised before we do anything else. If they do, we remove the hand from their username, because we don’t need to display their name once they’ve been "promoted."

Once we’ve got the ✋-less name, we pass it to our displayName() function. displayName() strips away the participant role from the rendered name.

const displayName = (username) => {
  if (!username) return;
    // return name without account type
    return username.slice(0, username.length - 4);
  };

We don’t need to display the participant’s role after their name; we just need this information to be stored on participants[id].user_name so that the UI can group participants in the correct place (We do that with some fun filtering in InCall.js using the exported getAccountType(). Head to our repository to explore the full codebase).

We already said this, but it’s worth repeating: this is a workaround for quick prototyping! In production, you’ll want to use a more comprehensive solution to enforce the roles.

What’s next?

There are so many ways to experiment with setUserName(). I’m hoping somebody builds a virtual Mafia-style game that updates players’ names. Please let us know if you’re building something fun, and if we can help with anything along the way!






Never miss a story

Get the latest direct to your inbox.