Skip to content

Reconnection

The SDK handles transient network drops automatically. You don't need to write reconnect logic — just listen to the events.

Automatic Reconnect

When LiveKit detects a network interruption, the SDK transitions through:

connected → reconnecting → connected  (success)
connected → reconnecting → disconnected  (failure after retries)
ts
call.on('reconnecting', (attempt) => {
  showBanner(`Connection lost — reconnecting (attempt ${attempt})`)
})

call.on('reconnected', () => {
  hideBanner()
})

call.on('disconnected', (reason) => {
  if (reason === 'networkError') {
    showError('Could not reconnect. Please rejoin.')
  }
})

LiveKit's client SDK handles the underlying WebSocket and ICE renegotiation. The RTCstack SDK surfaces the events; LiveKit manages the retry timing (exponential backoff with jitter, configurable in livekit-client options).

Token Refresh on Reconnect

If the JWT is near expiry when a reconnect happens, the SDK calls tokenRefresher to get a fresh token before reconnecting. Wire it up at call creation:

ts
const call = createCall({
  token,
  url,
  tokenRefresher: async () => {
    const res = await fetch('/api/refresh-token', { method: 'POST' })
    const { token } = await res.json()
    return token
  },
})

Without tokenRefresher, a reconnect attempt with an expired token will fail and emit disconnected.

Token Expiry

ts
call.tokenExpiresAt  // Date

call.on('tokenExpired', () => {
  // Token is within the expiry window
  // If tokenRefresher is set, the SDK handles this automatically
  // Listen here only if you want to show a warning UI
})

Connection State

ts
call.connectionState
// 'idle'          — createCall() called, connect() not yet called
// 'connecting'    — connect() called, waiting for LiveKit
// 'connected'     — active call
// 'reconnecting'  — temporary drop, retrying
// 'disconnected'  — call ended or unrecoverable error

Detecting Poor Connection

Per-participant connection quality is available:

ts
call.participants.forEach((p) => {
  console.log(p.name, p.connectionQuality)
  // 'excellent' | 'good' | 'poor' | 'lost' | 'unknown'
})

The local participant's quality is at:

ts
call.localParticipant?.connectionQuality

Use connectionQuality === 'poor' to show a warning icon in your UI.

Mobile Backgrounding

On iOS and Android, backgrounding a tab suspends WebSocket connections. The SDK will emit reconnecting when the tab comes back to the foreground. Surface a non-intrusive indicator so users know the call is recovering.

ts
call.on('reconnecting', () => {
  // Show: "Reconnecting..."
})

call.on('reconnected', () => {
  // Hide indicator
})