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) andscoreReasonsfor computed quality with a machine-readable explanationattachmentsfor 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
| Group | Records |
|---|---|
| Top level | ClientSample, PeerConnectionSample |
| Tracks | InboundTrackSample, OutboundTrackSample |
| RTP | InboundRtpStats, OutboundRtpStats, RemoteInboundRtpStats, RemoteOutboundRtpStats |
| Media | MediaSourceStats, MediaPlayoutStats, CodecStats |
| Transport | PeerConnectionTransportStats, DataChannelStats, IceTransportStats, IceCandidateStats, IceCandidatePairStats, CertificateStats |
| Application | ClientEvent, ClientIssue, ClientMetaData, ExtensionStat |
| Other producers | SfuSample, TurnSample, Samples |
Full field reference: ClientSample.
Generated outputs
| Format | Location |
|---|---|
| TypeScript type definitions | outputs/typescript/ |
| Protocol Buffers | outputs/proto/ |
| Flattened Avro (all chunks expanded) | outputs/avsc/ |
| Markdown field reference | schemaList.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:
- Upgrade the client library to a 3.x-schema
client-monitor-js(the 4.x line). - Treat 2.x archives as a separate, frozen dataset rather than converting them.
- Rewrite server-side processing against the W3C-shaped stats arrays.
- Move any custom fields you had added into
attachmentson the appropriate record.
The 2.x history remains in the CHANGELOG if you need to interpret archived data.