This August we significantly improved our dashboard, along with other changes.

- [Dashboard enhancements](#dashboard-enhancements): Improved observability and
  developer experience.
- [Conditionally render parts](#conditionally-render-parts): Use the same
  components inside & outside rooms.
- [Fetch unread notifications](#fetch-unread-notifications): Create email
  notifications more easily.
- [Better search dialog](#better-search-dialog): Docs search has more results
  and is more accurate.
- [Improved canvas examples](#improved-canvas-examples): Polished up draggable
  Comments examples.

## Upgrade now

To use the latest features, update your packages with the following command.

```bash
npx create-liveblocks-app@latest --upgrade
```

If you were previously on Liveblocks 2.1 or below, make sure to follow our
[upgrade guides](/docs/platform/upgrading) before updating.

## Dashboard enhancements [#dashboard-enhancements]

In the past month we’ve made a huge amount of enhancements to our dashboard,
helping improve observability and developer experience. For example, you can now
visualize Comments and Text Editor state directly in the dashboard.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-august-24/comments-view.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

### Dashboard blog post

We’ve made so many improvements in this area, that we’ve written a whole blog
post just to highlight them.

<UniversalLink href="/blog/dashboard-enhancements-to-improve-observability-and-developer-experience">
  <Figure>
    <Image
      src="/images/blog/social-images/dashboard-enhancements-2024.jpg"
      alt="New room detail page navigation in the Liveblocks dashboard"
      width={750}
      height={394}
      quality={95}
    />
  </Figure>
</UniversalLink>

Enhancements include:

- [Search, sort, and filter rooms](#search-sort-and-filter-rooms) - Find and
  debug your rooms more easily.
- [Room detail improvements](#room-detail-improvements) - Delete rooms and added
  information.
- [New Comments view](#new-comments-view) - Sort & delete threads and comments
  visually.
- [Text Editor preview](#text-editor-preview) - Preview editor content,
  annotations, threads.
- [Broadcast events](#broadcast-events) - Send custom events directly to your
  rooms.
- [API snippets](#api-snippet) - Pre-filled code for modifying and retrieving
  rooms.
- [Webhook error tracking](#webhook-error-tracking) - View failed webhook
  responses from your back end.

## Conditionally render parts [#conditionally-render-parts]

When building a collaborative React application, it can be helpful to re-use
components both inside and outside Liveblocks rooms. For example in a Liveblocks
document, a header bar could display a live avatar stack of every connected
user, but outside the document, you won’t need it.

Previously, it wasn’t possible to conditionally render Liveblocks hooks in this
way, but we’ve added a new hook that makes this much easier,
[`useIsInsideRoom`](/docs/api-reference/liveblocks-react#useIsInsideRoom).
Below, we’re only rendering `<LiveAvatars />` inside Liveblocks rooms.

```tsx
function HeaderAvatars() {
  // `true` if inside a Liveblocks room, `false` otherwise
  const isInsideRoom = useIsInsideRoom();

  if (!isInsideRoom) {
    return null;
  }

  return <LiveAvatars />;
}

function LiveAvatars() {
  const others = useOthers();
  return others.map((other) => <img src={other.info.picture} />);
}
```

Along with hiding components completely,
[`useIsInsideRoom`](/docs/api-reference/liveblocks-react#useIsInsideRoom) can
also be used to render alternative parts. Let’s say you have an interactive list
of tags built with [Storage](https://liveblocks.io/realtime-apis/storage).
Outside of rooms, you could instead render non-interactive data, for example
with a data-fetching library instead, such as [SWR](https://swr.vercel.app/).

```tsx
function Tags() {
  // `true` if inside a Liveblocks room, `false` otherwise
  const insideRoom = useInsideRoom();

  return insideRoom ? <LiveTags /> : <StaticTags />;
}

function LiveTags() {
  const tags = useStorage((root) => root.tags);

  // ...
}

function StaticTags() {
  const { data: tags } = useSWR("/api/get-tags-from-storage");

  // ...
}
```

## Fetch unread notifications [#fetch-unread-notifications]

When fetching inbox notifications in your back end, you can now filter by unread
notifications, making it easier than before to create email notifications, or
render from your back end.

```ts highlight="4-6"
const { data: unreadInboxNotifications } =
  await liveblocks.getInboxNotifications({
    userId: "steven@example.com",
    query: {
      unread: true,
    },
  });
```

As you can see above, this is made possible by passing an `unread` query option
to
[`liveblocks.getInboxNotifications`](/docs/api-reference/liveblocks-node#get-users-userId-inboxNotifications).

## Better search dialog [#better-search-dialog]

We’ve taken time to upgrade the search dialog in our [documentation](/docs)—it
now searches through more of our website, and is much better at finding results.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-august-24/new-cmdk-menu-blog.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Make sure to try it out next time you’re developing, you can open it with
`Cmd/Ctrl + K` or by pressing the input at the top right of the [docs](/docs).
It’s particularly helpful as it can search through headings on each page, and
will scroll down to the exact section you need.

## Improved canvas examples [#improved-canvas-examples]

We’ve spent some time polishing our canvas-based Comments examples, showing you
how to take care of various edge cases, such as flipping comments before they go
off the edge of the screen. You can try a live demo of our
[Next.js Canvas Comments](/examples/canvas-comments/nextjs-comments-canvas)
example below, a simple example using x/y coordinates.

<div className="relative my-8 flex flex-col gap-2 rounded-xl bg-marketing-surface-faded-subtle p-2 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle md:my-10">
  <div className="relative aspect-video w-full overflow-hidden rounded-md after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
    <Embed
      src="https://nextjs-comments-canvas.liveblocks.app/"
      className="absolute origin-top-left"
      style={{
        width: `${1.2 * 100}%`,
        height: `${1.2 * 100}%`,
        transform: `scale(${1 / 1.2})`,
      }}
    />
  </div>
</div>

We’ve similarly improved
[Next.js Overlay Comments](/examples/overlay-comments/nextjs-comments-overlay),
a complex example which demonstrates how you might attach comments to any HTML
elements, or website, enabling _preview comments_.

<div className="relative my-8 flex flex-col gap-2 rounded-xl bg-marketing-surface-faded-subtle p-2 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle md:my-10">
  <div className="relative aspect-video w-full overflow-hidden rounded-md after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
    <Embed
      src="https://nextjs-comments-overlay.liveblocks.app/"
      className="absolute origin-top-left"
      style={{
        width: `${1.43 * 100}%`,
        height: `${1.43 * 100}%`,
        transform: `scale(${1 / 1.43})`,
      }}
    />
  </div>
</div>

## Upgrade

To use the latest features, update your packages with the following command.

```bash
npx create-liveblocks-app@latest --upgrade
```

If you were previously on Liveblocks 2.1 or below, make sure to follow our
[upgrade guides](/docs/platform/upgrading) before updating.

## More information

This post is a summary of August’s changes, make sure to read our
[Changelog](/changelog) to learn about every change we’ve made, no matter how
minor.

## Contributors

<Contributors
  gitHubUsernames={[
    "ctnicholas",
    "sugardarius",
    "pierrelevaillant",
    "stevenfabre",
    "nimeshnayaju",
    "marcbouchenoire",
    "teddarific",
    "assaadhalabi",
  ]}
/>