1. Ably FAQs
  2. Channels
  3. Subscribing and publishing

Subscription filters

Subscribe to a channel using a filter in order to only receive messages that satisfy a filter expression.

When subscribing to a channel without a filter, published messages are immediately sent to clients as soon as they attach(), as long as they have subscribe capabilities for that channel. The advantage of subscription filters is that they apply server-side filtering to messages, meaning that a client will only ever be sent the messages they subscribe to.

Be aware that subscription filters have an additional channel and message cost:

  • Every unique subscription filter counts as an additional channel.
  • Each message published will count an additional time for each unique subscription filter it satisfies. A message that does not pass the filter will not be charged for.

Normal limits still apply when using subscription filters. As such, it is not recommended to publish all data to a single channel and rely solely on subscription filters. A level of partitioning at the channel level is still required for the majority of use cases.

Development status

Subscription filters are currently in preview. Fill in this form to request access to them.

Create a filter expression

Filter expressions should be written using JMESPath. They can be constructed using the message name and message.extras.headers fields.

message.extras.headers optionally provides ancillary metadata to a message, as Ably can’t inspect message payloads themselves. Adding suitable key-value pairs to messages will enable more complicated filter expressions to be constructed resulting in more effective message filtering.

The following is an example of publishing a message with additional metadata:


    name: 'ice-cream',

    data: '...',

    extras: {

        headers: {

            flavor: "strawberry",

            cost: 35,

            temp: 3




Be aware that message.extras.headers must be a flat object. It can’t contain any further nesting or arrays.

The following is an example of a filter expression subscribing to messages with the name “ice-cream”, a flavor of “strawberry” and a cost of less than 50:

name == `"ice-cream"` && headers.flavor == `"strawberry"` && headers.cost < `50`

The following is an example of a filter expression subscribing to messages with a flavor of either “strawberry” or “chocolate”:

headers.flavor == `"strawberry"` || headers.flavor == `"chocolate"`

Subscribe with a filter

In order to use a subscription filter, a qualifier called filter must be added to the channel name when calling get() to create or retrieve a channel instance. The qualifier should appear in square brackets before the channel name, for example [filter=]my-channel-name. The filter expression must be base64 encoded. 

The following is an example of subscribing to a channel using an example filter:




Clients that are publishing to the same channel that they are subscribed to using a filter need to call get() twice. Once using the filter expression qualifier for the subscription filter and once without a qualifier for publishing. Attempts to publish to a channel created or retrieved using a filter qualifier will fail.

The following example demonstrates publishing to a channel, but subscribing to only a subset of messages on it:

// Connect to Ably

const realtime = new Ably.Realtime({ '<API-KEY>' });

// Create a channel instance to publish to

const pubChannel = realtime.channels.get('scoops-kiosk');

// Create a channel instance using the filter qualifier

const subChannel = realtime.channels.get(

  `[filter=${btoa('name == `"ice-cream"` && headers.flavor == `"strawberry"` && headers.cost < `50`')}]scoops-kiosk`


// Subscribe to the channel using the filtered subscription

subChannel.subscribe((message) => {

   alert('Ice cream update: ' + message.data);


// Publish to the unfiltered channel instance


   name: 'ice-cream',

   data: '...',

   extras: {

       headers: {

           flavor: "strawberry",

           cost: 35,

           temp: 3




In Node.JS you will need to convert to base64 using Buffer.from(...).toString('base64') instead of using btoa().


Clients require the subscribe capability for one of the following resources in order to receive messages from a subscription filter:

  • [filter]<channel name>  
  • [*]<channel name>  
  • [*]*

It is important to set the correct capabilities for clients that will be carrying out additional operations on the same channel they are subscribed to using a filter. If clients have the subscribe capability for the channel itself and attach to it, such as when entering the presence set, they will be streamed all messages.

The following is an example of a request for a token with only the subscribe capability for the subscription filter, and only the publish capability for the unfiltered channel. This avoids the client from being streamed all messages, even if they attach to the unfiltered channel:

auth.requestToken({ capability: {

"[filter]scoops-kiosk": ["subscribe"],

"scoops-kiosk": ["publish"]

}}, tokenCallback);


There are several limitations to be aware of when using subscription filters, versus subscribing to a channel without a filter. The following features are not supported: