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.
Tutorials & Examples
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.
Rule fields
- 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
, orchannel.occupancy
events on channels should activate this event rule. - Request Mode
- This will either be in
Single Request
mode orBatch 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.
Examples
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 event payloads
Batched events will have the following headers:
- content-type
- the type of the payload. This will be
application/json
orapplication/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
orchannel.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
, orchannel.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
Batched message events
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"
}]
}
}]
}
CopyCopied!
Decoding batched messages
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 theencoding
) 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):
webhookMessage.items.forEach((item) => {
const messages = Ably.Realtime.Message.fromEncodedArray(item.data.messages);
messages.forEach((message) => {
console.log(message.toString());
})
})
CopyCopied!
Batched presence events
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
}]
}
}]
}
CopyCopied!
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 asenter
update
orleave
- It will fully decode any
data
(using theencoding
) 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):
webhookMessage.items.forEach((item) => {
const messages = Ably.Realtime.PresenceMessage.fromEncodedArray(item.data.messages);
messages.forEach((message) => {
console.log(message.toString());
})
})
CopyCopied!
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
}
}
}
}
}]
}
CopyCopied!
Enveloped event payloads
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
orapplication/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
, orchannel.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.
Enveloped message events
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"
}]
}
CopyCopied!
Decoding enveloped messages
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 theencoding
) 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):
const messages = Ably.Realtime.Message.fromEncodedArray(item.messages);
messages.forEach((message) => {
console.log(message.toString());
})
CopyCopied!
Enveloped presence events
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
}]
}
CopyCopied!
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 asenter
update
orleave
- It will fully decode any
data
(using theencoding
) 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):
const messages = Ably.Realtime.PresenceMessage.fromEncodedArray(item.messages);
messages.forEach((message) => {
console.log(message.toString());
})
CopyCopied!
Non-enveloped event payloads
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
, orapplication/octet-stream
, depending on if it’sJSON
,text
, orbinary
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
, orchannel.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
Non-enveloped message events
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 OnlyCopyCopied!
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:
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 OnlyCopyCopied!
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”.