Table of Contents

    Book an Appointment

    How Do Engineering Teams Encounter Jitsi React Native SDK Freezes in Telehealth Apps?

    While building a scalable telehealth platform, seamless real-time communication is non-negotiable. During a recent project, our engineering team integrated the jitsi react native sdk to power HIPAA-compliant virtual consultations. The initial development in our React Native environment (version 0.82.1) went smoothly, but during staging tests on iOS devices, we uncovered a critical performance bottleneck.

    We realized that when opening the video meeting for the first time—or when a remote participant (such as a medical professional) joined an active meeting—the application screen completely froze. This main thread block lasted for upwards of two minutes. During this freeze, the iOS application was entirely unresponsive, dropping frames and preventing users from interacting with any UI elements.

    A two-minute UI lockup in production destroys user trust, especially in urgent healthcare scenarios. Understanding why the react native video call was stalling required a deep dive into how heavy native modules initialize, how JavaScript thread delays interact with iOS UI threads and how WebRTC handles ICE candidate gathering during participant joins. This challenge inspired this technical breakdown so other engineering teams can avoid similar thread deadlocks and gracefully manage heavy native SDK lifecycle events.

    Where Do React Native Video Call Architectures Typically Break Down?

    To understand the root cause, we must look at the architectural requirements of the business use case. The application required on-demand, secure video rooms where patients could wait for their assigned doctors. The underlying architecture relied on React 19.1.1, the Jitsi Native SDK and react-native-webrtc.

    In the original implementation, the component housing the Jitsi meeting view was wrapped in a functional component. Because navigating to this screen involved an interactive popup animation, the previous engineers had implemented a 1200-millisecond setTimeout to delay the mounting of the heavy native view. They also triggered a synchronous request for iOS Camera and Microphone permissions just before allowing the component to render.

    While this logic seems sound for a standard web application, in a mobile architecture, combining arbitrary JavaScript timers, native permission overlays and a massively heavy native view initialization (WebRTC bindings, audio session configuration and video encoders) creates a perfect storm for bridge congestion. When organizations hire app developer to create a mobile app, it is crucial to ensure that the development team understands how asynchronous JavaScript callbacks interact with strict native thread requirements on iOS.

    Why Does the iOS Main Thread Block During Jitsi SDK Initialization?

    When investigating the symptoms, we observed that CPU usage spiked to 100% on the main thread, while the JavaScript thread remained surprisingly idle. The logs revealed a bottleneck during the Jitsi SDK’s WebRTC initialization phase.

    Several underlying architectural oversights contributed to this massive freeze:

    • Arbitrary Timers Colliding with UI Updates: The 1200ms setTimeout fired indiscriminately. If the timer elapsed while the iOS UI thread was busy cleaning up the previous animation frame or displaying the native OS permission dialog, the sudden command to mount a complex native view caused a thread deadlock.
    • Audio Session Interruptions: iOS handles audio categories strictly. By default, Jitsi attempts to grab the AVAudioSession. When a new participant joins, WebRTC negotiates new ICE candidates and audio streams. Because the app was unnecessarily passing CallKit flags without a full CallKit integration, iOS forced the main thread to wait for audio session resolution, pausing all UI rendering.
    • Permission Blocking: Triggering iOS native permission prompts inside a React useEffect right before mounting a heavy WebRTC component creates a race condition. The OS pauses certain application execution states while waiting for the user’s permission selection.

    What Diagnostic Steps Can Resolve the Jitsi React Native SDK Freeze?

    We launched Xcode Instruments (specifically the Time Profiler) to trace the native method calls causing the lockup. We needed to isolate whether the freeze was happening within the JS-to-Native bridge or purely within native Objective-C/Swift execution. Based on our findings, we tested several architectural approaches. If you are looking to hire react native developers for native module integrations, these are the diagnostic steps you should expect them to execute.

    Can Adjusting the JavaScript Timeout Delay Fix the Screen Freeze?

    Our first hypothesis was that 1200ms was simply the wrong arbitrary delay. We considered removing the setTimeout entirely or increasing it. However, removing it caused the navigation animation to stutter heavily, as rendering the Jitsi view consumes significant CPU cycles. Increasing it only delayed the inevitable freeze. We concluded that setTimeout is inherently anti-pattern for sequencing native UI mounts.

    Does Disabling CallKit Flags Improve React Native Video Call Stability?

    Next, we analyzed the configuration flags passed to the SDK. The initial implementation passed several basic flags, but left audio routing and CallKit integration ambiguous. We explicitly disabled call-integration.enabled and pip.enabled, which reduced the severity of the freeze upon a participant joining, but the initial two-minute mount freeze remained. This indicated the core issue was lifecycle and rendering synchronization, not just audio session locking.

    Will InteractionManager Offload the Heavy Native SDK Initialization?

    React Native provides a built-in utility specifically designed for this scenario: InteractionManager. Instead of relying on a blind timer, we considered wrapping the mounting logic inside InteractionManager.runAfterInteractions(). This ensures that the heavy Jitsi component only mounts after all navigation and popup animations are completely finalized on the native UI thread, preventing CPU contention.

    How Can We Optimize the Final React Native Video Call Implementation?

    The final solution required a holistic refactor of the mounting lifecycle, separating the permission requests from the rendering pipeline and utilizing React Native’s interaction lifecycle properly. We also tuned the Jitsi configuration flags to prevent the native SDK from fighting for UI thread resources during ICE negotiation.

    Here is the sanitized, optimized implementation that resolved the freezing issue completely:

    import React, { useEffect, useState, useCallback } from 'react';
    import { JitsiMeeting } from '@jitsi/react-native-sdk';
    import { View, ActivityIndicator, Platform, InteractionManager } from 'react-native';
    import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
    const VideoCallScreen = ({ room, token, serverURL }) => {
      const [isReadyToMount, setIsReadyToMount] = useState(false);
      const [permissionsGranted, setPermissionsGranted] = useState(Platform.OS !== 'ios');
      // Step 1: Isolate and resolve permissions before doing anything else
      const checkAndRequestPermissions = useCallback(async () => {
        if (Platform.OS !== 'ios') return true;
        try {
          const cameraResult = await request(PERMISSIONS.IOS.CAMERA);
          const micResult = await request(PERMISSIONS.IOS.MICROPHONE);
          return cameraResult === RESULTS.GRANTED && micResult === RESULTS.GRANTED;
        } catch (error) {
          console.error('Failed to request native iOS permissions:', error);
          return false;
        }
      }, []);
      useEffect(() => {
        if (!room) return;
        let isMounted = true;
        let interactionTask;
        const initializeMeetingData = async () => {
          const hasPermissions = await checkAndRequestPermissions();
          if (isMounted) {
            setPermissionsGranted(hasPermissions);
          }
          // Step 2: Use InteractionManager instead of setTimeout
          // This ensures all native UI animations finish before we stress the CPU
          interactionTask = InteractionManager.runAfterInteractions(() => {
            if (isMounted && hasPermissions) {
              setIsReadyToMount(true);
            }
          });
        };
        initializeMeetingData();
        return () => {
          isMounted = false;
          if (interactionTask) {
            interactionTask.cancel();
          }
        };
      }, [room, checkAndRequestPermissions]);
      if (!isReadyToMount || !permissionsGranted) {
        return (
          <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000' }}>
            <ActivityIndicator size="large" color="#4A90D9" />
          </View>
        );
      }
      // Step 3: Explicitly define flags to prevent iOS audio session deadlocks
      return (
        <View style={{ flex: 1, backgroundColor: 'black' }}>
          <JitsiMeeting
            userInfo={{ displayName: 'Telehealth Patient' }}
            flags={{
              'call-integration.enabled': false, // Prevents CallKit thread locking
              'pip.enabled': false,
              'welcomepage.enabled': false,
              'prejoinpage.enabled': false,
              'video-muted-indicator.enabled': true,
              'ios.screensharing.enabled': false // Disable unless explicitly configured
            }}
            config={{
              startWithAudioMuted: false,
              startWithVideoMuted: false,
              subject: 'Confidential Consultation',
              disableSimulcast: false,
            }}
            room={room}
            serverURL={serverURL}
            token={token || undefined}
            style={{ flex: 1 }}
          />
        </View>
      );
    };
    export default React.memo(VideoCallScreen);
    

    What Can Engineering Teams Learn About Scaling React Native Video Calls?

    Resolving complex issues with native UI threading requires strict adherence to mobile performance paradigms. Here are actionable insights engineering teams can extract from this resolution:

    • Never Sequence Native Mounts with setTimeout: Arbitrary JavaScript timers do not monitor the iOS main thread state. Always use InteractionManager.runAfterInteractions() when delaying the rendering of heavy components like maps, cameras or WebRTC views.
    • Decouple Permission Logic: Requesting hardware permissions should ideally occur at the routing layer or a preliminary staging screen. Triggering OS dialogs at the exact moment a massive native module is initializing creates immediate resource contention.
    • Audit SDK Flags: Heavy native libraries like the jitsi react native sdk offer numerous feature flags. Ensure features like CallKit (call-integration.enabled) are explicitly set to false unless you have manually configured the corresponding Swift/Objective-C AppDelegate hooks.
    • Memoize Heavy Views: Wrapping the component in React.memo() prevents unnecessary JavaScript re-renders from bubbling down to the native bridge when parent states change, which mitigates freezing when new participants trigger state updates.
    • Upgrade Strategically: Always ensure compatibility between react-native-webrtc and your chosen Jitsi SDK version. Mismatched WebRTC binary frameworks often result in silent thread locks during ICE gathering.

    If your organization needs to build reliable, high-performance systems, it pays to hire mobile engineers for telehealth scalability who understand the intricacies of native thread synchronization.

    Are You Ready to Stabilize Your Mobile Application Architecture?

    A two-minute UI freeze is a symptom of a deeper architectural misalignment between JavaScript logic and native thread processing. By diagnosing the react native video call lifecycle, stripping away unreliable timeouts, integrating proper thread interaction management and optimizing iOS audio session flags, we completely eliminated the freezing issue. The resulting architecture now scales reliably for thousands of on-demand telehealth sessions without dropping frames or blocking the UI.

    If your engineering team is facing persistent performance bottlenecks or if you need to hire software developer experts to stabilize your enterprise mobile applications, contact us to explore our dedicated engineering solutions.

    Social Hashtags

    #JitsiMeet #ReactNative #iOSDevelopment #ReactNativeDevelopment #WebRTC #JitsiSDK #MobileAppDevelopment #iOSPerformance #VideoCallSDK #ReactNativeTips #TelehealthTechnology #AppPerformance #MobileAppOptimization #SoftwareEngineering #Debugging

    Frequently Asked Questions

    Success Stories That Inspire

    See how our team takes complex business challenges and turns them into powerful, scalable digital solutions. From custom software and web applications to automation, integrations, and cloud-ready systems, each project reflects our commitment to innovation, performance, and long-term value.