Skip to content

Commit de53456

Browse files
committed
Addresses message billing docs gap
1 parent 4009afd commit de53456

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/data/nav/platform.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ export default {
125125
link: '/docs/platform/pricing/billing',
126126
name: 'Billing',
127127
},
128+
{
129+
link: '/docs/platform/pricing/message-billing',
130+
name: 'Message billing',
131+
},
128132
{
129133
link: '/docs/platform/pricing/limits',
130134
name: 'Limits',
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
title: "Message billing"
3+
meta_description: "Understand how different Ably operations contribute to your message count, including persistence, presence, Chat SDK features, and cost optimization strategies."
4+
meta_keywords: "message billing, message counting, pricing, persistence billing, presence billing, chat billing, cost optimization"
5+
---
6+
7+
This page explains how different Ably operations contribute to your message count. Understanding message billing helps you optimize costs and choose the right features for your use case.
8+
9+
<Aside data-type="further-reading">
10+
For package comparison and volume discounts, see the [pricing](https://ably.com/pricing) page. For general billing information, see [billing](/docs/platform/pricing/billing).
11+
</Aside>
12+
13+
## Basic message counting <a id="basic-counting"/>
14+
15+
Every message sent through Ably is counted for both publishing and delivery:
16+
17+
* 1 publish = 1 inbound message
18+
* Each subscriber delivery = 1 outbound message per subscriber
19+
20+
For example, 1 publisher sends a message to a channel with 10 subscribers = **11 messages** (1 inbound + 10 outbound).
21+
22+
## Message size <a id="message-size"/>
23+
24+
Message size is calculated as the sum of the `name`, `clientId`, `data`, and `extras` [properties](/docs/api/realtime-sdk/messages#properties) before any compression or expansion occurs in the serialization process.
25+
26+
* `name` and `clientId` are calculated as the size in bytes of their UTF-8 representation.
27+
* `data` is calculated as the size in bytes if it is binary, or its UTF-8 byte length if it is a string.
28+
* `extras` is calculated as the string length of its JSON representation.
29+
30+
The [bandwidth](/docs/platform/pricing#bandwidth) allowance calculation uses an average message size of 5KiB. If your total bandwidth for the month exceeds this baseline, the overage is charged per GiB.
31+
32+
See [maximum message size](/docs/platform/pricing/limits#message) for the size limits per package type.
33+
34+
## Operations and their billing impact <a id="operations"/>
35+
36+
The following table shows how different operations contribute to your message count:
37+
38+
| Operation | Messages counted | Notes |
39+
| --- | --- | --- |
40+
| Publish to channel | 1 inbound + 1 per subscriber outbound | Base cost for all messaging |
41+
| Persisted message storage | +1 per message stored | Enable via [channel rules](/docs/storage-history/storage) |
42+
| History retrieval | +1 per message retrieved | Each call to the [history API](/docs/storage-history/history) |
43+
| Presence enter/leave/update | 1 inbound + 1 per presence subscriber outbound | Same counting as regular messages |
44+
| Typing indicator heartbeat | 1 inbound + 1 per room member outbound | Controlled by `heartbeatThrottleMs` |
45+
| Webhook/integration delivery | +1 per outbound delivery | Per [integration](/docs/platform/integrations) target |
46+
| Rewind on attach | Rewound messages count as outbound | Up to 100 messages per [rewind](/docs/channels/options/rewind) |
47+
| Push notification | Counted separately per push platform | See [push notifications](/docs/push) |
48+
49+
## Persistence billing <a id="persistence"/>
50+
51+
When persistence is enabled via [channel rules](/docs/storage-history/storage), each message stored to disk counts as an additional message.
52+
53+
If you persist all messages, a message published to 10 subscribers with persistence enabled = 1 (publish) + 10 (subscriber delivery) + 1 (persistence storage) = **12 messages**.
54+
55+
If you persist last message only, the most recent message is stored. The storage cost is 1 additional message per new "last message" stored.
56+
57+
Retrieving persisted messages via the [history API](/docs/storage-history/history) also counts: each message returned in a history response = 1 additional message.
58+
59+
To avoid persistence costs on messages that don't need history, mark them as [ephemeral](/docs/pub-sub/advanced#ephemeral).
60+
61+
## Presence event billing <a id="presence"/>
62+
63+
Presence events (enter, leave, update) are billed as regular messages:
64+
65+
* 1 presence enter event with 100 presence subscribers = **101 messages** (1 enter + 100 deliveries)
66+
67+
In high-churn scenarios, presence events can generate significant message volume due to the n-squared pattern. When both subscribers and members are present on a channel, each member event is delivered to every subscriber.
68+
69+
For example, 200 members joining and leaving a channel generates approximately **80,400 messages**. See the [large-scale presence sets](/docs/presence-occupancy/presence#large-presence) section for the full calculation.
70+
71+
To reduce presence costs:
72+
73+
* Use [occupancy](/docs/presence-occupancy/occupancy) if you only need member counts, not individual identities.
74+
* Enable [server-side batching](/docs/presence-occupancy/presence#large-presence) to group presence events and support up to 20,000 members per channel.
75+
* Subscribe to presence updates only on channels where you need member-level detail.
76+
77+
## Chat-specific billing <a id="chat"/>
78+
79+
The [Chat SDK](/docs/chat) uses the same billing model.
80+
81+
Each chat message published to a room = 1 inbound + 1 per subscriber outbound.
82+
83+
Each typing indicator heartbeat event = 1 inbound + 1 per subscriber outbound. At the default 10-second heartbeat, one active typer generates approximately six events per minute. In a room with 50 subscribers, this is approximately **306 messages per minute** per active typer.
84+
85+
Each reaction = 1 inbound + 1 per subscriber outbound.
86+
87+
## Cost optimization strategies <a id="optimization"/>
88+
89+
The following table summarizes strategies for reducing message costs:
90+
91+
| Strategy | How it reduces costs | When to use |
92+
| --- | --- | --- |
93+
| [Ephemeral messages](/docs/pub-sub/advanced#ephemeral) | Exempt from persistence, rewind, resume, and integrations | Streaming data where history is not needed |
94+
| [echoMessages: false](/docs/pub-sub/advanced#echo) | Prevents self-delivery to the publisher | Optimistic UI patterns and server-side publishers |
95+
| [Conflation](/docs/guides/pub-sub/data-streaming#solution-message-conflation) | Delivers only the latest message per key in each time window | High-frequency updates where only the latest value matters |
96+
| [Server-side batching](/docs/guides/pub-sub/data-streaming#solution-server-side-batching) | Groups messages into single deliveries | High-throughput channels where slight delay is acceptable |
97+
| [Delta compression](/docs/channels/options/deltas) | Reduces payload size, lowering bandwidth costs | Large, structurally similar successive messages |
98+
| [Occupancy](/docs/presence-occupancy/occupancy) instead of presence | Avoids n-squared presence event fan-out | When you need member counts, not individual identities |
99+
100+
<Aside data-type="further-reading">
101+
See the [pricing](https://ably.com/pricing) page for package comparison and volume discounts.
102+
</Aside>

0 commit comments

Comments
 (0)