Please be aware that you are viewing our bleeding edge unstable documentation. Unless you wanted to view the bleeding edge (and possibly unstable) documentation, we recommend you use our stable docs.

Go to Ably's stable canonical documentation »

I know what I'm doing, let me see the bleeding edge docs »

You are viewing our bleeding edge unstable documentation. We recommend you use our stable documentation »
Fork me on GitHub

Subscribing to Channel Occupancy Events

Ably Realtime’s Data Stream Network organizes all of the message traffic within its applications into named channels. Channels are the “unit” of message distribution; clients attach to any number of channels to publish or subscribe to messages. Every message published to a channel is broadcasted to all subscribers.

Many times, developers find it helpful to be aware of specific metadata related to their channels. This metadata can be accessed using our Channel Metadata API. This API allows you to subscribe to the channel lifecycle events and channel occupancy events or send one off REST requests to the Channel Status API to query channel enumeration, i.e., listing all the active channels associated with a particular API key in an app or to query the status and occupancy data associated with the channel. In this tutorial, we’ll see how to subscribe to the channel occupancy events.

Channel occupancy reveals the number and type of occupants of a particular channel. This includes the number of connections, publishers, subscribers, presence members, and presence subscribers. When you subscribe to the occupancy events via the realtime library, you’ll receive updates whenever the occupancy changes, in other words, the count of one of these parameters changes. However, you can still send out a one-off REST request via our REST library, to get the then occupancy data for the channel in question. This is part of the Channel Status API

Receiving realtime updates relating to Channel occupancy events is available only to our Enterprise customers via our Realtime client libraries. However, all users can use the Channel Status API to retrieve this data from the metachannels via REST requests whenever they need. Get in touch with our sales team to get set up with an enterprise account.

Step 1 – Set up a free account with Ably

In order to run these tutorials locally, you will need an Ably API key. If you are not already signed up, you should sign up now for a free Ably account. Once you have an Ably account:

  1. Log into your app dashboard
  2. Under “Your apps”, click on “Manage app” for any app you wish to use for this tutorial, or create a new one with the “Create New App” button
  3. Click on the “API Keys” tab
  4. Copy the secret “API Key” value from your Root key and store it so that you can use it later in this tutorial

    Copy API Key screenshot

Step 2 – Setting the right permissions on your API key

In order to be able to use the occupancy data that is offered as part of the Channel Lifecycle API, you’ll need to attach to a special channel called ‘[meta]channel.lifecycle’. This channel, in essence, is similar to any other channel that you would use to share data within Ably’s Data Stream Network; however, it’s kept on a different namespace to easily separate concerns. All of the metadata, including channel lifecycle events and occupancy events, will be sent on this channel.

You’ll need to ensure that the Channel Metadata permission is enabled on your API key. Permissions (or privileges or capabilities, used interchangeably) restrict your API key from being used to performing specific actions only, such as publish-and-subscribe or publish-only, etc. These privileges can be set on your API key via your account dashboard. Navigate to the ‘API Keys’ tab of your dashboard as shown in the image below and click on the ‘settings’ button against an existing API key that you’d like to use or create a new one.

A regular Ably API key has a capability which lists resources (glob expressions that match channel names) and, for any given resource, a set of permitted operations. The wildcard resource '*' will match any regular channel name.

In order to grant permission in a key to a channel, however, the resource name(s) in the capability must include the [meta] qualifier explicitly; so the following are examples of capabilities that will validly permit access to a metachannel:

{"[meta]*":["*"], "*":["*"]}

Channel metadata permissions

Under normal circumstances you won’t be granted permission to publish to, or be present in metachannels.

Step 3 – Creating a basic HTML page to display the results

Since we’ll be using JavaScript in this tutorial, the best way to display the results, is in a browser. So, go ahead and paste the following simple HTML in a file and name it index.html


    <title>Channel Occupancy Events</title>
    <script src="" crossorigin="anonymous"></script>

<body style="padding: 60px; font-family:Arial, Helvetica, sans-serif; text-align: center;">
    Ably Channel Occupancy Events - Demo
    <div style="text-align: center; padding: 10px;">
        <button style="padding: 5px; width: 150px" id="add-publisher-instance" onclick="addPublisherInstance()">Add publisher instance</button>
        <button style="padding: 5px; width: 150px" id="add-subscriber-instance" onclick="addSubscriberInstance()">Add subscriber instance</button>
    <div style="text-align: center; padding: 10px;">
        <button style="padding: 5px; width: 150px" id="add-publisher-instance-presence" onclick="addPublisherInstanceWithPresence()">Add publisher instance and enter presence</button>
        <button style="padding: 5px; width: 150px" id="add-subscriber-instance-presence" onclick="addSubscriberInstanceWithPresence()">Add subscriber instance and enter presence</button>
        <textarea id="result" rows="30" style="width: 100%; margin-top: 10px; font-family: courier, courier new; background-color: #333; color: orange;  overflow-y: scroll;"
    <script src="main.js"></script>


The key thing to note in the HTML above is the inclusion of two JS files, one is the Ably Library, referenced via the CDN, while the other is the main.js file which will include our logic, we’ll work on this next. We have also added a text area to display our results in.

See this step in Github

Step 4 – Subscribing to Occupancy events using Ably’s Realtime Library

For the simplicity of this tutorial, we’ll use Basic authentication in our realtime client. However, it is highly recommended to use Token auth on client-side applications for better security and protection of your API key.

Let’s begin with instantiating the Ably Realtime client library using the API key. Create a new file called main.js and add the following to it.

var apiKey = '<YOUR-API-KEY>';
var ably = new Ably.Realtime({
    key: apiKey

Next, let’s instance the metachannel using the realtime client that we instanced above and also reference the text area we added in the HTML, to display results in.

var metaChannel = ably.channels.get("[meta]channel.lifecycle");
var resultArea = document.getElementById("result");
resultArea.scrollTop = resultArea.scrollHeight;

The next step would be to subscribe to the channel occupancy events. This event is triggered on the [meta]channel.lifecycle that we instanced above and bears the name ‘channel.occupancy’. We can display the results returned in the callback in the text area in our HTML.

metaChannel.subscribe('channel.occupancy', (msg) => {
    var msgJSONobj = JSON.parse(JSON.stringify(;
    //extract occupancy data from the message returned in the callback
    var occupancyMetrics = msgJSONobj.status.occupancy.metrics
    if (occupancyMetrics && !'[meta]')) {
        resultArea.value += ('\n\n[METADATA - ' + (new Date().toLocaleTimeString()) + ' ]: Occupancy on channel "' + + '" has been updated. New data is as follows:\n')
        resultArea.value += ('Connections: ' + occupancyMetrics.connections + ' \n')
        resultArea.value += ('Publishers: ' + occupancyMetrics.publishers + ' \n')
        resultArea.value += ('Subscribers: ' + occupancyMetrics.subscribers + ' \n')
        resultArea.value += ('Presence Connections: ' + occupancyMetrics.presenceConnections + ' \n')
        resultArea.value += ('Presence Members: ' + occupancyMetrics.presenceMembers + ' \n')
        resultArea.value += ('Presence Subscribers: ' + occupancyMetrics.presenceSubscribers + ' \n')
        resultArea.scrollTop = resultArea.scrollHeight;

Remember to replace the text ‘’ with an actual Ably API key.

In the above code, we have subscribed to the ‘channel.occupancy’ events on the metachannel containing the channel lifecycle information. Then, we have displayed the data returned in the text area. Simple as that!

See this step in Github

Step 5 – Add button functionality

Now that we have the backend code running, it’s time to make our buttons work! Add the following code to your main.js file:

function addPublisherInstance() {
    resultArea.value += ('\n[LOCAL LOG - ' + (new Date().toLocaleTimeString()) + ' ]: Adding new publisher instance\n')
    var myKey = '<YOUR-API-KEY>'
    var ably = new Ably.Realtime({
        key: myKey
    var regularChannel = ably.channels.get("regular-channel")
    console.log('adding publisher instance')
    regularChannel.publish('test-data', {
        data: "Dummy Data",

function addSubscriberInstance() {
    resultArea.value += ('\n[LOCAL LOG - ' + (new Date().toLocaleTimeString()) + ' ]: Adding new subscriber instance\n')
    var myKey = '<YOUR-API-KEY>'
    var ably = new Ably.Realtime({
        key: myKey
    var regularChannel = ably.channels.get("regular-channel")
    console.log('adding subscriber instance')
    regularChannel.subscribe('test-data', (data) => {
        //do whatever
        console.log('Subscription working')

function enterPresence() {
    resultArea.value += ('\n[LOCAL LOG - ' + (new Date().toLocaleTimeString()) + ' ]: Entering presence\n')
    var ably = new Ably.Realtime({
        key: apiKey
    var regularChannel = ably.channels.get("regular-channel")

function leavePresence() {
    resultArea.value += ('\n[LOCAL LOG - ' + (new Date().toLocaleTimeString()) + ' ]: Leaving presence\n')
    var ably = new Ably.Realtime({
        key: apiKey
    var regularChannel = ably.channels.get("regular-channel")

See this step in Github

Step 6 – Live Demo

For the live demo, we’ll manually add new occupants through button clicks, so that we can see the ‘channel.occupancy’ events live in action.

Ably Channel Occupancy Events – Demo

See the full code in GitHub

Next Steps

1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime channels & messages documentation.
2. If you would like to check out the other related tutorials to work with channel metadata, see the Channel Lifecycle Events and Channel Enumeration tutorials.
3. Learn more about Ably features by stepping through our other Ably tutorials
4. Gain a good technical overview of how the Ably realtime platform works
5. Get in touch if you need help

Back to top