Skip to main content
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

1
Connection Lost
2
When the connection is lost, the state changes to .reconnecting.
3
Quick Reconnect Attempt
4
The SDK first attempts a quick reconnect to resume the existing session:
5
  • Maintains the same room SID
  • Preserves published tracks
  • Minimal disruption to the call
  • 6
    Full Reconnect
    7
    If quick reconnect fails, the SDK performs a full reconnect:
    8
  • Creates a new session
  • Re-publishes all tracks
  • Resubscribes to remote tracks
  • 9
    Connection Restored
    10
    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)
    • Quick reconnect is much faster than full reconnect
    • Reduce track bitrates during poor connection quality
    • Consider disabling video during cellular reconnects
    • Implement adaptive bitrate based on connection quality

    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:
    1. Simulate network loss: Enable Airplane Mode briefly
    2. Background/foreground: Send app to background and bring it back
    3. Network switching: Switch between WiFi and Cellular
    4. 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

    Build docs developers (and LLMs) love