OBSERVERTC / Client Monitor

Configuration

Use verified defaults and complete detector overrides.

Configuration controls how often the monitor reads statistics, which problems it detects, and what it includes in samples. Start with the defaults, then change settings for a concrete requirement: faster local feedback, less traffic, or a detector that needs different thresholds for your product.

Configure a monitor

const monitor = new ClientMonitor({
  clientId: 'participant-42',
  callId: 'room-123',
  collectingPeriodInMs: 1000,
  samplingPeriodInMs: 5000,
  congestionDetector: null,
});

This example collects every second, sends a sample every five seconds, and disables the deprecated congestion detector. It leaves the other detectors at their defaults. Faster collection increases the work done by getStats() and changes how much time a detection window covers.

Identity and local application data

OptionWhat it is for
clientIdIdentify this monitored endpoint. Supply an application identifier when sending to Observer.
callIdGroup this endpoint with other clients in the same call. Required for Observer ingestion.
appDataKeep application-owned working state locally. Use serializable attachments for data that should be sent.
loggerRoute monitor diagnostics through your application logger.

Collection and sample settings

OptionDefaultWhat changes when you set it
collectingPeriodInMs5000Time between browser-stat updates. 0 disables automatic collection.
samplingPeriodInMs5000Requested interval for creating samples. Use a multiple of collection cadence; 0 disables automatic sampling.
bufferingEventsForSamplesfalseRetain discrete records for manual samples when automatic sampling is off.
bufferClientSamplesUntilSubscriberfalseKeep samples until the first sample listener attaches. Prefer attaching listeners early.

See collection and sampling for manual collection and sample boundaries.

Browser integration settings

OptionDefaultPurpose
integrateNavigatorMediaDevicestrueFollow media-device activity. Can also receive a MediaDevices instance.
watchTabVisibilitytrueTrack whether the tab is hidden so detectors can account for browser throttling.
addClientJointEventOnCreatedtrueRecord the client’s join when the monitor is created. The API spelling is Joint.
addClientLeftEventOnClosetrueRecord departure when the monitor closes.

Sample detail settings

OptionDefaultPurpose
sendResolvedIssuesToServertrueInclude keyed raises and resolutions so a backend can maintain active issue state.
sendScoreReasonsToServertrueInclude peer-connection and track penalty breakdowns. Scores remain available when disabled.
sendSdpMetadataToServerfalseOpt in to sending session descriptions as metadata, with ICE passwords redacted. SDP-derived monitor fields remain available when disabled.
sendIceTransportMetadataOnChangeOnlytrueSend mostly static transport metadata initially and on change rather than repeating it in every sample.

How detection windows work

A single bad measurement can be a brief fluctuation. Detection windows keep a recent sequence of measurements so detectors can judge sustained behavior. Recovery windows let them check whether a problem has settled before clearing it. These windows hold collected values, not outgoing samples.

With the default five-second collection interval, three values span two intervals, or about 10 seconds between the oldest and newest value. Four values span about 15 seconds. Collecting every second shortens those spans to two and three seconds. A detector can also use an independent time threshold or require other evidence, so these spans are not promises of an exact alert delay.

Window optionDetection valuesRecovery valuesApplies to
clientWindow33Measurements of the overall client.
peerConnectionWindow33Measurements of an individual connection.
outboundTrackWindow33Sending/capture measurements for a track.
inboundTrackWindow33Receiving/playout measurements for a track. Also has flowDetection: 4 and flowRecovery: 3 for media-flow evaluation.

maxAllowedGapInMs defaults to four times a positive collection interval (20 seconds at the normal cadence). A gap larger than this prevents stale measurements from being treated as a continuous run. Think of a laptop waking from sleep: measurements before sleep should not be joined to the first measurement after wake as if the call had been continuously observed.

const monitor = new ClientMonitor({
  collectingPeriodInMs: 1000,
  inboundTrackWindow: {
    numberOfSamples: {
      detection: 3,
      recovery: 3,
      flowDetection: 4,
      flowRecovery: 3,
    },
    maxAllowedGapInMs: 4000,
  },
});

Supply the complete window object when overriding it. Tune against real sessions: shorter windows respond sooner but can react to transient fluctuations; longer windows need more evidence and react later.

Enable, disable, or tune a detector

Supplied valueResult
Omitted or undefinedUse the built-in configuration.
nullDisable this detector.
Configuration objectReplace its default object with your object.

Nested objects are not deep-merged. Copy the complete detector configuration before changing a threshold; {} is only appropriate when that detector has no required tunables. BlockedInboundMediaDetector is off by default because its evidence is not generally available with browser RTCP multiplexing. The deprecated CongestionDetector remains enabled by default in 4.10.1.

Detector option reference

The table below lists every detector option and its complete default settings in Client Monitor 4.10.1. Values ending in InMs are milliseconds; ratios are fractions unless the detector guide states otherwise. Use the detector catalog to understand the evidence before tuning a number. Newer installed versions can add or change options; their TypeScript configuration is the authority for that version.

OptionDefault settings
iceReachabilityDetectorthresholdInMs: 6000
iceTraversalDetectorNo thresholds
icePathEstablishmentDetectorthresholdInMs: 5000; createEvent: true
iceEstablishmentFailedDetectorthresholdInMs: 15000
dtlsHandshakeFailedDetectorNo thresholds
dtlsHandshakeStalledDetectorstalledThresholdInMs: 6000
iceDisconnectedDetectordisconnectedThresholdInMs: 5000
iceConnectionFailedDetectorNo thresholds
iceTransportStalledDetectortransportStallThresholdInMs: 5000
unstableIcePathDetectorpathSwitchWindowInMs: 30000; pathSwitchThreshold: 3
iceRestartDetectorcreateEvent: true
iceRestartRecommendationDetectorcreateEvent: true; iceRestartRecommendationThresholdInMs: 10000; iceRestartRecommendationCooldownInMs: 15000; restartRecommendationThresholdInMs: 10000; restartRecommendationCooldownInMs: 15000
congestionDetectorsensitivity: 'medium' as const
uplinkCongestionDetectorminSeverity: 0.65; pacerBloatingSaturatesAt: 4
downlinkCongestionDetectorminSeverity: 0.65; bufferBloatingSaturatesAt: 4
transportDelayDetectorthresholdInMs: 300; recoveryThresholdInMs: 200
transportLossDetectorthreshold: 0.05; recoveryThreshold: 0.01; durationInMs: 6000
blockedStunRequestsDetectorresponseReceivedTimeoutInMs: 10000; requestsSentTimeoutInMs: 10000
blockedOutboundMediaDetectorthresholdInMs: 10000
blockedInboundMediaDetectornull
captureSourceLostDetectorcreateEvent: true
silentAudioSourceDetectorsilenceThresholdInMs: 60000; silenceRmsThreshold: 0.0001; recoveryRmsThreshold: 0.0003
loopbackAudioInputDetectorBuilt-in loopback-device label patterns; see the release configuration source for the array
videoCaptureBottleneckDetectorproduceDegradationThreshold: 0.2
encoderBottleneckDetectorencodeDegradationThreshold: 0.3
rtpSenderStalledDetectorthresholdInMs: 4000
dryOutboundTrackDetectorthresholdInMs: 5000
transportDemuxStalledDetectorthresholdInMs: 4000; minTransportReceiveBitrateBps: 20000
dryInboundTrackDetectorthresholdInMs: 5000
frameAssemblyStalledDetectorthresholdInMs: 3000; minPacketsReceived: 20
decoderBottleneckDetectordecodeDegradationThreshold: 0.1; minReceivedFps: 5
decoderPerformanceDetectordecodeTimeBudgetRatio: 0.8; minFramesReceived: 10; quietLossThreshold: 0.02; minConsecutiveTicks: 2
stuckDecoderDetectorthresholdInMs: 4000; rttMultiplier: 15; minBitrate: 10000; minPliCount: 2
playoutDiscrepancyDetectorlowSkewRatio: 0.1; highSkewRatio: 0.25; minFramesReceived: 10
videoRecoveryFailedDetectorrecoveryFailedThresholdInMs: 5000; recoveryFailedMinPliCount: 2
cpuPerformanceDetectorutilizationThreshold: 0.5; recoveryThreshold: 0.4
pixelatedVideoDetectorthreshold: 0.62; recoveryThreshold: 0.52; durationInMs: 8000
inboundVideoFlowStateDetectorfrozenAfterInMs: 2000; minFreezeCountForChoppy: 2
concealedSamplesDetectorallowedConcealedRatio: 0.05; raiseAfterConcealedMs: 400
audioInterruptionDetectorallowedInterruptedRatio: 0.02; raiseAfterInterruptedMs: 500
audioPlayoutSynthesisDetectorsynthesizedRatioThreshold: 0.05; createEvent: true
avDesyncPlayoutDetectoraudioAheadRaiseInMs: 90; audioAheadResolveInMs: 45; audioBehindRaiseInMs: 185; audioBehindResolveInMs: 125; sustainForInMs: 3000
jitterBufferStressDetectortargetDelayThresholdInMs: 200; timeStretchThreshold: 0.02; minConsecutiveTicks: 2; unbearableTargetDelayInMs: 1000; unbearableTimeStretchRate: 0.15
captureTrackMutedDetectorcreateEvent: true
codecChangeDetectorcreateEvent: true
videoResolutionChangeDetectorcreateEvent: true
simulcastLayerDetectorcreateEvent: true
statsGapDetectorgapRatioThreshold: 2; minGapInMs: 5000; createEvent: true

Detailed detector types and implementation evidence.

Sources: ClientMonitor constructor, ClientMonitorConfig, Detectors.

Version coverage varies by reference. Source revisions · Markdown source