React Native Integration Skill

Integration conventions for the StreamLayer React Native SDK that keep an AI agent's diff small and correct — where to initialize, where to render StreamLayerView, callback wiring, auth forwarding, and minimal-diff placement.

StreamLayer React Native SDK Integration

How to wire StreamLayer into an existing React Native or Expo app cleanly. Follow the rules — they prevent the common over-integration mistakes.

This page is the human-readable form of the streamlayer-react-native-integration agent skill. Reference it from your AI agent alongside the streamlayer-docs MCP — see Integrate with an AI Agent.

Pick the package

  • react-native-sl-sdk — the React Native SDK, published to npm. Import StreamLayer, StreamLayerView, and the supporting types/enums from it: import { StreamLayer, StreamLayerView, StreamLayerViewConfiguration, StreamLayerViewNotificationFeature, StreamLayerViewOverlayLandscapeMode, StreamLayerTheme } from 'react-native-sl-sdk';
  • New Architecture only. The SDK ships on the React Native New Architecture (Fabric / TurboModules). Install it (npm install react-native-sl-sdk) and run pod install — it can't be added to an old-bridge app without migrating.
  • Main UI element: StreamLayerView — the StreamLayer Element. It renders your player through its playerView prop and scales it down when the L-bar layout arrives; it is not a standalone floating panel.
  • Companion packages: expo-screen-orientation (Expo, for rotation) and react-native-config (to read the SDK API Key from .env) — follow the Integration Guide for the exact native setup.
  • Requirements: React Native 0.76+ / Expo SDK 52+, iOS 15+, Android min SDK 24, Xcode 15.3+.

Rules (do this)

  1. Initialize once and high; render the view low, gated on init. Call StreamLayer.initSdk({ sdkKey, theme, isLoggingEnabled }, false) exactly once — in a mount useEffect at the app/player-screen root, not on every render. Track completion in state (const inited = await StreamLayer.isInitialized(); setInitialized(inited)) and render StreamLayerView only when isInitialized is true. Put it inside the player screen — the component that owns the video and its play/pause state — not in a global provider mounted app-wide.

    • ❌ Rendering StreamLayerView before initSdk resolves — the native view has no initialized SDK context.
    • ❌ Calling initSdk inside render / on every effect run — it's a one-time call; guard it.
    • initSdk in a []-dependency useEffect; StreamLayerView rendered under an isInitialized gate.
  2. Wrap your player in the playerView prop; don't render it separately. StreamLayerView takes your existing player element as its playerView prop and resizes it for L-bar and sidebar layouts. Pass a stable player object (a StreamLayerViewPlayer with a volume getter/setter) so the SDK can bridge audio. Keep a useRef<StreamLayerView> for imperative calls. Style it with StyleSheet.absoluteFillObject over your player container, not the whole screen.

  3. Build config once and wire only the callbacks your features use. Compute the StreamLayerViewConfiguration from a stable helper (getViewConfig()), not inline in JSX, so it isn't rebuilt every render. Wire onRequestAudioDucking(level) / onDisableAudioDucking() to your player's volume for the audio bridge, onLBarStateChanged(slideX, slideY) to resize the playerView when the L-bar slides in, and onRequestStream(id) to switch events — leave out the ones you don't handle. Set overlayHeightSpace / overlayLandscapeMode in the config to control portrait/landscape placement.

  4. Forward authentication after init. For logged-in users, call await StreamLayer.authorizationBypass(schema, token) with a token from your backend; for guests use await StreamLayer.useAnonymousAuth(). Check first with StreamLayer.isUserAuthorized() and do it once, after initSdk. Both are async and can reject — always try/catch. Start a session for your event with await StreamLayer.createEventSession(eventId) when the user opens or switches a stream; call StreamLayer.releaseEventSession() when leaving.

  5. Keep credentials and the diff simple. The SDK API Key is a public, client-side value from StreamLayer Studio. This SDK's documented pattern reads it from .env via react-native-config (SL_SDK_API_KEY) — use that existing mechanism, don't invent a new secrets layer or hardcode the key in source. Fit StreamLayerView around your existing player and screen — don't restructure navigation, add wrapper providers, or refactor unrelated component code.

Gotchas

  • StreamLayerView renders nothing. Almost always the isInitialized gate is missing or initSdk hasn't resolved yet, or your player was rendered outside the playerView prop instead of inside it.
  • Native build fails after install. Missing pod install, an iOS deployment target below 15, the New Architecture not enabled, or the expo-screen-orientation plugin not added to app.json.
  • Player covers or clips the L-bar. onLBarStateChanged isn't resizing the playerView — subtract slideX / slideY from your player's width/height as the L-bar slides in.
  • Audio doesn't duck. onRequestAudioDucking / onDisableAudioDucking aren't wired to your player's volume, or the player object passed to StreamLayerView has no working volume setter.
  • Auth call throws. authorizationBypass / useAnonymousAuth are async and reject on failure — always await inside try/catch.
  • Wrong architecture. This SDK requires the New Architecture; an old-bridge app must migrate first — don't try to add it to a Paper-only project.
  • Authoritative API details: the streamlayer-docs MCP (search / fetch) and the API Reference.

Related