val channelClient = client.channel("messaging", "general")
// Enable slow mode and set cooldown to 1s
channelClient.enableSlowMode(cooldownTimeInSeconds = 1).enqueue { /* Result handling */ }
// Increase cooldown to 30s
channelClient.enableSlowMode(cooldownTimeInSeconds = 30).enqueue { /* Result handling */ }
// Disable slow mode
channelClient.disableSlowMode().enqueue { /* Result handling */ }Slow Mode & Throttling
For live events or concerts, you can sometimes have so many users, that the sheer volume of messages overloads the browser or mobile device. This can cause the UI to freeze, high CPU usage, and degraded user experience. Stream offers 3 features to help with this:
-
Channel Slow Mode
-
Automatic feature Throttling
-
Message Throttling
Stream scales to 5 million concurrent users on a channel, see Scaling Chat to 5 Million Concurrent Connections.
Channel Slow Mode
Slow mode helps reduce noise on a channel by limiting users to a maximum of 1 message per cooldown interval.
The cooldown interval is configurable and can be anything between 1 and 120 seconds. For instance, if you enable slow mode and set the cooldown interval to 30 seconds a user will be able to post at most 1 message every 30 seconds.
Moderators, admins and server-side API calls are not restricted by the cooldown period and can post messages as usual.
Slow mode is disabled by default and can be enabled/disabled via the Dashboard, using the Chat Explorer:

It can also be enabled/disabled by admins and moderators via SDK.
// enable slow mode and set cooldown to 1s
await channel.enableSlowMode(1);
// increase cooldown to 30s
await channel.enableSlowMode(30);
// disable slow mode
await channel.disableSlowMode();When a user posts a message during the cooldown period, the API returns an error message. You can avoid hitting the APIs and instead show such limitation on the send message UI directly. When slow mode is enabled, channels include a cooldown field containing the current cooldown period in seconds.
const p = channel.sendMessage(msg);
if (channel.data.cooldown != null && channel.data.cooldown > 0) {
p.then(() => {
// first lock the UI so that the user is aware of the cooldown
disableSendMessageUI();
// restore the UI after the cooldown is finished
setTimeout(enableSendMessageUI, channel.data.cooldown);
});
}
await p;Automatic Feature Throttling
When a channel has more than 100 active watchers Stream Chat automatically toggles off some features. This is to avoid performance degradation for end-users. Processing large amount of events can potentially increase CPU and memory usage on mobile and web apps.
-
Read events and typing indicator events are discarded
-
Watcher start/stop events are only sent once every 5 seconds
Event throttling
Stream applies two control layers to protect clients and keep real-time behaviour predictable under load:
- API throttles cap how often a given event type can be produced. Limits are scoped by entity key (per channel, per call, or per user), not globally across your app.
- WebSocket queue throttles cap how quickly events are delivered over a single user connection. Each connection has three queues that prioritise traffic and smooth bursts.
Together, these limits keep delivery fair during spikes such as live events, concerts, or mass-notification scenarios, without dropping the events that matter most.
WebSocket queues
Every user connection drains events through three queues, each with its own per-connection rate limit:
| Queue | Limit (events/sec) | Purpose |
|---|---|---|
critical | 30 | Highest priority. System and access events where fast, reliable delivery matters most. |
ordered | 15 | Preserves event order. Used for sequential streams such as messages and reactions. |
mergeable | 10 | Coalesces repeated updates by key (latest wins) to reduce noisy state-change traffic. |
If a burst exceeds a queue's limit, events continue to be delivered but at the queue's steady-state rate. Events on the mergeable queue may be collapsed so only the most recent update per key is sent.
API throttles per event
The tables below list the per-entity API throttle for each event type and the WebSocket queue it is delivered through. unlimited means no API-side cap is applied; delivery is still governed by the WebSocket queue.
API throttles are applied per entity key. For example, message.new at 10 events/sec applies per channel, and user.presence.changed at 8 events/sec applies per user. Separate channels or users do not share the same budget.
| Event | API throttle (events/sec) | WS queue | WS queue limit (events/sec) |
|---|---|---|---|
* (custom events) | 8 | ordered | 15 |
ai_indicator.clear | 10 | ordered | 15 |
ai_indicator.stop | 10 | ordered | 15 |
ai_indicator.update | 10 | ordered | 15 |
channel.created | 5 | ordered | 15 |
channel.deleted | 5 | ordered | 15 |
channel.frozen | 10 | mergeable | 10 |
channel.hidden | 10 | ordered | 15 |
channel.kicked | 30 | critical | 30 |
channel.max_streak_changed | 10 | mergeable | 10 |
channel.truncated | 5 | ordered | 15 |
channel.unfrozen | 10 | mergeable | 10 |
channel.updated | 8 | mergeable | 10 |
channel.visible | 10 | ordered | 15 |
draft.deleted | 10 | mergeable | 10 |
draft.updated | 10 | mergeable | 10 |
member.added | 8 | ordered | 15 |
member.removed | 8 | ordered | 15 |
member.updated | 8 | ordered | 15 |
message.deleted | 8 | ordered | 15 |
message.delivered | 8 | ordered | 15 |
message.new | 10 | ordered | 15 |
message.pending | 15 | ordered | 15 |
message.read | 20 | ordered | 15 |
message.undeleted | 8 | ordered | 15 |
message.updated | 10 | ordered | 15 |
notification.added_to_channel | 8 | critical | 30 |
notification.channel_deleted | 8 | critical | 30 |
notification.channel_mutes_updated | 8 | mergeable | 10 |
notification.channel_truncated | 8 | critical | 30 |
notification.invite_accepted | 8 | critical | 30 |
notification.invite_rejected | 8 | critical | 30 |
notification.invited | 8 | critical | 30 |
notification.mark_read | 20 | critical | 30 |
notification.mark_unread | 10 | critical | 30 |
notification.message_new | 10 | critical | 30 |
notification.mutes_updated | 8 | mergeable | 10 |
notification.reminder_due | unlimited | critical | 30 |
notification.removed_from_channel | 8 | critical | 30 |
notification.thread_message_new | 10 | critical | 30 |
poll.closed | 15 | ordered | 15 |
poll.deleted | 15 | ordered | 15 |
poll.updated | 15 | ordered | 15 |
poll.vote_casted | 15 | ordered | 15 |
poll.vote_changed | 15 | ordered | 15 |
poll.vote_removed | 15 | ordered | 15 |
reaction.deleted | 10 | ordered | 15 |
reaction.new | 10 | ordered | 15 |
reaction.updated | 10 | ordered | 15 |
reminder.created | 15 | ordered | 15 |
reminder.deleted | 15 | ordered | 15 |
reminder.updated | 15 | ordered | 15 |
thread.updated | 10 | mergeable | 10 |
typing.start | 10 | ordered | 15 |
typing.stop | 10 | ordered | 15 |
user.messages.deleted | 15 | critical | 30 |
user.muted | 10 | mergeable | 10 |
user.watching.start | 5 | ordered | 15 |
user.watching.stop | 5 | ordered | 15 |
If you are on an Enterprise Plan, throttling limits can be adjusted for your application by our support team.