# Live (LiveKit rooms): moving from the room page to the call widget unsubscribes you from everyone's video (black tiles) - w/ proposed fix

**URL:** <https://meta.discourse.org/t/live-livekit-rooms-moving-from-the-room-page-to-the-call-widget-unsubscribes-you-from-everyones-video-black-tiles-w-proposed-fix/417380>\
**Category:** Bug\
**Tags:** live\
**Created:** [November 13, 2026, 6:00pm UTC](https://meta.discourse.org/t/live-livekit-rooms-moving-from-the-room-page-to-the-call-widget-unsubscribes-you-from-everyones-video-black-tiles-w-proposed-fix/417380 "2026-11-13T18:00:52Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![sperry](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sperry/32/584571_2.png) [@sperry](https://meta.discourse.org/u/sperry)\
**Post date:** [November 13, 2026, 6:00pm UTC](https://meta.discourse.org/t/live-livekit-rooms-moving-from-the-room-page-to-the-call-widget-unsubscribes-you-from-everyones-video-black-tiles-w-proposed-fix/417380/1 "2026-11-13T18:00:52Z")

</div>

Hi all, first time contributor, so sorry if I’m not formatting this the proper way.

I’m setting up a Discourse forum for an automotive enthusiast group and they wanted to use Live video chats via LiveKit for larger rooms/presentations.

During testing we consistently ran into black tiles for video streams, but only when using the LiveKit integration. I used Claude Code to investigate and found what looks like the issue and a fix, the Claude generated report follows.

I’m happy to make a PR with a proposed fix if that would be helpful.

**Summary**

In a LiveKit (SFU) room, going from the room page to the floating call widget leaves the viewer with black tiles for everyone else. The other participants still see the viewer fine. Going back to the room page, or leaving and rejoining while in the widget, brings the video back. It happens every time, because the room page’s teardown sends `watching=false` _after_ the widget has sent `watching=true`.

**Version**

- Discourse at commit `1f09a33bffd908d6e38ef4b51697e8390e2a4c7f` (the `latest` branch, 2026-10), Live plugin as bundled
- LiveKit Cloud as the media server (`live_livekit_room_policy = per_room`)
- Firefox 159 on Linux (also observed on other browsers and phones)

**Steps**

1. Two accounts (one in a private window) join the same LiveKit-enabled room with cameras on.
2. In one window, click a link that leaves the room page, so the call moves to the widget.
3. In that window the other participant’s tile is black. The other window sees both fine.

**What I saw**

- In the black window, the other person’s `<video>` has a stream, is not paused and has `readyState` 4. But its track is `readyState: "live"`, `muted: true`, `8×8`, and `getVideoPlaybackQuality().totalVideoFrames` is 0. No media ever arrived on it.
- Network tab, one page → widget switch: three `POST /live/rooms/<id>/state` calls, with `watching` = **true, true, false** in that order.

**Cause (from reading the code at the commit above)**

- `room-page.gjs`, `willDestroy`: `next(() => liveWebrtc.setWatching(roomId, false, { keepVideo }))`
- `call-widget.gjs`: the widget’s `didInsert` calls `watchWidgetRoom`, which runs `next(() => setWatching(roomId, true))`
- `live-webrtc.js`, `setWatching`: on non-mesh rooms it calls `setVideoSubscriptionsEnabled(watching)`, which unsubscribes the viewer’s camera, screen and screen-audio tracks (`livekit-session.js`, `#applyDesiredSubscription`)

The page’s deferred `false` lands after the widget’s `true`, so the viewer ends up in the not-watching state while the widget is on screen. Going widget → room page works because the widget’s `stopWatchingWidgetRoom` runs synchronously on destroy and the page’s `true` is deferred, so `true` wins. A fresh join in the widget works because there is no old page.

Peer-to-peer rooms don’t unsubscribe anyone (the SFU branch is skipped), which would match this being specific to LiveKit rooms.

**Confirmed workaround, in the browser console**

1. With the tile black, `Discourse. __container__.lookup("service:live-webrtc").setWatching(1, true)` brought the video back.
2. This wrapper, installed before switching, kept the tile up on every page → widget switch:

```js
const svc = Discourse. __container__.lookup("service:live-webrtc");
const orig = svc.setWatching.bind(svc);
svc.setWatching = (roomId, watching, options = {}) => {
  if (watching) return orig(roomId, true, options);
  setTimeout(() => {
    const shown = document.querySelector(".live-call-widget, .live-room-page");
    orig(roomId, !!shown, options);
  }, 500);
};

```

**Suggested fix**

The room page’s teardown shouldn’t turn watching off when the widget is about to show the same room. For example, derive the watching state from whether the page or the widget is mounted, instead of letting each send its own set/clear. That way ordering can’t matter.

**Related, may be separate**

One `POST .../state` in the same session was answered with **429**. Failures on these calls are ignored (`.catch(() => {})`), so a refused “watching” update fails silently.

---

_[View the full topic](https://meta.discourse.org/t/live-livekit-rooms-moving-from-the-room-page-to-the-call-widget-unsubscribes-you-from-everyones-video-black-tiles-w-proposed-fix/417380)._
