# Connection status

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/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, of type `system:network:connection:lost`, while the client can't reach Stream. [System notifications](https://getstream.io/chat/docs/sdk/react/ui/components/notifications-ui/#system-notifications) explains when it says "Waiting for network…" or "Reconnecting…", and how long it stays.

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 channel paginators, channels and threads after a reconnect. With it off, only the thread list reloads, and `connection.recovered` still fires after each reconnect. See [Turning recovery off or running it by hand](https://getstream.io/chat/docs/sdk/react/state/connection/#turning-recovery-off-or-running-it-by-hand).
- `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/state/state-and-entities/configuration/) explains `client.config`, and [Connection](https://getstream.io/chat/docs/sdk/react/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>
);
```

Like every system notification banner, it needs no live region of its own: see [A banner for system notifications](https://getstream.io/chat/docs/sdk/react/ui/components/notifications-ui/#a-banner-for-system-notifications). 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/features/app-experience/localization/) explains.

The [System notification banner](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/notifications/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/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 the result of a one-off query, is reloaded on `connection.recovered`. In React, subscribe with `client.on()` in an effect, and return the `unsubscribe` it gives you so the listener goes away with the component.

[Event `connection.recovered`](https://getstream.io/chat/docs/sdk/react/state/connection/#event-connectionrecovered) explains when the event fires, with an example that reloads an unread count.

### 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/features/notifications/accessibility/#customizing-notification-announcements) shows.

## Reference

- [Connection](https://getstream.io/chat/docs/sdk/react/state/connection/): `client.wsConnection`, `client.networkConnection`, `client.connectionRecovery` and `connection.recovered`.
- [System notifications](https://getstream.io/chat/docs/sdk/react/ui/components/notifications-ui/#system-notifications): the lost-connection notification and `useSystemNotifications`.
- [Connection hooks](https://getstream.io/chat/docs/sdk/react/reference/hooks/connection-hooks/): `useNetworkConnectionState`, `useNetworkConnectionStateSelector`, `useWSConnectionState` and `useReportLostConnectionSystemNotification`.
- [Notification hooks](https://getstream.io/chat/docs/sdk/react/reference/hooks/notification-hooks/): `useSystemNotifications` and `useNotificationApi`.
- [System notification banner](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/notifications/system-notification-banner/): a complete banner.
- [Configuration tree](https://getstream.io/chat/docs/sdk/react/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/features/app-experience/connection-status/](https://getstream.io/chat/docs/sdk/react/features/app-experience/connection-status/).