client.notifications.add({ message, origin, options });
client.notifications.addError({ message, origin, options });
client.notifications.addWarning({ message, origin, options });
client.notifications.addInfo({ message, origin, options });
client.notifications.addSuccess({ message, origin, options });Notifications
The Stream Chat client can create notifications that are then rendered through NotificationList.
NotificationList renders client notifications from client.notifications.
Inside MessageList and VirtualizedMessageList, the default notification stack is split like this:
MessageListNotificationsrenders channel notifications fromChannelStateContext.notificationsplus connection status UINotificationListrenders client notifications scoped to the message-list panel
Best Practices
- Use severity levels to keep notifications meaningful.
- Keep notification copy concise and actionable.
- Prefer
NotificationListfor client-notification customization and filtering. - Use
MessageListNotificationsonly when you need to change the channel-notification container orConnectionStatuslayout. - Translate notifications through the
notificationtopic for consistency. - Avoid over-notifying noisy or repeating events.
To build and translate notification text, register translator functions for the notification topic. See the notification translation guide.
Customizing NotificationList
Use WithComponents to replace the default client-notification surface:
import {
Channel,
ChannelHeader,
MessageInput,
MessageList,
NotificationList,
Thread,
Window,
WithComponents,
type NotificationListProps,
} from "stream-chat-react";
const CustomNotificationList = (props: NotificationListProps) => (
<div className="custom-notification-list">
<NotificationList {...props} verticalAlignment="top" />
</div>
);
const App = () => (
<WithComponents overrides={{ NotificationList: CustomNotificationList }}>
<Channel>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</WithComponents>
);Use panel, fallbackPanel, or filter on NotificationList when you need panel-specific routing or client-notification filtering.
If you need to customize channel notifications and connection status inside the message list specifically, override MessageListNotifications instead. MessageListNotifications only controls that channel-notification container. The unread UI and new-message UI are handled separately by UnreadMessagesNotification, NewMessageNotification, and ScrollToLatestMessageButton.
The sections below cover notification management in NotificationManager.
NotificationManager
NotificationManager centralizes notification creation and display across severities (error, warning, info, success) with configurable duration and behavior.
Accessing NotificationManager
NotificationManager is available on the StreamChat client:
const client = new StreamChat(apiKey, token);
const notificationManager = client.notifications;Notification Severity Types
The manager supports four severity levels:
type NotificationSeverity = "error" | "warning" | "info" | "success";Each severity defaults to 3000ms (3 seconds).
Adding Notifications
Basic Usage
// Add a notification with default severity (info)
const id = client.notifications.add({
message: "Operation completed",
origin: {
emitter: "MyComponent",
context: {
/* any relevant context */
},
},
});Specific Severity Methods
// Add error notification
client.notifications.addError({
message: "Operation failed",
origin: { emitter: "MyComponent" },
});
// Add warning notification
client.notifications.addWarning({
message: "Operation might fail",
origin: { emitter: "MyComponent" },
});
// Add info notification
client.notifications.addInfo({
message: "Operation in progress",
origin: { emitter: "MyComponent" },
});
// Add success notification
client.notifications.addSuccess({
message: "Operation succeeded",
origin: { emitter: "MyComponent" },
});Advanced Options
client.notifications.add({
message: "Custom notification",
origin: { emitter: "MyComponent" },
options: {
severity: "warning",
duration: 8000, // Override default duration
actions: [
{
label: "Retry",
handler: () => {
/* handle retry */
},
},
],
metadata: {
/* custom data */
},
},
});Managing Notifications
Removing Notifications
// Remove specific notification
client.notifications.remove(notificationId);
// Clear all notifications
client.notifications.clear();Accessing Current Notifications
// Get all notifications
const allNotifications = client.notifications.notifications;
// Get notifications by severity
const errors = client.notifications.error;
const warnings = client.notifications.warning;
const infos = client.notifications.info;
const successes = client.notifications.success;Subscribing to State Changes
NotificationManager uses a StateStore. Subscribe to state changes:
// Subscribe to all notification changes
const unsubscribe = client.notifications.store.subscribe(
(nextValue, previousValue) => {
// Handle notification state changes
console.log("New notifications:", nextValue.notifications);
console.log("Previous notifications:", previousValue?.notifications);
},
);
// Clean up subscription
unsubscribe();State Structure
The NotificationManager state has the following structure:
type NotificationState = {
notifications: Array<{
id: string;
message: string;
origin: {
emitter: string;
context?: Record<string, unknown>;
};
severity: NotificationSeverity;
createdAt: number;
actions?: Array<{
label: string;
handler: () => void;
metadata?: Record<string, unknown>;
}>;
expiresAt?: number;
metadata?: Record<string, unknown>;
originalError?: Error;
type?: string;
}>;
};Notification Types
You can group notifications by assigning type. The SDK uses a unified format:
domain:entity:operation:result- domain: where it occurred (api, validation, permission)
- entity: what it affected (poll, attachment, message)
- operation: what was attempted (create, upload, validate)
- result: outcome (failed, blocked, invalid)
Examples:
validation:attachment:file:missingvalidation:attachment:upload:blockedapi:attachment:upload:failedapi:poll:create:failed
Example error notification emitted by AttachmentManager:
client.notifications.addError({
message: `The attachment upload was blocked`,
origin: {
emitter: "AttachmentManager",
context: { attachment, blockedAttachment: localAttachment },
},
options: {
type: "validation:attachment:upload:blocked",
metadata: {
reason: localAttachment.localMetadata.uploadPermissionCheck?.reason,
},
},
});Best Practices
- Origin Tracking
- Provide a clear
origin.emitter - Include minimal context needed for debugging
- Duration Management
- Match duration to severity and UX needs
- State Cleanup
- Remove notifications that no longer apply
- Clear notifications when the UI context changes
- Error Handling
- Use error notifications for real failures
- Make messages actionable
- Performance
- Unsubscribe on unmount
- Avoid spamming notifications