Recording
In MOQOM a recorder is not a hidden participant. It is a watchdog: an observer attached to a room through the admin API, disclosed to everyone in it, and governed by the room’s recording policy.
Recording policy
Section titled “Recording policy”Every room has a recording policy, set on CreateRoom or changed with UpdateRoomPolicy.
| Policy | Meaning |
|---|---|
allowed |
The default. A recording watchdog may be attached. |
required |
The room is meant to be recorded. Attach your recorder before the room goes live. |
prohibited |
Attaching a recording watchdog is refused with FAILED_PRECONDITION, including from your own backend. |
r := client.Room("board-meeting")_, err := r.UpdatePolicy(ctx, moqom.PolicyUpdate{ Policy: moqom.Policy{Recording: moqom.RecordingProhibited}, Fields: []string{"recording"},})Name recording in the update mask. A policy update without a mask applies every field. See
RoomPolicy.
Attach a recorder
Section titled “Attach a recorder”- Mint your recorder a token for the room with no publish rights, and start it.
- Attach a watchdog of kind
recording, so the room knows it is being recorded and by whom. - Detach it when the recorder stops.
w, err := client.Room("live/42").AttachWatchdog(ctx, moqom.NewWatchdog{ Kind: moqom.WatchdogRecording, OperatedBy: moqom.OperatedByTenant, Descriptor: "This session is recorded by Example Inc.",})// later_, err = client.Room("live/42").DetachWatchdog(ctx, w.ID, moqom.Actor{})| Field | Notes |
|---|---|
Descriptor |
Shown to participants. Write it for a person. |
OperatedBy |
tenant for your own recorder. third_party needs OperatorName, so the room can say who is recording. |
Scope |
A namespace prefix to record, for example one participant. Empty records the whole room. |
PinnedLayer |
Subscribe to one rung of the layer ladder only. |
What the room sees:
- The watchdog is listed in room state with its kind, operator and descriptor, so your app can show a recording indicator. It is never in the roster or the participant count.
Room.is_recordingis true while a recording watchdog is attached and has not failed.- Every attach and detach is written to the room’s moderation log.
- A room’s
watchdog_limit(default 8) caps how many observers can attach.
Billing
Section titled “Billing”A recorder is billed as a subscriber for the bytes it receives, at the same cost-plus rate, capped, as any viewer at the same tier. There is no recording fee. Storage is wherever your recorder writes, so you pay your own storage costs. If the recorder subscribes through a relay you host, only the platform fee applies.
Pin a lower layer (PinnedLayer) if you don’t need full resolution; a recorder that takes the
top rung pays for the top rung.
Recording and end-to-end encryption
Section titled “Recording and end-to-end encryption”Rooms are end-to-end encrypted by default. In an E2EE room, relays and any server-side process see ciphertext only, so MOQOM’s servers cannot record the plaintext of an E2EE room. You have three options:
| Option | Result |
|---|---|
| Your recorder holds the room key | It decrypts like any participant. The recording is plaintext in your storage; MOQOM still sees only ciphertext. The recorder is inside your trust boundary, so treat its host and storage accordingly. |
| Record on the device | A participant’s app records what it already decrypts. Nothing extra leaves the device. |
| Turn E2EE off for the room | Set e2ee to optional with actor.reason. The change is written to the moderation log and announced on the room’s event stream. Media then travels without end-to-end encryption, still protected by TLS 1.3 on every connection. See Turning it off for a room. |
A recorder without the key stores ciphertext it cannot play back. Whichever option you choose, the recording watchdog is disclosed to the room, so participants know they are being recorded.
Related
Section titled “Related”- Moderation: the audit trail that attach and detach are written to.
- Control-plane gRPC API:
AttachWatchdog,DetachWatchdog,ListWatchdogs. - Threat model & controls: hidden observers.