Notifications

Starting in stream-chat-react@13.1.0, you can render notifications created by the StreamClient:

client.notifications.add({ message, origin, options }); // low-level method called by addError/addWarning/...
client.notifications.addError({ message, origin, options }); // adds severity: 'error'
client.notifications.addWarning({ message, origin, options }); // adds severity: 'warning'
client.notifications.addInfo({ message, origin, options }); // adds severity: 'info'
client.notifications.addSuccess({ message, origin, options }); // adds severity: 'success'

MessageListNotifications renders these notifications. You can swap it with a custom component:

<Channel MessageListNotifications={CustomMessageListNotifications}>

Best Practices

  • Use severity levels to keep notifications meaningful.
  • Keep notification copy concise and actionable.
  • Prefer custom MessageListNotifications only for layout or branding changes.
  • Translate notifications via the notification topic for consistency.
  • Avoid over-notifying; throttle noisy sources.

To build and translate notification text, register translator functions for the notification topic. See the notification translation guide.

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:missing
  • validation:attachment:upload:blocked
  • api:attachment:upload:failed
  • api: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

  1. Origin Tracking
  • Provide a clear origin.emitter
  • Include minimal context needed for debugging
  1. Duration Management
  • Match duration to severity and UX needs
  1. State Cleanup
  • Remove notifications that no longer apply
  • Clear notifications when the UI context changes
  1. Error Handling
  • Use error notifications for real failures
  • Make messages actionable
  1. Performance
  • Unsubscribe on unmount
  • Avoid spamming notifications