Jitsi

Introducing Multi-screen support for Jitsi Meet

A Jitsi Meet participant has always been one browser window showing one layout. Put that meeting in a conference room with a display on every wall, or on a desk with two monitors, and the extra screens show the same thing the first one does, or nothing at all.

Multi-screen, built as a Google Summer of Code 2026 project, changes that. A single Jitsi Meet session can now render onto more than one display: the active speaker on one screen, a screenshare on another, the whiteboard on a third, without joining the conference twice.

One meeting, three surfaces: the meeting window, plus second screens showing the stage and the whiteboard. Composited from screenshots of each window.

Why not just open the room twice?

Plenty of room deployments do exactly that today. It works, but a second tab is a second participant: it shows up in the roster, it subscribes to and decodes its own copy of every stream, its audio has to be muted by hand, and nothing keeps the two windows in step.

A second screen is a rendering surface on top of the meeting you are already in. One connection to the bridge, one set of media subscriptions, no extra audio path. Nobody else in the meeting can tell it happened.

What a second screen can show

Each of these is a role rather than a fixed stream. A window showing the stage re-points itself as people talk, and a tile grid updates as participants join and leave.

How it works

The interesting problem was rendering into a window the app does not own. A popup opened with window.open is a separate document, but a React portal will happily mount a component tree inside it. So a second screen is not a second app or a copy of anything: it is the same redux store and the same components, rendered through a portal into the popup.

Two things needed special handling:

clone = track.clone();
video.srcObject = new win.MediaStream([ clone ]);

Cloning is cheap and adds no extra decode. It also gives the window a lifetime the feature controls: when the component unmounts, the clone stops.

Driving it from the iframe API

Multi-screen was built for room appliances: displays on the walls and no mouse in the room. So it is controlled through the iframe External API, with one command and three events. The API groundwork landed first, in #17527 by Emil Ivov, and the rendering layer was built on top of it.

// Put the active speaker on one display...
api.executeCommand('setSecondScreen', {
    id: 'wall-left',
    source: { role: 'stage' }
});

// ...and the screenshare on another.
api.executeCommand('setSecondScreen', {
    id: 'wall-right',
    source: { role: 'screenshare' },
    screen: 2
});

// Leaving out the source closes the window.
api.executeCommand('setSecondScreen', {
    id: 'wall-right'
});

The window ids belong to the embedder, so a room controller can address its displays by name and re-target them at any point. Three events report back:

Driving it from inside the meeting

The command covers displays that were configured in advance. The more ordinary case is somebody in a normal meeting with a second monitor. For that, every place in the UI that shows something worth sending now offers to send it: participants get a Show on second screen entry in their context menu, and the screenshare and shared-video thumbnails get a button on hover. Clicking again takes it back.

The same action from three places: a participant’s context menu, the whiteboard tile, and a shared-video thumbnail.

A send never disturbs something you are already watching. It fills a free external display first, and only reuses a window once every display has one. The in-app triggers dispatch the same action as the API command, so an embedder listening to the events sees in-app activity too.

Good to know

Try it

Multi-screen is off by default. Deployments opt in through config:

secondScreen: {
    enabled: true
}

To try it without deploying anything, add #config.secondScreen.enabled=true to a room URL on beta.meet.jit.si, then open any participant’s context menu. The command, the events and the error codes are documented in the handbook.

The work

This work was done as part of Google Summer of Code 2026, mentored by Tudor Avram and Cosmin-Alexandru Timis. Thank you to both for the reviews, several of which changed a design rather than a line, and to the Jitsi community for a summer of work on something I get to keep using.

Share this!