← Back to Integrations with 3rd parties

LiveKit

Add rtcstats-js to a LiveKit app with a singleton wrapper and three insertion points.

LiveKit's JavaScript SDK creates its peer connections through the browser's global RTCPeerConnection. rtcstats-js collects data by monkey-patching that same global. Patch once at startup, and every session LiveKit creates gets traced automatically - no forking, no internal hooks.

This guide shows how to add rtcstats-js to the livekit-client demo (examples/demo), but the pattern works in any LiveKit app.

Before you start

You need:

  • A running rtcstats-server (local or deployed)
  • A LiveKit app using livekit-client (the demo works out of the box)
  • A signed rtcstats token (not the LiveKit token - these are separate auth systems)

Generate a token for local testing:

node bin/generate-token.js -u ws://localhost:8080/

This prints the full WebSocket URI with the token embedded. For production, mint tokens server-side. See the JWT-based authorization docs.

Step 1: install and create the singleton wrapper

npm install @rtcstats/rtcstats-js

Create a file (e.g. rtcstats.ts) that patches the globals once and exposes connect/close:

import { wrapRTCStatsWithDefaultOptions } from '@rtcstats/rtcstats-js';

type Trace = ReturnType<typeof wrapRTCStatsWithDefaultOptions>;
let trace: Trace | undefined;

export function initRTCStats(): Trace | undefined {
  if (typeof window === 'undefined') return undefined;
  if (!trace) {
    trace = wrapRTCStatsWithDefaultOptions();
  }
  return trace;
}

export function connectRTCStats(url: string): void {
  const t = initRTCStats();
  if (t) t.connect(url);
}

export function closeRTCStats(): void {
  trace?.close();
}

The if (!trace) guard prevents double-wrapping if the module is imported from multiple places.

Step 2: wire it into your LiveKit app

Three insertion points. The order matters.

At startup - patch globals before anything creates a peer connection:

import { closeRTCStats, connectRTCStats, initRTCStats } from './rtcstats';

initRTCStats();

const RTCSTATS_WS_URL = 'ws://localhost:8080/?rtcstats-token=<your-rtcstats-jwt>';

On connect - open a dump before prepareConnection (which prewarms a peer connection):

const room = new Room(roomOptions);

connectRTCStats(RTCSTATS_WS_URL);

await room.prepareConnection(url, token);

On disconnect - close the dump in your RoomEvent.Disconnected handler:

function handleRoomDisconnect(reason?: DisconnectReason) {
  closeRTCStats();
  // ... rest of your cleanup
}

One connectRTCStats call opens one dump file. One closeRTCStats call closes it. Everything in between is captured.

Verify it works

With rtcstats-server running, connect a LiveKit session. The server logs one accept on connect and one disconnect when the room closes:

Accepted new connection with uuid 93a750f8-223a-4c64-a39f-4c01f2731ae3
Connection with uuid 93a750f8-223a-4c64-a39f-4c01f2731ae3 disconnected, starting to process data

That pair confirms the dump opened and was processed. Your session data is now flowing to rtcstats-server.

NOTE: Can't get this to work? Need help? mailto:support@rtcstats.com

Was this page helpful?