Screen sharing lets a user show their screen, a window, or a browser tab to everyone in the call: a support agent walking a customer through settings, or a teammate presenting slides. This page shows how to start and stop a screen share, and how to show it to others.
Before you start: your app has joined a room with a token that has
publish: true (see Authentication). All code runs
in your app.
| Platform | Supported? |
|---|---|
| Web | Yes |
| Flutter (Android) | Yes |
| Flutter (iOS) | Yes, with a Broadcast Upload Extension (see below) |
| React Native | Not yet |
Start sharing
When you start a share, the browser or OS shows its own picker (which screen, window, or tab). After the user picks, the share is published to the room like any other video track.
await room.enableScreenShare();Or create the track first, then publish it:
const track = await client.createScreenShareTrack();
await room.publish(track);Both use the browser's built-in screen picker (getDisplayMedia()).
await room.enableScreenShare();- Android: works out of the box.
- iOS: you must add a Broadcast Upload Extension target in Xcode.
The package can't add it for you. Without it,
enableScreenShare()throws. See Flutter SDK.
Stop sharing
await room.disableScreenShare();await room.disableScreenShare();It works just like the camera and mic. The difference between muting and unpublishing applies here too. See Audio & Video.
What other people see
A screen share is just another video track. Most apps show it in a big tile, with the presenter's camera small beside it:
- It arrives with
trackSubscribed(orparticipantChangeson Flutter). - You show it the same way as a camera.
- There's no special "screen share" event. Check the track's
kind: it's'screenShare'.
Share the audio too
Sharing a video or a demo with sound? Ask for the audio along with the
screen. It's published as a second track, with the source
screenShareAudio, and stops together with the screen share.
await room.enableScreenShare({ audio: true });
// later: stops the screen and its audio
await room.disableScreenShare();The browser decides whether there is audio. Chrome and Edge offer a "Share tab audio" (or "Share system audio" on Windows and ChromeOS) checkbox in the picker. Firefox and Safari return no audio. If none comes back, the share goes ahead as video only, with no error.
await room.enableScreenShare(audio: true);
participant.isScreenShareAudioEnabled;Only Flutter Web on Chromium returns audio. On iOS and Android
flutter_webrtc's screen capture has no audio, so the share is video only.
room.enableScreenShare(result.data!!, ScreenShareOptions(captureAudio = true))Uses Android's playback capture: Android 10 (API 29) and later, with
RECORD_AUDIO granted. It only hears apps that allow capture (media and
games, never calls). Below Android 10 the option is ignored with a
warning. While the microphone is off, the shared audio is its own
screenShareAudio track. While the microphone is on, Android's WebRTC
has a single recording path, so the shared audio is mixed into the
microphone track (and muting the mic mutes it too).
The Broadcast Upload Extension template
publishes the shared apps' audio (ReplayKit's .audioApp buffers) as a
screenShareAudio track next to the screen. It's on by default; to turn it off,
change ScreenShareHandoff.shareAppAudio to false in the template. The extension's
token needs publishAudio.
In-app room.enableScreenShare() stays video only: inside your app,
WebRTC's one audio input is the microphone, so there is no second source
to publish the app's audio from.
| Platform | Screen-share audio |
|---|---|
| Web (Chrome, Edge) | Yes: a tab, or the whole screen on Windows and ChromeOS |
| Web (Firefox, Safari) | No, the browser returns none |
| Flutter Web (Chromium) | Yes |
| Flutter (iOS, Android) | No |
| Android SDK | Android 10+ (see above) |
| iOS SDK | With the Broadcast Upload Extension; in-app share is video only |
| React Native | No (react-native-webrtc returns no audio track) |
What other people get: a normal audio track. It plays like anyone's
microphone (React's <RoomAudioRenderer> plays it too). It never makes
the presenter the active speaker, so a shared video doesn't take over the
speaker view.
Known issue: a screen share can look like a camera
Sometimes (mostly in Chrome), the server can't tell that a track is a
screen share. It then labels it as a camera. The video still arrives and
plays, but a layout based on track.kind may put the shared screen in the
person's face tile.
The SDK tries to prevent this and logs a warning if it can't. A full fix needs a server change.
Until then: if your layout must be correct, send your own hint, like a data message or participant metadata, instead of relying on the track kind.
Common errors
| Problem | Cause | Fix |
|---|---|---|
| The user cancels the browser's share picker | enableScreenShare() rejects. | Treat it as "the user said no", not a real error. |
enableScreenShare() throws on iOS (Flutter) | No Broadcast Upload Extension. | Add one in Xcode. There's no other way. |
Tips for production
- Only show the "Share screen" button on platforms that support it. Especially check React Native.
- Users can stop sharing from the browser or OS, not just your button. This still fires the normal unpublish event. Listen for it.
Related
- Audio & Video: the enable / disable / mute model this uses.
- Rooms & Participants: the track model.