RTMP Streaming / Recording

Want to preserve your video call for posterity in a recording? Or live stream it out to millions of viewers on YouTube, Twitch, Facebook, MUX or whatever gives you an RTMP ingest URL?

Turn on RTMP streaming or recording.

In 100ms, recording and streaming is usually achieved by having a bot join your room and stream what it sees and hears to a file (recording) or to an RTMP ingest URL (streaming). It's also possible to start streaming and recording from server side APIs.

There is another type of SFU based recording as well which allows for all the tracks to be recorded individually, you can find more details about it here.

Start and stop streaming / recording

These are the options which need to be passed to start RTMP or recording -

  1. meetingURL: string. The URL the 100ms bot user will open to join your room. It must allow access without any user level interaction.

  2. rtmpURLs: string[]. Optional, if streaming is required, this has to be one or more RTMP Ingest URLs with max limit of 3 URLs where the stream should go.

    • Format: rtmp://server.com/app/STREAM_KEY
    • Example: rtmp://a.rtmp.youtube.com/live2/k0jv-329m-1y7f-ktth-ck48
      • "rtmp://a.rtmp.youtube.com/live2/" - RTMP stream URL.
      • "k0jv-329m-1y7f-ktth-ck48" - RTMP stream key.
  3. record: boolean. Optional, If recording is required this can be set as true. This value has no effect on streaming.

  4. resolution: { width: number, height: number }. Optional, if passed the recording or RTMP will be done in the passed in resolution.

  • If both rtmpURLs and record = true are provided, both streaming and recording will begin.
  • If only rtmpURLs are provided, only streaming will begin.
  • If only record true is provided, only recording will begin.

If either one is started, the other can't be started without first stopping whatever is running. Eg: Only streaming is started. Recording can't be started unless streaming is stopped first.

If both are required, they have to be started together by providing both RTMP Ingest URLs and recording = true.

async start() { const params = { meetingURL: "", rtmpURLs: [], record: true }; try { await hmsActions.startRTMPOrRecording(params); } catch(err) { console.error("failed to start RTMP/recording", err); } } async stop() { try { await hmsActions.stopRTMPAndRecording(); } catch (err) { console.error("failed to stop RTMP/recording", err); } }

Recording State configuration

export enum HMSRecordingState { NONE = "none", STARTED = "started", STOPPED = "stopped", FAILED = "failed" } // recording state export interface HMSBrowserRecording { running: boolean; startedAt?: Date; state?: HMSRecordingState; error?: HMSException; }

RTMP State configuration

export enum HMSStreamingState { NONE = "none", STARTED = "started", STOPPED = "stopped", FAILED = "failed" } // rtmp state export interface HMSRTMP { running: boolean; startedAt?: Date; state?: HMSStreamingState; error?: HMSException; } // recording state export interface HMSBrowserRecording { running: boolean; startedAt?: Date; state?: HMSRecordingState; error?: HMSException; }

Current Recording/RTMP State

As it is with everything else in the 100ms web world, we've selectors to tell us about the current state of the room, whether recording or streaming is already going on and if recording is happening, which type of recording is currently running.

const recordingState = hmsStore.getState(selectRecordingState); const rtmpState = hmsStore.getState(selectRTMPState); console.log('is sfu recording going on - ', recordingState.server.running); if (recordingState.browser.running) { console.log('time when browser recording was started - ', recordingState.browser.startedAt); } else if (recordingState.browser.error) { console.error('error in browser recording - ', recordingState.browser.error); } if (rtmpState.running) { console.log('time when RTMP was started - ', rtmpState.startedAt); } else if (rtmpState.error) { console.error('error in RTMP streaming - ', rtmpState.error); }


  • If you're using the dashboard web-app from 100ms, please make sure to use a role which doesn't have publish permissions for beam tile to not show up. The meeting URL can be edited in the streaming/recording popup to join with a recording specific role configured as such.
  • If using your own web-app, do put in place retries for API calls like tokens etc. just in case any call fails. As human users we're used to reloading the page in these scenarios which is difficult to achieve in the automated case.
  • Make sure to not disable the logs for the passed in meeting URL. This will allow for us to have more visibility into the room, refreshing the page if join doesn't happen within a time interval.

Have a suggestion? Recommend changes ->

Was this helpful?