Ensuring stability and a seamless realtime experience is crucial for
collaborative applications. Liveblocks 1.1 not only introduces significant
improvements in connection stability, but it also enables new APIs allowing you
to build high-quality user experiences with minimal effort.

By completely rewriting our previous connection engine as a formalized state
machine, we have taken a holistic approach to resolve all known bugs around
connectivity and client recovery in edge cases. In this blog post, we’ll
explore:

- [Connection stability enhancements](#connection-stability-enhancements)
- [Connection status API](#connection-status-api)
- [Lost connection API](#lost-connection-api)
- [DevTools offline support](#devtools-offline-support)

## Connection stability enhancements [#connection-stability-enhancements]

With the 1.1 release, we’re placing a strong emphasis on connection stability
around edge cases, ensuring a reliable realtime experience for users. The
rewritten connection engine, formalized and implemented as a state machine,
streamlines the connection and reconnection process, greatly reducing the number
of states we handle internally, making it easier to reason about the exact state
of the Liveblocks connection at any given moment.

<Figure highlight={false}>
  <Image
    src="/images/blog/whats-new-in-v1-1/state-machine-connection-status.png"
    alt="Simplified state chart of the new internal finite state machine"
    width={820}
    height={482}
    quality={90}
  />
</Figure>

The stability enhancements extend to the collaborative aspect of applications,
ensuring a smoother and uninterrupted experience that recovers quickly,
minimizing disruptions and providing users with a seamless collaboration
environment.

### Features

In particular, we’ve made improvements to specific areas:

- The client now restores connections much more quickly after your network
  becomes available again, or after waking up from a long sleep.
- The client will respect 401 and 403 HTTP responses from your backend, and will
  take them as a sign that retrying will not have an any effect. This means that
  responding with a 401 or 403 in your auth endpoint will cause the client to
  stop trying to establish a connection altogether, reducing load on your
  application’s backend. Previously it would keep trying infinitely.

Rewriting the connection engine has also enabled us to create new APIs.

## Connection status API [#connection-status-api]

We’re now providing a clearer connection status API with simplified, and more
intuitively ordered, status names. We’re also deprecating the old names, because
they were tricky to understand, and confusing to work with.

<Figure highlight={false}>
  <Image
    src="/images/blog/whats-new-in-v1-1/table-statuses.png"
    alt="Old vs new connection statuses"
    width={820}
    height={412}
    quality={90}
  />
</Figure>

Previously, without learning about Liveblocks internals, it was not at all
apparent when your app would be in each state, raising more questions than
answers.

- What does `open` mean?
- When is my app `unavailable`, and is it before or after `failed`?
- What’s the difference between `authenticating` and `connecting`?

In Liveblocks 1.1, you can subscribe to a new status subscription, which uses a
fresh new set of states: `initial`, `connecting`, `connected`, `reconnecting`,
`disconnected`.

With the status subscription, it’s immediately apparent which state your app
starts in, and the order in which each state occurs. And as an added bonus, you
can now also distinguish between `connecting` and `reconnecting`, which is an
important difference when building real world applications.

### Building a status badge

With this addition, it’s now easier than ever to create a connection status
badge, and display the current state of your app.

<Slideshow
  slides={[
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/status-connected.png",
      caption: "Connected status badge",
    },
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/status-reconnecting.png",
      caption: "Reconnecting status badge",
    },
  ]}
/>

To build this in React, import the new
[`useStatus`](/docs/api-reference/liveblocks-react#useStatus) hook to return the
current online status.

```tsx
import { useStatus } from "../liveblocks.config";

export function Status() {
  // "initial" | "connecting" | "connected" | "reconnecting" | "disconnected"
  const status = useStatus();

  return <StatusBadge type={status} />;
}
```

We’ve also added a JavaScript equivalent to this hook to our client package for
other framework users,
[`room.subscribe("status")`](/docs/api-reference/liveblocks-client#Room.subscribe.status).

```ts
room.subscribe("status", (status) => {
  // "initial" | "connecting" | "connected" | "reconnecting" | "disconnected"
  console.log(status);
});
```

## Lost connection API [#lost-connection-api]

When a user loses connection to your app, for example because of a poor Wi‑Fi
signal, it’s important to let them know about it. You can do this by displaying
a toast notification, however, you don’t have to let them know _immediately_.

<Slideshow
  slides={[
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/toast-reconnecting.png",
      caption: "Reconnecting status toast",
    },
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/toast-reconnected.png",
      caption: "Reconnected status toast",
    },
  ]}
/>

Because Liveblocks continues working after a connection interruption, and then
synchronizes after reconnecting, it’s safe to ignore brief connection hiccups,
and allow the user’s device a few seconds to reconnect. Only after this period
is it necessary to consider a connection “lost”. With this in mind, we’ve added
another new feature.

### Lost connection listener

In Liveblocks 1.1, you can subscribe to a new “lost connection” event, making it
far simpler to create these toast notifications and handle reconnection
behaviour. What’s important about our new subscription, is that we handle the
behaviour for you:

- Short connection issues are ignored, this event is for when a more serious
  problem has occurred.
- This event is only emitted after a user has connected and _then_ had a
  problem.
- If nothing goes wrong, your user will never receive this event.

Implementing this was possible previously, but a deep understanding of our
internals was required to create a reliable implementation.

### Building toast notification warnings

Below is a video recording of the open-source
[Connection Status example](/examples/connection-status) we put together to demo
the sort of experience you can create with those APIs.

<Link href="/examples/connection-status">
  <Figure>
    <video autoPlay loop muted playsInline>
      <source
        src="/images/blog/whats-new-in-v1-1/connection-status.mp4"
        type="video/mp4"
      />
    </video>
  </Figure>
</Link>

To build toast notification warnings in React, import the new
[`useLostConnectionListener`](/docs/api-reference/liveblocks-react#useLostConnectionListener)
hook alongside your favorite toast notification library, for example
[`react-hot-toast`](https://react-hot-toast.com/).

```tsx
import { useLostConnectionListener } from "../liveblocks.config";
import toast, { Toaster } from "react-hot-toasts";

export function LostConnectionToasts() {
  const toastId = useRef<string>();

  useLostConnectionListener((event) => {
    if (event === "lost") {
      toastId.current = toast.loading("Trying to reconnect…");
    }

    if (event === "restored") {
      toast.success("Reconnected!", { id: toastId.current });
    }

    if (event === "failed") {
      toast.error("Could not reconnect, try refresh", { id: toastId.current });
    }
  });

  return <Toaster />;
}
```

We’ve also added a JavaScript equivalent,
[`room.subscribe("lost-connection")`](/docs/api-reference/liveblocks-client#Room.subscribe.lost-connection).

```ts
room.subscribe("lost-connection", (event) => {
  // "lost" | "restored" | "failed"
  console.log(event);
});
```

Alongside this addition, we’ve also made a change to `others`.

### Change to others

Previously, [`others`](/docs/api-reference/liveblocks-react#useOthers) would be
reset as soon as a reconnect would happen under the hood, even if that reconnect
happened quickly. This meant that even if a network interuption lasted just
milliseconds, [live avatars](/examples/browse/avatar-stack) or other
[presence indicators](/presence) would have a flash of unrendered content,
before reappearing. We’ve fixed this.

In Liveblocks 1.1, `others` will ignore short reconnections, similar to the lost
connection API, and will only reset if a noticeable problem occurs, preventing
any unwanted user interface flashes.

### Configuring the lost connection timeout

It’s possible to configure how quickly you’d like to inform your users about
problems reconnecting using the new `lostConnectionTimeout` client option. The
default value is 5 seconds, and we recommend setting it between 3 and 15
seconds.

```ts
import { createClient } from "@liveblocks/client";

const client = createClient({
  // Set timeout in milliseconds
  lostConnectionTimeout: 5000,

  // Other options
  // ...
});
```

This enhanced user awareness improves transparency, empowers users to take
appropriate actions, and contributes to an overall positive user experience.

### Deprecated APIs

While we’ve carefully taken care of every edge case we could think of, we have
introduced some behavioral changes to fix bugs and make the whole experience
more stable. As a result the following API are being deprecated as part of 1.1:

- `room.subscribe("connection")`
- `room.getConnectionState()`

## DevTools offline support [#devtools-offline-support]

Before Liveblocks 1.1, if your connection was lost, you’d see our
[DevTools](/devtools) jump back to the “loading” state, making it impossible to
observe storage and presence while the client was trying to reestablish a
connection. This is no longer the case!

<Slideshow
  slides={[
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/devtools-connected.png",
      caption: "Connected DevTools status",
    },
    {
      width: 820,
      height: 412,
      imageUrl: "/images/blog/whats-new-in-v1-1/devtools-reconnecting.png",
      caption: "Reconnecting DevTools status",
    },
  ]}
/>

Now, when reconnecting, both storage and presence remain introspectable, so you
can actually see how they’re behaving while not connected to the Liveblocks
servers. This more accurately reflects the way the client actually handles data
(all the storage and presence data still exists in the local client).

## Contributors

Huge thanks to everyone who contributed and specifically to
[Chris Nicholas](https://twitter.com/ctnicholasdev) for the feedback and help
testing this out. Also a big shout out to our incredible community that keeps
jumping in to help us improve our infrastructure! Keep checking out the
[changelog](https://github.com/liveblocks/liveblocks/blob/main/CHANGELOG.md) for
the full release notes – see you next time!