The LiveKit Swift SDK automatically handles network disruptions and reconnects to the server when the connection is lost.
Automatic Reconnection
The SDK implements automatic reconnection with two modes:
Quick reconnect : Attempts to resume the existing session
Full reconnect : Creates a new session if quick reconnect fails
No additional code is required—reconnection happens automatically.
Connection States
Monitor connection state changes to update your UI:
class MyRoomDelegate : RoomDelegate {
func room ( _ room : Room, didUpdateConnectionState connectionState : ConnectionState) {
switch connectionState {
case . disconnected :
print ( "Disconnected from room" )
// Show "Disconnected" UI
case . connecting :
print ( "Connecting to room..." )
// Show "Connecting" spinner
case . connected :
print ( "Connected to room" )
// Show normal UI
case . reconnecting :
print ( "Reconnecting..." )
// Show "Reconnecting" indicator
@unknown default :
break
}
}
}
room. add ( delegate : MyRoomDelegate ())
Reconnection Flow
When the connection is lost, the state changes to .reconnecting.
The SDK first attempts a quick reconnect to resume the existing session:
Maintains the same room SID
Preserves published tracks
Minimal disruption to the call
If quick reconnect fails, the SDK performs a full reconnect:
Creates a new session
Re-publishes all tracks
Resubscribes to remote tracks
When reconnected, the state changes back to .connected.
Handling Reconnection in Your App
Show Reconnection UI
Display a reconnection indicator:
func room ( _ room : Room, didUpdateConnectionState connectionState : ConnectionState) {
DispatchQueue. main . async {
if connectionState == .reconnecting {
// Show reconnecting overlay
self . showReconnectingIndicator ()
} else if connectionState == .connected {
// Hide reconnecting overlay
self . hideReconnectingIndicator ()
}
}
}
Detect Reconnect Mode
Determine which reconnect mode is being used:
func room ( _ room : Room, didUpdateConnectionState connectionState : ConnectionState) {
if connectionState == .reconnecting {
if let reconnectMode = room._state.isReconnectingWithMode {
switch reconnectMode {
case . quick :
print ( "Attempting quick reconnect" )
case . full :
print ( "Attempting full reconnect" )
}
}
}
}
Accessing room._state is not part of the public API and may change. Use connectionState for production code.
Track Republishing
After a full reconnect, tracks are automatically republished:
func room ( _ room : Room, participant : LocalParticipant, didPublishTrack publication : LocalTrackPublication) {
print ( "Track published: \( publication. sid ) " )
// This is called for initial publish AND after reconnection
}
Connection Quality
Monitor connection quality for participants:
func room (
_ room : Room,
participant : Participant,
didUpdateConnectionQuality connectionQuality : ConnectionQuality
) {
print ( " \( participant. identity ) : \( connectionQuality ) " )
switch connectionQuality {
case . excellent :
// Green indicator
break
case . good :
// Yellow indicator
break
case . poor :
// Red indicator - connection issues likely
break
case . lost :
// Connection lost
break
@unknown default :
break
}
}
Network Type Monitoring
Monitor network type changes (requires Network framework):
import Network
class NetworkMonitor {
let monitor = NWPathMonitor ()
func startMonitoring () {
monitor. pathUpdateHandler = { path in
if path.status == .satisfied {
if path. usesInterfaceType (. wifi ) {
print ( "Connected via WiFi" )
} else if path. usesInterfaceType (. cellular ) {
print ( "Connected via Cellular" )
}
} else {
print ( "No connection" )
}
}
let queue = DispatchQueue ( label : "NetworkMonitor" )
monitor. start ( queue : queue)
}
}
let networkMonitor = NetworkMonitor ()
networkMonitor. startMonitoring ()
Disconnect Detection
Detect when a disconnect occurs:
func room ( _ room : Room, didUpdateConnectionState connectionState : ConnectionState) {
if connectionState == .disconnected {
// Check if disconnect was due to an error
if let error = room.disconnectError {
print ( "Disconnected with error: \( error ) " )
if let lkError = error as? LiveKitError {
switch lkError.type {
case . webSocket :
print ( "WebSocket error" )
case . network :
print ( "Network error" )
default :
print ( "Other error: \( lkError. type ) " )
}
}
} else {
print ( "Disconnected normally" )
}
}
}
Best Practices
Show a clear reconnection indicator during .reconnecting state
Don’t automatically navigate away from the room during reconnection
Display connection quality indicators for remote participants
Disable publish controls during reconnection
Don’t manually republish tracks—the SDK handles this
Wait for .connected state before publishing new tracks
Handle track unpublish events during full reconnect
Resubscribe to data messages if needed after reconnect
Monitor disconnectError to determine disconnect reason
Log reconnection events for debugging
Implement a manual reconnect button as fallback
Consider showing network type to users (WiFi vs Cellular)
Manual Reconnection
If automatic reconnection fails, allow manual reconnection:
func manualReconnect () async {
do {
// Disconnect first
await room. disconnect ()
// Wait a moment
try await Task. sleep ( nanoseconds : 1_000_000_000 )
// Reconnect
try await room. connect (
url : previousUrl,
token : previousToken
)
} catch {
print ( "Manual reconnect failed: \( error ) " )
}
}
Testing Reconnection
To test reconnection behavior:
Simulate network loss : Enable Airplane Mode briefly
Background/foreground : Send app to background and bring it back
Network switching : Switch between WiFi and Cellular
Poor network : Use Network Link Conditioner (Xcode)
Timeout Configuration
The SDK uses internal timeouts for reconnection attempts. While these aren’t directly configurable, you can detect when reconnection takes too long:
var reconnectTimer: Timer ?
func room ( _ room : Room, didUpdateConnectionState connectionState : ConnectionState) {
if connectionState == .reconnecting {
// Start timeout timer
reconnectTimer = Timer. scheduledTimer ( withTimeInterval : 30 , repeats : false ) { _ in
print ( "Reconnection taking too long, consider manual reconnect" )
// Show manual reconnect option
}
} else if connectionState == .connected {
// Cancel timer if reconnected
reconnectTimer ? . invalidate ()
reconnectTimer = nil
}
}
See Also
Core/Room.swift:84 (connectionState)
Types/ConnectionState.swift
Types/ConnectionQuality.swift