# Requires Node.js (check .nvmrc for version)
nvm use
yarn installLivestream and Live shopping
This guide covers best practices for building livestream and live event chat experiences with Stream. It applies to all SDKs.
- Use the Livestream channel type, which does not require membership for read/write access
- Disable expensive features like read events, typing indicators, and connect events
- Enable slow mode and message throttling for high-traffic events
- Pre-load users before events to avoid registration bottlenecks
- Disable offline/local storage to eliminate write overhead on every incoming message
- Load test your app at high message volumes to catch UI performance issues before going live
- Implement moderation tools like block lists, automod, and flagging
For SDK-specific performance guidance, see:
Channel Types
The Livestream channel type is designed for livestream settings and has pre-configured permissions that do not require membership as a registered user to read or write to a channel. This channel type is "open" to any user accessing it with an authorized JWT. Users do not need to be added as members, which saves complexity and additional updates to the channel through the membership endpoint. The channel can be "watched" by users to receive real-time updates on activity (new messages, etc.) in the channel.
For general information on understanding channel types, roles, and permissions, refer to those documentation pages.
Live events, by contrast, may sometimes be well suited for the Livestream channel type, but frequently require membership for interacting in channels. Creating a new channel type with similar settings to the Livestream channel, but with some tweaks to tailor to your event platform's needs, may be necessary.
Channel Features
A well-built mobile or web app can easily be degraded by excessive API traffic. The Stream API is designed with this in mind with features to protect clients (see throttling and slow mode). However, we still recommend taking these additional steps.
Features to disable for Livestream type settings (in order of performance impact):
- Read events
- Typing indicators
- Connect events
- File uploads
- Custom messages
The Stream Chat API automatically starts throttling typing and read events at 100 watchers in a channel, but it is good practice to remove these from the start, as even 100 very active users can be problematic. It's also worth noting that typing and read events lose their value in user experience as active users rise.
Message Throttling and Slow Mode
The Stream API will begin to throttle messages at >5 messages per second and some messages will not be delivered to all clients watching a channel to protect the client from degraded performance. We also recommend considering Slow Mode for events in which traffic is expected to be particularly high.
For reference, Stream found that in this SpaceX launch video, peak message volume was 9 messages per second, and the chat experience was already difficult to follow.
Disable Offline/Local Storage
Most Stream SDKs offer an offline persistence layer that caches messages to a local database. For livestream use cases, offline storage should be disabled. It introduces write overhead on every incoming message, which becomes a bottleneck under high message volume.
Every message.new event triggers a write to the local database when persistence is enabled. At 5-10+ messages per second (peak livestream traffic), this means:
- Continuous disk I/O on every incoming message
- Memory pressure from maintaining a synchronized local cache that has no value in a livestream context (users don't need to scroll back through thousands of ephemeral messages offline)
- Additional CPU cycles for serialization/deserialization to and from the database
In a livestream, the message list is ephemeral and forward-only. Offline storage adds cost with no user benefit. See your SDK's specific guide for how to disable it.
Application Settings
It is always recommended to ensure that Auth and Permission checks are not disabled for any application in a production environment.
It is common for guest or anonymous users to be integrated into Livestream channels. These users have access to fewer permissions by default, but this is entirely configurable. Guest and Anonymous users do not require a signed JWT from a server.
Adding Users Prior to Events
Stream recommends that users are "pre-loaded" into the Stream API prior to the event. This prevents registration/upsert bottlenecks at the start of the event. In particular, for channels that may have large member counts, it is advised to add members to these ahead of time.
If this can't be achieved based on your app's use case, then we recommend batching users being added to Stream and members being added to channels. Both upsertUsers and addMember endpoints accept up to 100 user_ids in a single API call.
Lastly, if this isn't possible and you expect to exceed rate limits, please email https://getstream.io/contact/support/ with your use case and we may seek to make an exception for your application to avoid any disruptions.
API Calls to /channels
There are several methods that will trigger an API call to /channels: watch, query, and create. Only one of these is necessary. Additional API calls quickly add up and can be problematic. Filtering and sorting generally are not issues for this use case, but for more information on optimizing these queryChannel parameters, take a look at the best practices.
Livestream In-Memory Chat
For mobile platforms, dedicated in-memory controllers are available that bypass the local database entirely, eliminating read/write overhead and keeping memory usage bounded during high-volume events. These controllers omit features that are unnecessary in a livestream context (typing indicators, read indicators, threads, offline support) and support capping the number of messages kept in memory.
- iOS: use the
LivestreamChannelControllerinstead of the standardChatChannelController. - Android: use the Livestream Chat guide for the equivalent Android implementation.
Limit Visible Messages
Cap the number of messages held in memory and rendered on screen. Keeping 200-500 messages is sufficient for a livestream chat. Trim older messages as new ones arrive to prevent unbounded memory growth and rendering cost.
Each SDK handles this differently:
- On web/React, use a virtualized list component to limit DOM elements
- On mobile (Flutter, iOS, Android), cap the list data source and remove old entries
See your SDK's specific guide for implementation details.
Load Testing with BenChat
Before launching a live event, test your application under high user and message volumes. Subtle mistakes in UI elements can cause performance degradation at scale that isn't apparent during normal development.
Common issues that only surface under load:
- Expensive re-renders: components that re-render on every message cause lag when message volume is high
- Memory leaks: unbounded message lists or event listeners that aren't properly cleaned up
- Avatar and image loading: fetching user avatars or images for every message without caching
- Complex message formatting: rich text parsing, link previews, or emoji rendering that doesn't scale
- Animation overhead: animations or transitions that compound with high message frequency
Use Stream's BenChat tool to stress test your chat channels and simulate realistic traffic patterns.
Setup
Running a Benchmark
./bench.sh \
--apiKey=YOUR_API_KEY \
--apiSecret=YOUR_API_SECRET \
--channelType=livestream \
--channelID=your-channel-idKey Parameters
| Parameter | Default | Description |
|---|---|---|
--apiKey | (required) | Your Stream API key |
--apiSecret | (required) | Your Stream API secret |
--channelType | (required) | Channel type, e.g. livestream |
--channelID | (required) | Target channel ID |
--userConnectionsMax | 99 | Number of concurrent users to connect |
--messagesPerMinute | 20 | Message send rate |
--connectionDelay | 100 | Milliseconds between user connections |
--userLifetime | 6000 | How long (ms) each user stays connected |
--coolDown | 5000 | Pause (ms) between full benchmark runs |
--userIDPrefix | tommaso- | Prefix for generated user IDs |
--includeAttachments | false | Include image attachments in messages |
--sendReactions | false | Send reactions on each message |
Recommended Testing Approach
- Start at baseline: run with defaults (~20 messages/minute, 99 users) and profile your app
- Ramp to peak: increase
--messagesPerMinuteto 300-600 (5-10 msg/sec) to simulate peak livestream conditions - Test with attachments: enable
--includeAttachmentsto measure the cost of image rendering under load - Test with reactions: enable
--sendReactionsto measure the impact of reaction events on your UI - Monitor your app: while BenChat runs, profile your app using your platform's native profiling tools (Flutter DevTools, Xcode Instruments, Android Profiler, browser DevTools, etc.)
Moderation
Stream provides a number of moderation tools useful in a livestream setting:
-
Users flagging messages - any user can flag another user's message. Flagged messages are sent to the Stream Moderation Dashboard and also trigger a Webhook event.
-
Moderation Dashboard - available to all customers and includes a chat Explorer, Flagged Message review area, and a number of API driven features to ban or delete users.
-
Block Lists - a simple but powerful tool to prevent lists of words from being used in a Chat. These are applied on a Channel Type basis and either a Flag or Block behavior can be defined.
-
Pre-send message hook - a customer-hosted solution that provides a means to host your own moderation solution that can hook into any 3rd party solutions, have Regex filters, or more advanced filtering based on your own criteria.
-
AI Moderation - please reach out to https://getstream.io/contact/support/ to learn more.
-
Image Moderation - an addon to Enterprise packages that flags images deemed inappropriate by the moderation logic.