diff --git a/docs/how-to/client/migration-guide.mdx b/docs/how-to/client/migration-guide.mdx
new file mode 100644
index 0000000..052cb21
--- /dev/null
+++ b/docs/how-to/client/migration-guide.mdx
@@ -0,0 +1,504 @@
+---
+sidebar_position: 0
+sidebar_label: "Migration Guide"
+---
+
+# Migration Guide: From @fishjam-cloud/react-native-client to @fishjam-cloud/mobile-client
+
+This guide will help you migrate your React Native application from `@fishjam-cloud/react-native-client` to `@fishjam-cloud/mobile-client`.
+
+## Overview
+
+The new `@fishjam-cloud/mobile-client` package provides a more consistent API across web and mobile platforms, improved TypeScript support, and better integration with React's context system.
+
+## Package Installation
+
+### Before
+
+```bash
+npm install @fishjam-cloud/react-native-client
+```
+
+### After
+
+```bash
+npm install @fishjam-cloud/mobile-client
+
+```
+
+Remember to update all your imports:
+
+**From:**
+
+```tsx
+// @errors: 2307
+import { useCamera } from "@fishjam-cloud/react-native-client";
+```
+
+**To:**
+
+```tsx
+import { useCamera } from "@fishjam-cloud/mobile-client";
+```
+
+## Required Android Permissions
+
+Add the following WebRTC permissions to your Android configuration in `app.json`:
+
+```json
+{
+ "expo": {
+ "android": {
+ "permissions": [
+ "android.permission.CAMERA",
+ "android.permission.RECORD_AUDIO",
+ "android.permission.MODIFY_AUDIO_SETTINGS",
+ "android.permission.ACCESS_NETWORK_STATE",
+ "android.permission.ACCESS_WIFI_STATE"
+ ]
+ }
+ }
+}
+```
+
+## FishjamProvider Setup
+
+The new package requires wrapping your app with `FishjamProvider` to provide the Fishjam ID context.
+
+### Before
+
+```tsx
+// @errors: 2307
+import React from "react";
+// ---cut---
+import { useConnection } from "@fishjam-cloud/react-native-client";
+
+const { joinRoom } = useConnection();
+// fishjamId was passed directly to joinRoom
+await joinRoom({ fishjamId: "your-fishjam-id", peerToken: "..." });
+```
+
+### After
+
+```tsx
+import React from "react";
+import { Text } from "react-native";
+// ---cut---
+import { FishjamProvider } from "@fishjam-cloud/mobile-client"; // [!code highlight]
+
+// Wrap your app with FishjamProvider
+export default function App() {
+ return (
+
+ {" "}
+ // [!code highlight]
+
+ // [!code highlight]
+ );
+}
+
+const YourApp = () => {
+ return (
+ <>
+ Your app content
+ >
+ );
+};
+```
+
+The `fishjamId` is now provided through the context, so you no longer need to pass it to `joinRoom` or `useSandbox`.
+
+## Device Initialization
+
+### Before
+
+```tsx
+// @errors: 2307
+import { useCamera } from "@fishjam-cloud/react-native-client";
+
+const { prepareCamera } = useCamera();
+
+await prepareCamera({ cameraEnabled: true });
+```
+
+### After
+
+```tsx
+import { useInitializeDevices } from "@fishjam-cloud/mobile-client";
+
+const { initializeDevices } = useInitializeDevices();
+
+// Initialize devices when you first want to stream
+await initializeDevices({ enableAudio: false }); // or initializeDevices() for both
+```
+
+:::important
+On mobile, you should use `initializeDevices()` when you first want to stream. This gives your app access to all available devices and automatically requests camera and microphone permissions. After initialization, you can use `startCamera`/`stopCamera` or `startMicrophone`/`stopMicrophone` to manage device state.
+:::
+
+## Video Rendering and Accessing Peer Tracks
+
+### Before
+
+```tsx
+// @errors: 2307 7006
+import React from "react";
+import { View } from "react-native";
+// ---cut---
+import {
+ usePeers,
+ VideoRendererView,
+} from "@fishjam-cloud/react-native-client";
+
+const { remotePeers, localPeer } = usePeers();
+
+const videoTracks = remotePeers.flatMap((peer) =>
+ peer.tracks.filter((track) => track.type === "Video" && track.isActive),
+);
+const localTrack = localPeer?.tracks.find((t) => t.type === "Video");
+
+
+ {localTrack && (
+
+ )}
+ {videoTracks.map((track) => (
+
+ ))}
+;
+```
+
+### After
+
+```tsx
+import React from "react";
+// ---cut---
+import { usePeers, RTCView } from "@fishjam-cloud/mobile-client";
+
+function VideoPlayer({ stream }: { stream: MediaStream | null | undefined }) {
+ return (
+ <>
+ {stream && (
+
+ )}
+ >
+ );
+}
+
+const { localPeer, remotePeers } = usePeers();
+{
+ localPeer?.cameraTrack?.stream && (
+
+ );
+}
+
+{
+ remotePeers.map((peer) => (
+ <>
+ {peer.cameraTrack?.stream && (
+
+ )}
+ >
+ ));
+}
+```
+
+Key changes:
+
+- `VideoRendererView` → `RTCView`
+- `trackId` prop → `mediaStream` prop
+- `peer.tracks` array → `peer.cameraTrack` and `peer.microphoneTrack` properties
+- `track.isActive` removed (check if stream exists instead)
+- `track.type` removed (use specific track properties)
+
+## Connection API
+
+### Before
+
+```tsx
+// @errors: 2307
+import { useConnection, useSandbox } from "@fishjam-cloud/react-native-client";
+
+const { joinRoom } = useConnection();
+const { getSandboxPeerToken } = useSandbox({ fishjamId: "your-id" });
+
+const peerToken = await getSandboxPeerToken("roomName", "peerName");
+await joinRoom({ fishjamId: "your-id", peerToken });
+```
+
+### After
+
+```tsx
+import { useConnection, useSandbox } from "@fishjam-cloud/mobile-client";
+
+const { joinRoom } = useConnection();
+// fishjamId is now provided through FishjamProvider
+const { getSandboxPeerToken } = useSandbox();
+
+const peerToken = await getSandboxPeerToken("roomName", "peerName");
+await joinRoom({ peerToken }); // fishjamId passed through FishjamProvider
+```
+
+## Device Management
+
+### Camera Device Selection
+
+### Before
+
+```tsx
+// @errors: 2307 7006
+import { useCamera } from "@fishjam-cloud/react-native-client";
+
+const { cameras, switchCamera, currentCamera } = useCamera();
+
+// find first camera facing opposite direction than current camera
+const otherCamera = cameras.find(
+ (camera) => camera.facingDirection !== currentCamera?.facingDirection,
+);
+if (otherCamera) {
+ switchCamera(otherCamera.id);
+}
+```
+
+### After
+
+```tsx
+import { useCamera } from "@fishjam-cloud/mobile-client";
+const { cameraDevices, selectCamera } = useCamera();
+
+// Select camera by deviceId
+const nextCamera = cameraDevices[0];
+if (nextCamera) {
+ selectCamera(nextCamera.deviceId);
+}
+```
+
+Key changes:
+
+- `cameras` → `cameraDevices`
+- `switchCamera` → `selectCamera` (takes `deviceId` instead of direction)
+- `facingDirection` property removed
+
+### Camera Control
+
+### Before
+
+```tsx
+// @errors: 2307
+import React from "react";
+import { Button } from "react-native";
+// ---cut---
+import { useCamera } from "@fishjam-cloud/react-native-client";
+const { isCameraOn, toggleCamera } = useCamera();
+
+;
+```
+
+### After
+
+```tsx
+import { useCamera } from "@fishjam-cloud/mobile-client";
+const { startCamera, stopCamera, toggleCamera } = useCamera();
+
+await startCamera();
+
+await stopCamera();
+
+toggleCamera();
+```
+
+## Screen Sharing
+
+### Before
+
+```tsx
+// @errors: 2307
+import React, { useCallback } from "react";
+import { Button } from "react-native";
+// ---cut---
+import { useScreenShare } from "@fishjam-cloud/react-native-client";
+
+const { toggleScreenShare, isScreenShareOn } = useScreenShare();
+const onPressToggle = useCallback(
+ () => toggleScreenShare(),
+ [toggleScreenShare],
+);
+
+;
+```
+
+### After
+
+```tsx
+import React, { useCallback } from "react";
+import { Button } from "react-native";
+// ---cut---
+import { useScreenShare } from "@fishjam-cloud/mobile-client";
+
+const { startStreaming, stopStreaming, stream } = useScreenShare();
+
+const onPressToggle = () => {
+ if (stream) {
+ stopStreaming();
+ } else {
+ startStreaming();
+ }
+};
+
+;
+```
+
+Key changes:
+
+- `toggleScreenShare()` → `startStreaming()` / `stopStreaming()`
+- `isScreenShareOn` → check if `stream` exists
+
+## Picture in Picture
+
+### Before
+
+```tsx
+// @errors: 2307
+import React from "react";
+import { View } from "react-native";
+// ---cut---
+import { PipContainerView } from "@fishjam-cloud/react-native-client";
+export function VideoCallScreen() {
+ return (
+
+ {/* Your video call UI */}
+
+ );
+}
+```
+
+### After
+
+```tsx
+import React, { useRef } from "react";
+import { View, Button } from "react-native";
+import {
+ RTCPIPView,
+ startPIP,
+ stopPIP,
+ useCamera,
+} from "@fishjam-cloud/mobile-client";
+export function VideoCallScreen() {
+ const pipViewRef = useRef>(null);
+ const { cameraStream } = useCamera();
+ return (
+
+
+ );
+}
+```
+
+Key changes:
+
+- `PipContainerView` → `RTCPIPView`
+- Requires a ref for manual `startPIP`/`stopPIP` control
+- Added `pip` prop for configuration
+
+## Livestreaming Imports
+
+### Before
+
+```tsx
+// @errors: 2307
+import {
+ useLivestreamStreamer,
+ useLivestreamViewer,
+} from "@fishjam-cloud/react-native-client/livestream";
+```
+
+### After
+
+```tsx
+import {
+ useLivestreamStreamer,
+ useLivestreamViewer,
+} from "@fishjam-cloud/mobile-client";
+```
+
+The livestreaming hooks are now exported from the main package instead of a separate `/livestream` subpath.
+
+## Removed Hooks and APIs
+
+The following hooks and APIs have been removed and are no longer available:
+
+### Permission Hooks
+
+### Before
+
+```tsx
+// @errors: 2307
+import {
+ useCameraPermissions,
+ useMicrophonePermissions,
+} from "@fishjam-cloud/react-native-client";
+
+const [cameraPermission, requestCameraPermission] = useCameraPermissions();
+const [micPermission, requestMicPermission] = useMicrophonePermissions();
+```
+
+### After
+
+Permissions are now handled automatically by the SDK. When you call initializeDevices(), the SDK will automatically request camera and microphone permissions if they haven't been granted yet.
+
+### CallKit Hooks
+
+### Before
+
+```tsx
+// @errors: 2307 7006
+import {
+ useCallKit,
+ useCallKitService,
+ useCallKitEvent,
+} from "@fishjam-cloud/react-native-client";
+
+// Manual CallKit control
+const { startCallKitSession, endCallKitSession } = useCallKit();
+
+// Automatic CallKit service
+useCallKitService({
+ displayName: "User Name",
+ isVideo: true,
+});
+
+// CallKit events
+useCallKitEvent("muted", (isMuted) => {
+ // Handle mute event
+});
+```
+
+### After
+
+CallKit integration is now handled automatically by the SDK when VoIP background mode is enabled. You no longer need to manually manage CallKit sessions.