Skip to Main Content

What happens when a Contact Center agent has their headset plugged in but steps away from their computer and then receives a call? Or if the agent misses the browser notification that pops up at the bottom of their screen? Wouldn’t it be nice to enable an additional notification ringtone that plays through a different audio source like your computer’s speakers? If you are already utilizing a custom Contract Control Panel (CCP), the changes needed are minimal and don’t require altering how the CCP works. Read on to see how!


  1. You will need to have a Custom CCP script that can easily be made by following the instructions at
  2. Ensure your Custom CCP script is utilizing the Event Subscription method { ... });
  3. At least one new audio file that will be the secondary ringtone for your CCP. Since this will not affect the CCP, it can be any audio format and any length that is supported by your browser.

Adding an audio element

The first step is to add a new audio element to your HTML page. Something like below:


This will display the audio controls useful for testing and seeing the play in action, you can hide this afterwards. Change the file name on the “src” tag as needed, as well as the type of audio.

Check out for more information about the audio element.

Specifying Audio Output

To specify the audio output device, see the code example below:





In this example, we simply created an HTML button that calls changeAudioDevice() when clicked, looping through the list of audio devices and displaying the current selection on a “p” tag. The important part of this function is await audio.setSinkId(audioDevices[deviceOption].deviceId); This actually sets the audio output source for that audio element. There are many other ways you could implement this function so feel free to change how you cycle through the list and set the audio.

Below you can see a new audio output source after clicking “Set Audio Output” a few times.


CCP Integration

So we can now get an audio file on a page and select the output source. Integrating with the CCP at this point is simple, we just need to invoke the PlayNotificationAudio and StopNotificationAudio functions within a few functions from the Connect Streams API

Once you have Connect Streams API included and can display the CCP, you’ll need to add our audio notification functions to the Event Subscription method

The Connect Streams API has several methods that are invoked during several state changes with the CCP.



That’s all you need to do to implement this basic feature. OnEnded() is needed in case the agent misses the call, this function is called when the contact is destroyed and so it will stop the ringtone until the agent goes available again.

Next Steps

This is a simplified implementation of adding additional audio with a custom CCP and there is a lot more we could do to create a better experience for the agent. See below for a few ideas to get started with.

  • Toggle switch to enable/disable secondary notification ringtone.
  • Use a dropdown to select the desired audio output source instead of a button to loop through them.
  • Save audio output selection as a user configuration so it becomes the default when using the CCP.
  • Allow agent to upload ringtones to an S3 Bucket or other hosting service for custom, unique ringtones for each agent.
  • Use a variety of ringtones and set a different ringtone for known contact phone numbers so agent is aware of who is calling before accepting.


Audio not playing – If your audio file is not playing on an incoming call, check the developer tools in the browser. You may encounter “Uncaught (in promise) DOMException” when trying to play the audio file. There is a feature of browsers meant to prevent auto-playing audio and video in new tabs and pop-ups. The user must click or interact with the page first before the call to is invoked. Check out for more information. This could be solved by including a toggle for the notification sound forcing the agent to interact with the page first.

You can view the full source code used in this post at