JavaScript

Metachannels

Metachannels are a namespace of channels beginning with the [meta] qualifier. This separates them from regular channels. An example of a metachannel is [meta]channel.lifecycle or [meta]clientEvents:connections.

There are a number of metachannels available:

[meta]log
This metachannel broadcasts error messages that you would not otherwise have any way of receiving (with the exception of errors delivering push notifications, see below). For example, if Ably receives an error response when delivering a webhook to your endpoint, Ably sends a message on the log metachannel with information about the error. Errors where the client can be directly notified are not sent on the log metachannel. For example, if a client attempts to publish a message but exceeds a channel rate limit, the client can be notified by an error callback passed to publish.
[meta]log:push
This metachannel is similar to [meta]log, but only for errors that happen during delivery of push notifications.
[meta]channel.lifecycle
This metachannel publishes messages about channel lifecycle.
[meta]connection.lifecycle
This metachannel publishes messages about the lifecycle of realtime connections.
[meta]clientEvents:connections
This metachannel publishes metadata for a sample of connection events.
[meta]clientEvents:apiRequests
This metachannel publishes metadata for a sample of API request events.
[meta]stats:minute
This metachannel publishes app statistics.

To subscribe to a metachannel you require an Ably key or token that has suitable capabilities. The resource name or names in the capability must include the [meta] qualifier explicitly.

If you are using an API key, you can set the key’s capabilities in the Ably dashboard. If you are using tokens, you specify capabilities within the token.

The following shows an example of a capability allowing subscription to all metachannels:

{<a href="[">[meta]*</a>"subscribe"]}
Copied!

The above capability allows for the token to subscribe to any meta channel. The wildcard * indicates anything can follow the [meta] claim, so an example of a valid channel would be [meta]log. However, this capability does not allow for any other actions to be performed on the metachannels, nor does it allow the token to do anything with any non-metachannels.

The following shows an example of a capability allowing all permissible actions on all metachannels and all regular channels:

{ <a href="[">[meta]*</a>"*"], "*":["*"] }
Copied!

The above permission provides two capabilities; the ability to perform any action on any metachannel, such as [meta]log with <a href="[">[meta]*</a>"*"], and the ability to perform any action on any channel such as another:channel with "*":["*"].

However, you are never able to publish or be present in a metachannel, so this permission results in an effective permission that excludes publish and presence capabilities in [meta] channels. This is due to the intersecting capabilities.

If [meta] is not specified in the permissions, you will be unable to access the metachannels. An example of this is the following:

{ "*":["*"] }
Copied!

Although the above provides all capabilities in all regular channels, without a [meta] permission being explicitly specified, you will be unable to perform any actions on a metachannel.

To provide all capabilities on all metachannel and channels you can use the following:

{ "[*]*":["*"] }
Copied!

These wildcard rules are summarized here:

  • * as a resource name matches all regular channels, but not metachannels.
  • To match both regular channels and metachannels you can use [*]*.
  • To match all metachannels and no regular channels you can use [meta]*.
  • To match just a single metachannel you can use, for example, [meta]channel.lifecycle.

For further information on capabilities, please refer to the following resources:

The following events are published as messages on the [meta]channel.lifecycle channel. In all cases, the data member of the message is a ChannelDetails instance.

channel.opened
indicates that the channel has been activated globally; that is, it has become active in at least one region, having previously been inactive. The embedded ChannelDetails.status includes occupancy globally.
channel.closed
indicates that the channel has been deactivated globally.
channel.region.active
indicates that the channel has been activated in a specific region. The included ChannelDetails.status includes occupancy in that region.
channel.region.inactive
indicates that the channel has been deactivated in a specific region. The included ChannelDetails.status includes occupancy in that region.

The following code snippet shows how to subscribe to channel.closed channel lifecycle events:

const channel = ably.channels.get('[meta]channel.lifecycle'); channel.subscribe('channel.closed', (msg) => { console.log('lifecycle meta channel (closed): ', msg.data); });
Copied!

The following code snippet shows how to subscribe to all channel lifecycle events:

const channel = ably.channels.get('[meta]channel.lifecycle'); channel.subscribe((msg) => { console.log('Event type: ' + msg.name, msg.data); });
Copied!

The Ably system collects usage statistics on a per-app basis and exposes them via the REST API as described in the statistics documentation.

These app statistics are also published every minute to a metachannel named [meta]stats:minute, with each message being formatted according to the app-stats JSON schema.

You can subscribe to the stats metachannel with the following example code:

const channel = ably.channels.get("[meta]stats:minute"); channel.subscribe("update", event => { console.log(JSON.stringify(event, undefined, 2)); });
Copied!

This code subscribes to update events on the stats metachannel. The update events are published every minute and contain the statistics for only the past minute. No other events are supported in this metachannel at this time.

An example of the event received is shown here:

{ "name": "update", "id": "trVvT-KeEw:0:0", "encoding": null, "data": { "intervalId": "2021-10-07:16:23", "unit": "minute", "schema": "https://schemas.ably.com/json/app-stats-0.0.1.json", "entries": { "connections.all.peak": 1, "connections.all.min": 1, "connections.all.mean": 0.2, "connections.all.opened": 2, "apiRequests.all.succeeded": 2, "apiRequests.tokenRequests.succeeded": 2 } } }
Copied!

Where:

name
The update event. No other events are currently supported.
id
The unique ID of the event.
encoding
Encoding of the event data.
intervalId
This is an indication of the date/time interval that this stats record relates to.
unit
Currently only per-minute stats are supported.
schema
The JSON schema used for the encoding of the event.
entries
This is a flattened representation of the categories for which there are non-zero entries for this stats record.

It is possible to stream these values directly to the console by connecting and subscribing using Server-Sent Events (SSE)

curl -s -u "<loading API key, please wait>" "https://realtime.ably.io/sse?channel=[meta]stats:minute&v=1.2"
Demo Only
Copied!

This would return stats events in the following format:

id: [email protected] event: message data: {"id":"MVphZHA7l9:0:0","timestamp":1633679346026,"encoding":"json","channel":"[meta]stats:minute","data":"{\<a href="\">intervalId\</a>"2021-10-08:07:48\",\<a href="\">unit\</a>"minute\",\<a href="\">schema\</a>"https://schemas.ably.com/json/app-stats-0.0.1.json\",\"entries\":{\"messages.all.all.count\":1,\"messages.all.messages.count\":1,\"messages.outbound.realtime.all.count\":1,\"messages.outbound.realtime.messages.count\":1,\"messages.outbound.all.all.count\":1,\"messages.outbound.all.messages.count\":1,\"connections.all.peak\":2,\"connections.all.min\":1,\"connections.all.mean\":1,\"connections.all.opened\":1}}","name":"update"}
Copied!

As there could potentially be a delay of up to one minute before the first stat event, you can obtain the most recent stat, followed by subsequent events, by using the rewind option. For the Curl command, add the rewind=1 query parameter:

curl -s -u "<loading API key, please wait>" "https://realtime.ably.io/sse?channel=[meta]stats:minute&v=1.2&rewind=1"
Demo Only
Copied!

For the client library SDK example you can use the rewind channel parameter

const channel = ably.channels.get("[meta]stats:minute", {params: {rewind: '1'}});
Copied!

You can also use the History API to obtain stats from this metachannel, as shown in the following example:

curl -s -u "<loading API key, please wait>" "https://rest.ably.io/channels/[meta]stats:minute/messages?limit=1"
Demo Only
Copied!

This retrieves the most recent event.

Sampled connection and request events can be used to monitor the usage of Ably services. Events are published to metachannels that contain metadata for a sample of connections and API requests. These events can be used to compile statistics on app usage, enabling you to perform arbitrary data processing and aggregation related to client population and client activity.

Note that this is an Enterprise-only feature and must be enabled for each app you would like to sample. Please contact us to enable this functionality.

Events are published on the metachannels [meta]clientEvents:connections and [meta]clientEvents:apiRequests.

The following code snippet shows how to subscribe to connection.opened events:

const channel = ably.channels.get('[meta]clientEvents:connections'); channel.subscribe('connection.opened', (msg) => { console.log('connection opened: ', msg.data); });
Copied!

The following code snippet shows how to subscribe to all sampled API request events:

const channel = ably.channels.get('[meta]clientEvents:apiRequests'); // To subscribe to all event types channel.subscribe((msg) => { console.log('Event type: ' + msg.name, msg.data); });
Copied!

The rate of sampling dictates the number of events published to the metachannels. For example, a rate of 0.1% for connections would publish an average of 1 message in every 1000. The sample rate can be configured independently for connections and API requests within the same app.

Sampled connection events for an app are published to the channel [meta]clientEvents:connections. Connection events can be used to compile statistics relating to client population.

The connection event types are:

connection.opened
The connection was successfully made by the client to Ably.
connection.closed
The connection was explicitly closed by the client.
connection.refused
The connection was rejected for an expected reason, such as invalid credentials or a malformed request.
connection.failed
The connection was rejected for an unexpected reason, such as a network failure.

Events contain a subset of the following metadata in the data field:

host
The host the connection was made to.Type: String
requestId
The unique ID of the request that Ably can use to correlate a connection event with internal logs, if necessary.Type: String
region
The region the connection was made from.Type: String
headers
The headers sent with the connection.Type: JSON Object
query
The parsed query string of the connection request, excluding authentication parameters. It contains connection information such as the client library version and any custom transport parameters.Type: JSON Object
connectionId
The unique ID of the connection.Type: String
clientId
The ID of the client that attempted the connection.Type: String
channels
A list of channels included in the request. This is only relevant where channels are supported as part of the connection request, such as with SSE. Type: Array
duration
The duration the connection was open for.Type: Integer
error
The details of any error encountered whilst making the connection request. It includes an error message, error code and HTTP status code.Type: JSON Object

An example of a connection.closed event is:

{ "host": "realtime.ably.io", "requestId": "fbbcb0ab-fa56-47c4-bbd4-fccc22a271b8", "region": "us-east-1", "headers": { "host": "realtime.ably.io", ... }, "query": { "format": "json", "heartbeats": "true", "v": "1.2", "lib": "js-web-1.2.9" }, "connectionId": "54321", "clientId": "12345", "duration": 61151 }
Copied!

Sampled API request events for an app are published to the channel [meta]clientEvents:apiRequests. API request events can be used to compile statistics relating to client activity.

The request event types are:

request.succeeded
The request was successful.
request.refused
The request was rejected for an expected reason, such as a malformed request or insufficient privileges.
request.failed
The request was rejected for an unexpected reason, such as a network failure.

Events contain a subset of the following metadata in the data field:

host
The host the request was made to.Type: String
requestId
The unique ID of the request that Ably can use to correlate a request event with internal logs, if necessary.Type: String
region
The region the request was made in.Type: String
headers
The headers sent with the request.Type: JSON Object
query
The details of the parsed request query, including information such as the request format.Type: JSON Object
path
The path of the endpoint called in the request, for example /channels/{channel-name}/messages.Type: String
channels
A list of channels the request was made against.Type: Array
error
The details of any error encountered whilst making the request. It includes an error message, error code and HTTP status code.Type: JSON Object

An example of a request.succeeded event is:

{ "host": "rest.ably.io", "requestId": "fbbcb0ab-fa56-47c4-bbd4-fccc22a271c9", "region": "us-east-2", "headers": { "host": "rest.ably.io", ... }, "query": { "format": "json" }, "path": "/channels/example-channel/messages", "channels": [ "my-test-channel" ] }
Copied!