Skip to main content

Headless Mode

Headless mode is the right path when you want MediaSFU workflows, socket/state behavior, and shared business logic without adopting the default UI layout.

When to use headless mode

  • You want your own app shell and presentation layer.
  • You need the MediaSFU runtime behavior, but not the default UI.
  • You are integrating mediasfu-shared directly or using a framework SDK in a logic-first way.

Headless controls by SDK

SDKHeadless switchPre-join bypassHelper handoffBest starting point
ReactJSreturnUI={false}noUIPreJoinOptionsupdateSourceParametersReactJS SDK
Angular[returnUI]="false"[noUIPreJoinOptions]updateSourceParameters outputAngular SDK
React NativereturnUI={false}noUIPreJoinOptionsupdateSourceParametersReact Native SDK
React Native ExporeturnUI={false}noUIPreJoinOptionsupdateSourceParametersExpo SDK
VuereturnUI={false}noUIPreJoinOptionsupdateSourceParametersVue SDK
FlutterreturnUI: falsenoUIPreJoinOptionsCreate or noUIPreJoinOptionsJoinupdateSourceParametersFlutter SDK
KotlinreturnUI = falseapp-owned prejoin flowonParametersUpdateKotlin SDK
Sharedn/an/adirect methods, consumers, socketsmediasfu-shared

Across the UI SDKs, the headless pattern is consistent even when the prop names differ: disable default rendering, decide whether your app owns prejoin, then capture the live helper or state handoff so your custom shell can drive the room workflow.

Current best starting points

Framework notes

  • ReactJS: the reference behavior is strongest here, so use it to understand the full helper surface before porting a custom shell to another UI SDK.
  • Angular: headless mode is particularly useful when you want to keep Angular routing, DI, and templates while outsourcing MediaSFU runtime logic.
  • React Native / Expo: validate headless flows on a physical device before treating them as closed because permission and media-capture behavior can differ from simulators.
  • Vue: this is a good path when you want composition-friendly state handling while still preserving MediaSFU socket and consumer behavior.
  • Flutter: use the dedicated create/join headless payloads and validate per target platform because mobile, desktop, and web capture behavior can differ.
  • Kotlin: the Compose path exposes app-owned UI through returnUI = false plus onParametersUpdate; treat the room shell as native Compose from the start.
  • Shared: choose this when you are building a wrapper or framework integration rather than adapting a bundled UI package.

Implementation sequence

  1. Validate a standard join flow first.
  2. Flip returnUI off and wire noUIPreJoinOptions only after the default prebuilt path is known-good.
  3. Capture and store the helper surface from updateSourceParameters, onParametersUpdate, or the framework equivalent before replacing any visible screens.
  4. Validate translation, board sync, screen share, and receive-flow behavior in the target app environment.
  5. Use the package SDK page for the SDK-specific examples and prop signatures.

Adjacent native patterns

Not every native SDK uses the same returnUI={false} contract.

  • Swift: use app-owned setup plus hosted room presentation. Use autoProceed = true from the Swift SDK when your app should own prejoin or launch flow before presenting the MediaSFU controller.
  • Unity: use scene-owned integration. Use the Unity SDK when your game or simulation should own the full scene, layout, and interaction shell while MediaSFU handles room/client infrastructure.