# Connection status

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

When the client can't reach Stream, the SDK says why: "Waiting for network…" when the device is offline, "Reconnecting…" when the network is fine but the connection to Stream dropped. When the connection comes back, the client brings what's on screen up to date by itself. This page covers what users get, how the parts fit together, and how to show the status in your app.

## What users get

The user's laptop loses its Wi-Fi on a train:

1. The browser reports that the device is offline. `Chat` publishes "Waiting for network…" at once.
2. The app renders a banner for it, so the user sees "Waiting for network…" at the top of the chat. A screen reader reads "Loading notification: Waiting for network…".
3. The Wi-Fi comes back, and so does the connection. The banner goes away.
4. The client reloads the channel lists and the open channel. The messages the user missed appear.

Later, the connection to Stream drops while the Wi-Fi works, because the server closed it or a health check timed out:

- If it comes back within five seconds, the user sees nothing. Most drops recover in under a second.
- If it doesn't, the banner shows "Reconnecting…" until it does.

The banner is the app's part. `Chat` publishes the message but renders nothing for it, so without a banner the user sees no status, and only a screen reader hears it.

## How it works across the layers

### State: two connection facts and recovery

The client keeps two separate facts, because they disagree in both directions:

- `client.networkConnection.state` holds `isOnline`: whether the device has a network. It's `undefined` while unknown, so test it with `=== false`.
- `client.wsConnection.state` holds `isHealthy`: whether the WebSocket to Stream is up. It records a drop the moment it happens.

After a reconnect, `client.connectionRecovery` reloads the channel lists that have loaded, the active channels and the active threads, then dispatches `connection.recovered`. [Connection](https://getstream.io/chat/docs/sdk/react/v15/state/connection/) explains both stores, the network reporter outside the browser, and recovery.

### UI: the lost-connection notification

`Chat` watches both stores and publishes one system notification while the client can't reach Stream:

- "Waiting for network…" as soon as the device reports it's offline;
- "Reconnecting…" when the socket has been down for `client.wsConnection.config.offlineNotificationDisplayDelayMs`, five seconds by default, while the network is up or unknown.

Both have the type `system:network:connection:lost` and the severity `loading`. They stay until the connection is back, then `Chat` removes them. The hook that does this, `useReportLostConnectionSystemNotification`, is exported too.

A system notification carries the `system` tag, so no `NotificationList` shows it. The app renders it with `useSystemNotifications()`, anywhere inside `Chat`. `NotificationAnnouncer` reads it to screen readers like any other notification. [System notifications](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/displaying-notifications/#system-notifications) covers them.

After a reconnect, the components re-render from the stores recovery reloads. Which channels and threads reload depends on what's active:

- `Channel` marks the channel it shows active, so an open channel always reloads.
- `Thread` doesn't. An open thread reloads only while something holds it active, such as `useActiveThread({ activeThread })` from `stream-chat-react/slot-layout`, which holds it while the window has focus. Otherwise the thread is marked stale, and loads again the next time it's opened.

For a status UI of your own, `useNetworkConnectionState()`, `useNetworkConnectionStateSelector(selector)` and `useWSConnectionState()` read the two stores.

### Layout

The layout isn't involved: the status and the banner are the same wherever channels and threads open.

## Turning it on or off

The connection status is always on, for every user, and there's no capability or dashboard setting for it. `Chat` always publishes the notification. Whether users see it depends on whether the app renders a banner.

What you can change is in `client.config`:

- `client.wsConnection.offlineNotificationDisplayDelayMs`: how long a socket drop lasts before "Reconnecting…" shows. `0` shows it on the next tick.
- `client.connectionRecovery.enabled`: whether the client reloads lists, channels and threads after a reconnect. With it off, `connection.recovered` doesn't fire either.
- `client.networkConnection.statusReporter`: what tells the client about the device's network, outside the browser.

```ts
client.config.set({
  client: { wsConnection: { offlineNotificationDisplayDelayMs: 2000 } },
});
```

The delay is read at each drop, so a change applies from the next one. [Configuration](https://getstream.io/chat/docs/sdk/react/v15/state/state-and-entities/configuration/) explains `client.config`, and [Connection](https://getstream.io/chat/docs/sdk/react/v15/state/connection/) the other settings.

## Customizing

### Showing the banner

Render the lost-connection notification inside `Chat`, above the rest of the layout:

```tsx
import type { PropsWithChildren } from "react";
import type { Notification } from "stream-chat";
import { Chat, useSystemNotifications } from "stream-chat-react";

// Declared outside the component, so the subscription stays the same across renders.
const isConnectionLost = (notification: Notification) =>
  notification.type === "system:network:connection:lost";

const ConnectionBanner = () => {
  const [lostConnection] = useSystemNotifications({ filter: isConnectionLost });
  if (!lostConnection) return null;

  return <div className="connection-banner">{lostConnection.message}</div>;
};

export const App = ({ children }: PropsWithChildren) => (
  <Chat client={client}>
    <ConnectionBanner />
    {children}
  </Chat>
);
```

The banner has no live region of its own, because `NotificationAnnouncer` already reads the notification to screen readers. The message is already translated, and says which connection is down. To change the wording, override the translation keys `chat.reportLostConnection.waitingNetwork.text` and `chat.reportLostConnection.reconnecting.text`, as [Localization](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/localization/) explains.

The [System notification banner](https://getstream.io/chat/docs/sdk/react/v15/recipes/app/system-notification-banner/) recipe builds a complete banner, with an icon per severity, an animation, and system notifications of your own.

### A status of your own

To decide the copy yourself, read the two stores. This component waits before it says "Reconnecting…", as `Chat` does, so a short drop shows nothing:

```tsx
import { useEffect, useState } from "react";
import type { NetworkConnectionState } from "stream-chat";
import {
  useChatContext,
  useNetworkConnectionStateSelector,
  useWSConnectionState,
} from "stream-chat-react";

const selectIsOnline = ({ isOnline }: NetworkConnectionState) => ({
  isOnline,
});

export const ConnectionStatus = () => {
  const { client } = useChatContext();
  const { isOnline } = useNetworkConnectionStateSelector(selectIsOnline) ?? {};
  const { isHealthy = true } = useWSConnectionState() ?? {};
  const [isReconnecting, setIsReconnecting] = useState(false);

  useEffect(() => {
    if (isHealthy) {
      setIsReconnecting(false);
      return;
    }
    const delayMs =
      client.wsConnection.config.offlineNotificationDisplayDelayMs;
    const timer = setTimeout(() => setIsReconnecting(true), delayMs);
    return () => clearTimeout(timer);
  }, [client, isHealthy]);

  // `=== false`: `undefined` means the network status is unknown, not offline.
  if (isOnline === false) return <p>You're offline</p>;
  if (isReconnecting) return <p>Reconnecting…</p>;
  return null;
};
```

There's no hook that combines the two facts. Whether "no network and no socket" reads as offline or as reconnecting is a choice for your copy. Declare the selector at module scope: an inline one resubscribes on every render. [Reading state in components](https://getstream.io/chat/docs/sdk/react/v15/ui/reading-state-in-components/) explains why.

### Refreshing your own data after a reconnect

The client reloads its own lists, channels and threads. Data the app loads itself, such as results of a one-off query, is reloaded on `connection.recovered`:

```tsx
import { useEffect, useState } from "react";
import { useChatContext } from "stream-chat-react";

export const TotalUnreadBadge = () => {
  const { client } = useChatContext();
  const [totalUnread, setTotalUnread] = useState(0);

  useEffect(() => {
    const load = async () => {
      const { total_unread_count } = await client.unreadCounts();
      setTotalUnread(total_unread_count);
    };

    void load();
    const { unsubscribe } = client.on("connection.recovered", () => {
      void load();
    });
    return unsubscribe;
  }, [client]);

  return <span className="total-unread">{totalUnread}</span>;
};
```

[connection.recovered](https://getstream.io/chat/docs/sdk/react/v15/state/connection/#connectionrecovered) explains when the event fires.

### What screen readers hear

`NotificationAnnouncer` reads the lost-connection notification as "Loading notification: Reconnecting…". To leave it out, or reword it, replace the announcer as [Customizing notification announcements](https://getstream.io/chat/docs/sdk/react/v15/features/app-experience/accessibility/#customizing-notification-announcements) shows.

## Reference

- [Connection](https://getstream.io/chat/docs/sdk/react/v15/state/connection/): `client.wsConnection`, `client.networkConnection`, `client.connectionRecovery` and `connection.recovered`.
- [System notifications](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/displaying-notifications/#system-notifications): the lost-connection notification and `useSystemNotifications`.
- [Connection hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/connection-hooks/): `useNetworkConnectionState`, `useNetworkConnectionStateSelector`, `useWSConnectionState` and `useReportLostConnectionSystemNotification`.
- [Notification hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/notification-hooks/): `useSystemNotifications` and `useNotificationApi`.
- [System notification banner](https://getstream.io/chat/docs/sdk/react/v15/recipes/app/system-notification-banner/): a complete banner.
- [Configuration tree](https://getstream.io/chat/docs/sdk/react/v15/reference/state/configuration-tree/): the `wsConnection`, `networkConnection` and `connectionRecovery` settings.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/features/app-experience/connection-status/](https://getstream.io/chat/docs/sdk/react/v15/features/app-experience/connection-status/).