Schema 3.0.0

3.0.0 was a complete rewrite. It is the baseline every later 3.x release is additive against, and it is not compatible with 2.x data or 2.x tooling.

What changed conceptually

The sample mirrors getStats()

2.x modelled monitoring data as a set of hand-designed report types — InboundAudioTrack, OutboundVideoTrack, ClientTransport and so on — each a curated selection of fields. Every time the W3C stats spec moved, the mapping had to be renegotiated, and fields drifted in and out (the 2.1.0 changelog removed more than thirty of them in one release).

3.0.0 inverts that. PeerConnectionSample carries the W3C stats dictionaries themselves, one array per stats type:

PeerConnectionSample
├─ inboundTracks[]              outboundTracks[]
├─ inboundRtps[]                outboundRtps[]
├─ remoteInboundRtps[]          remoteOutboundRtps[]
├─ mediaSources[]               mediaPlayouts[]
├─ codecs[]                     dataChannels[]
├─ iceTransports[]              iceCandidates[]
├─ iceCandidatePairs[]          peerConnectionTransports[]
└─ certificates[]

Adding a field the spec added becomes a minor release, not a design discussion.

One sample type per producer

ClientSample, SfuSample and TurnSample — the client-side one being the primary path, with client-monitor-js producing it and observer-js consuming it.

Scores and attachments are first-class

Every level — client, peer connection, track — carries:

  • score (0–5) and scoreReasons for computed quality with a machine-readable explanation
  • attachments for application data, so a track can be “Alice’s screen share” rather than an opaque SSRC

That last one is what makes server-side publisher ↔ subscriber correlation possible at all — the resolver reads producerId / consumerId out of track attachments.

Application-level payloads travel with the stats

clientEvents, clientIssues, clientMetaItems and extensionStats ride in the same sample as the WebRTC statistics, so an event and the stats interval it occurred in arrive together and cannot be misaligned by a separate transport.

The 3.0.0 record set

GroupRecords
Top levelClientSample, PeerConnectionSample
TracksInboundTrackSample, OutboundTrackSample
RTPInboundRtpStats, OutboundRtpStats, RemoteInboundRtpStats, RemoteOutboundRtpStats
MediaMediaSourceStats, MediaPlayoutStats, CodecStats
TransportPeerConnectionTransportStats, DataChannelStats, IceTransportStats, IceCandidateStats, IceCandidatePairStats, CertificateStats
ApplicationClientEvent, ClientIssue, ClientMetaData, ExtensionStat
Other producersSfuSample, TurnSample, Samples

Full field reference: ClientSample.

Generated outputs

FormatLocation
TypeScript type definitionsoutputs/typescript/
Protocol Buffersoutputs/proto/
Flattened Avro (all chunks expanded)outputs/avsc/
Markdown field referenceschemaList.md
npm: core types@observertc/schemas
npm: binary encoding@observertc/samples-encoder
npm: binary decoding@observertc/samples-decoder

Migrating from 2.x

This is not an in-place upgrade

2.x report types have no mechanical mapping to 3.x samples — the model changed, not just the field names. In practice, migration means:

  1. Upgrade the client library to a 3.x-schema client-monitor-js (the 4.x line).
  2. Treat 2.x archives as a separate, frozen dataset rather than converting them.
  3. Rewrite server-side processing against the W3C-shaped stats arrays.
  4. Move any custom fields you had added into attachments on the appropriate record.

The 2.x history remains in the CHANGELOG if you need to interpret archived data.

← Back to version history