Cloudflare Workers

As part of Webhooks, it is possible to integrate with various systems.

Cloudflare Workers allow you to make use of Cloudflare’s Edge Network to distribute your normal JavaScript-based functions.

If you would like to just dive in and see an example of this being implemented, then take a look at our Cloudflare Worker tutorial.

For more details on the specifics of how webhooks and our integrations work, check out our Webhooks documentation.

URL
The URL of your Cloudflare Worker
Custom headers
Optionally allows you to provide a set of headers that will be included in all HTTP POST requests. You must use format "XCustom-Header-1:value1" for each header you add
Source
Choose which of channel.message, channel.presence, channel.lifecycle, or channel.occupancy events on channels should activate this event rule.
Request Mode
This will either be in Single Request mode or Batch Request mode. Single Request will send each event separately to the endpoint specified by the rule. Batch Request will send events triggered concurrently in the same request
Channel filter
An optional filter on channel name, to restrict the channels the rule applies to. Use a regular expression to match multiple channels.
Encoding
The encoding to be used by this rule. This can be either JSON or MsgPack

If the rule is in the Single Request mode, it will also have the following options:

Enveloped
If the rule has the Enveloped option set, then data delivered by this rule will be wrapped in an Ably envelope. Otherwise, the rule will send the raw payload

If the rule is in the Batch Request mode, it will have the following additional options:

Sign with key
Ably will optionally sign the data with the specified private key. This will be included as an HTTP header X-Ably-Signature in every HTTP post request issued to your server. See webhook security for more details.

Given the various potential combinations of enveloped, batched and message sources, it can be good to know what to expect given certain combinations of rules.

Batched events will have the following headers:

content-type
the type of the payload. This will be application/json or application/x-msgpack
x-ably-version
the version of the Webhook. At present this should be 1.2

Each batched message will have the following fields:

name
the event type, for example presence.message, channel.message or channel.closed
webhookId
an internal unique ID for the configured webhook
source
the source for the webhook, which will be one of channel.message, channel.presence, channel.lifecycle, or channel.occupancy
timestamp
a timestamp represented as milliseconds since the epoch for the presence event
data
an object containing the data of the event defined below in JSONPath format

For message events, data will contain:

data.channelId
name of the channel that the presence event belongs to
data.site
an internal site identifier indicating which primary datacenter the member is present in
data.messages
an Array of raw messages

The following is an example of a batched message payload:

{ "items": [{ "webhookId": "ABcDEf", "source": "channel.message", "serial": "a7bcdEFghIjklm123456789:4", "timestamp": 1562124922426, "name": "channel.message", "data": { "channelId": "chat-channel-4", "site": "eu-west-1-A", "messages": [{ "id": "ABcDefgHIj:1:0", "clientId": "user-3", "connectionId": "ABcDefgHIj", "timestamp": 1123145678900, "data": "the message data", "name": "a message name" }] } }] }
Copied!

Messages sent over the realtime service are automatically decoded into Message objects by the Ably client library. With webhooks you need to to do this explicitly, using Message.fromEncodedArray on the data.messages array, or Message.fromEncoded on an individual member of that array. This will transform them into an array of Message objects (or in the case of fromEncoded, an individual Message). This has several advantages, e.g.:

  • It will fully decode any data (using the encoding) back into the same datatype that it was sent in (or an equivalent in each client library’s language)
  • If you are using encryption, you can pass your encryption key to the method and it will decrypt the data for you

We recommend you do this for all messages you receive over webhooks. For example (using ably-js):

Select...
webhookMessage.items.forEach((item) => { const messages = Ably.Realtime.Message.fromEncodedArray(item.data.messages); messages.forEach((message) => { console.log(message.toString()); }) })
Copied!

For presence events, data will contain:

data.channelId
name of the channel that the presence event belongs to
data.site
an internal site identifier indicating which primary datacenter the member is present in
data.presence
an Array of raw presence messages

The following is an example of a batched presence payload:

{ "items": [{ "webhookId": "ABcDEf", "source": "channel.presence", "serial": "a7bcdEFghIjklm123456789:4", "timestamp": 1562124922426, "name": "presence.message", "data": { "channelId": "education-channel", "site": "eu-west-1-A", "presence": [{ "id": "ABcDefgHIj:1:0", "clientId": "bob", "connectionId": "ABcDefgHIj", "timestamp": 1123145678900, "data": "the message data", "action": 4 }] } }] }
Copied!

Presence messages sent over the realtime service are automatically decoded into PresenceMessage objects by the Ably client library. With webhooks you need to to do this explicitly, using PresenceMessage.fromEncodedArray on the data.presence array, or PresenceMessage.fromEncoded on an individual member of that array. This will transform them into an array of PresenceMessage objects (or in the case of fromEncoded, an individual PresenceMessage). This has several advantages, e.g.:

  • It will decode the (numerical) action into a Presence action string (such as enter update or leave
  • It will fully decode any data (using the encoding) back into the same datatype that it was sent in (or an equivalent in each client library’s language)
  • If you are using encryption, you can pass your encryption key to the method and it will decrypt the data for you

We recommend you do this for all presence messages you receive over webhooks. For example (using ably-js):

Select...
webhookMessage.items.forEach((item) => { const messages = Ably.Realtime.PresenceMessage.fromEncodedArray(item.data.messages); messages.forEach((message) => { console.log(message.toString()); }) })
Copied!

For channel lifecycle events, data will contain:

data.channelId
name of the channel that the presence event belongs to
data.status
a ChannelStatus object

The name of a channel.lifecycle event will be channel.opened or channel.closed.

The following is an example of a batched channel lifecycle payload:

{ "items": [{ "webhookId": "ABcDEf", "source": "channel.lifecycle", "timestamp": 1562124922426, "serial": "a7bcdEFghIjklm123456789:4", "name": "channel.opened", "data": { "channelId": "chat-channel-5", "name": "chat-channel-5", "status": { "isActive": true, "occupancy": { "metrics": { "connections": 1, "publishers": 1, "subscribers": 1, "presenceConnections": 1, "presenceMembers": 0, "presenceSubscribers": 1 } } } } }] }
Copied!

Enveloped events will have the following headers:

x-ably-version
the version of the Webhook. At present this should be 1.2
content-type
the type of the payload. This will be application/json or application/x-msgpack for enveloped messages

Each enveloped message will have the following fields:

source
the source for the webhook, which will be one of channel.message, channel.presence, channel.lifecycle, or channel.occupancy
appId
the Ably app this message came from
channel
the Ably channel where the event occurred
site
the Ably datacenter which sent the message
timestamp
a timestamp represented as milliseconds since the epoch for the presence event

In addition, it will contain another field which will contain the actual message, which is named according to the message type.

For message events, the messages array contains a raw message.

The following is an example of an enveloped message payload:

{ "source": "channel.message", "appId": "aBCdEf", "channel": "channel-name", "site": "eu-central-1-A", "ruleId": "1-a2Bc", "messages": [{ "id": "ABcDefgHIj:1:0", "connectionId": "ABcDefgHIj", "timestamp": 1123145678900, "data": "some message data", "name": "my message name" }] }
Copied!

Messages sent over the realtime service are automatically decoded into Message objects by the Ably client library. With webhooks you need to to do this explicitly, using Message.fromEncodedArray on the messages array, or Message.fromEncoded on an individual member of that array. This will transform them into an array of Message objects (or in the case of fromEncoded, an individual Message). This has several advantages, e.g.:

  • It will fully decode any data (using the encoding) back into the same datatype that it was sent in (or an equivalent in each client library’s language)
  • If you are using encryption, you can pass your encryption key to the method and it will decrypt the data for you

We recommend you do this for all messages you receive over webhooks. For example (using ably-js):

Select...
const messages = Ably.Realtime.Message.fromEncodedArray(item.messages); messages.forEach((message) => { console.log(message.toString()); })
Copied!

For presence events, the presence array contains a raw presence message.

The following is an example of of an enveloped message payload with a presence array:

{ "source": "channel.message", "appId": "aBCdEf", "channel": "channel-name", "site": "eu-central-1-A", "ruleId": "1-a2Bc", "presence": [{ "id": "abCdEFgHIJ:1:0", "clientId": "bob", "connectionId": "Ab1CDE2FGh", "timestamp": 1582270137276, "data": "some data in the presence object", "action": 4 }] }
Copied!

Presence messages sent over the realtime service are automatically decoded into PresenceMessage objects by the Ably client library. With webhooks you need to to do this explicitly, using PresenceMessage.fromEncodedArray on the presence array, or PresenceMessage.fromEncoded on an individual member of that array. This will transform them into an array of PresenceMessage objects (or in the case of fromEncoded, an individual PresenceMessage). This has several advantages, e.g.:

  • It will decode the (numerical) action into a Presence action string (such as enter update or leave
  • It will fully decode any data (using the encoding) back into the same datatype that it was sent in (or an equivalent in each client library’s language)
  • If you are using encryption, you can pass your encryption key to the method and it will decrypt the data for you

We recommend you do this for all presence messages you receive over webhooks. For example (using ably-js):

Select...
const messages = Ably.Realtime.PresenceMessage.fromEncodedArray(item.messages); messages.forEach((message) => { console.log(message.toString()); })
Copied!

Non-enveloped events have quite a few headers, in order to provide context to the data sent in the payload. These are:

content-type
the type of the payload. This can be either application/json, text/plain, or application/octet-stream, depending on if it’s JSON, text, or binary respectively
x-ably-version
the version of the Webhook. At present this should be 1.2
x-ably-envelope-appid
the app ID which the message came from
x-ably-envelope-channel
the Ably channel which the message came from
x-ably-envelope-rule-id
the Ably rule ID which was activated to send this message
x-ably-envelope-site
the Ably datacenter which sent the message
x-ably-envelope-source
the source for the webhook, which will be one of channel.message, channel.presence, channel.lifecycle, or channel.occupancy
x-ably-message-client-id
the client ID of the connection which sent the event
x-ably-message-connection-id
the connection ID responsible for the initial event
x-ably-message-id
the message’s unique ID
x-ably-message-timestamp
the time the message was originally sent

For message events, there will be the additional headers:

x-ably-message-name
The name of the Message

The payload will contain the data of the Message.

For example, if you sent the following curl message, which sends a JSON message to the channel my_channel:

curl -X POST https://rest.ably.io/channels/my_channel/messages \ -u "<loading API key, please wait>" \ -H "Content-Type: application/json" \ --data '{ "name": "publish", "data": "example" }'
Demo Only
Copied!

The x-ably-message-name header would be publish, and the payload would be example.

For Presence events, there will be the additional headers:

x-ably-message-action
the action performed by the event (update, enter, leave)

The payload will contain the data of the Presence message.

For example, if a client enters a channel’s presence with the following code:

Select...
realtime = new Ably.Realtime({ key: '<loading API key, please wait>', clientId: 'bob' }); channel = realtime.channels.get('some_channel'); await channel.presence.enter('some data');
Demo Only
Copied!

Then the x-ably-message-action would be enter, the x-ably-message-client-id would be “bob”, and the payload would be “some data”.

Tutorials & Examples