@multiplayer-app/session-recorder-react-native 0.0.1 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +708 -83
- package/SessionRecorderNative.podspec +26 -0
- package/android/build.gradle +34 -0
- package/copy-react-native-dist.sh +34 -16
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js +1 -1
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -1
- package/dist/components/SessionRecorderWidget/ErrorBanner.d.ts +7 -0
- package/dist/components/SessionRecorderWidget/ErrorBanner.js +1 -0
- package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.d.ts +12 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.js +1 -0
- package/dist/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.d.ts +8 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.js +1 -0
- package/dist/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.d.ts +16 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.js +1 -0
- package/dist/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.d.ts +8 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.js +1 -0
- package/dist/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.d.ts +6 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.js +1 -0
- package/dist/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +5 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +1 -0
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
- package/dist/components/SessionRecorderWidget/icons.d.ts +11 -0
- package/dist/components/SessionRecorderWidget/icons.js +1 -0
- package/dist/components/SessionRecorderWidget/icons.js.map +1 -0
- package/dist/components/SessionRecorderWidget/index.d.ts +2 -0
- package/dist/components/SessionRecorderWidget/index.js +1 -0
- package/dist/components/SessionRecorderWidget/index.js.map +1 -0
- package/dist/components/SessionRecorderWidget/styles.d.ts +165 -0
- package/dist/components/SessionRecorderWidget/styles.js +1 -0
- package/dist/components/SessionRecorderWidget/styles.js.map +1 -0
- package/dist/components/index.d.ts +2 -1
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/config/constants.js +1 -1
- package/dist/config/constants.js.map +1 -1
- package/dist/config/defaults.d.ts +4 -4
- package/dist/config/defaults.js +1 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/masking.d.ts +2 -2
- package/dist/config/masking.js +1 -1
- package/dist/config/masking.js.map +1 -1
- package/dist/config/session-recorder.js +1 -1
- package/dist/config/session-recorder.js.map +1 -1
- package/dist/config/validators.d.ts +1 -1
- package/dist/config/validators.js +1 -1
- package/dist/config/validators.js.map +1 -1
- package/dist/config/widget.d.ts +9 -0
- package/dist/config/widget.js +1 -0
- package/dist/config/widget.js.map +1 -0
- package/dist/context/SessionRecorderContext.d.ts +12 -3
- package/dist/context/SessionRecorderContext.js +1 -1
- package/dist/context/SessionRecorderContext.js.map +1 -1
- package/dist/context/SessionRecorderStore.d.ts +12 -0
- package/dist/context/SessionRecorderStore.js +1 -0
- package/dist/context/SessionRecorderStore.js.map +1 -0
- package/dist/context/useSessionRecorderStore.d.ts +8 -0
- package/dist/context/useSessionRecorderStore.js +1 -0
- package/dist/context/useSessionRecorderStore.js.map +1 -0
- package/dist/context/useStoreSelector.d.ts +4 -0
- package/dist/context/useStoreSelector.js +1 -0
- package/dist/context/useStoreSelector.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/native/GestureRecorderNative.d.ts +57 -0
- package/dist/native/GestureRecorderNative.js +1 -0
- package/dist/native/GestureRecorderNative.js.map +1 -0
- package/dist/native/SessionRecorderNative.d.ts +33 -0
- package/dist/native/SessionRecorderNative.js +1 -0
- package/dist/native/SessionRecorderNative.js.map +1 -0
- package/dist/native/index.d.ts +2 -0
- package/dist/native/index.js +1 -0
- package/dist/native/index.js.map +1 -0
- package/dist/otel/index.js +1 -1
- package/dist/otel/index.js.map +1 -1
- package/dist/patch/xhr.js +1 -1
- package/dist/patch/xhr.js.map +1 -1
- package/dist/recorder/eventExporter.d.ts +4 -1
- package/dist/recorder/eventExporter.js +1 -1
- package/dist/recorder/eventExporter.js.map +1 -1
- package/dist/recorder/gestureRecorder.d.ts +28 -62
- package/dist/recorder/gestureRecorder.js +1 -1
- package/dist/recorder/gestureRecorder.js.map +1 -1
- package/dist/recorder/index.d.ts +2 -0
- package/dist/recorder/index.js +1 -1
- package/dist/recorder/index.js.map +1 -1
- package/dist/recorder/navigationTracker.d.ts +4 -19
- package/dist/recorder/navigationTracker.js +1 -1
- package/dist/recorder/navigationTracker.js.map +1 -1
- package/dist/recorder/screenRecorder.d.ts +11 -5
- package/dist/recorder/screenRecorder.js +1 -1
- package/dist/recorder/screenRecorder.js.map +1 -1
- package/dist/services/api.service.d.ts +12 -3
- package/dist/services/api.service.js +1 -1
- package/dist/services/api.service.js.map +1 -1
- package/dist/services/network.service.d.ts +46 -0
- package/dist/services/network.service.js +1 -0
- package/dist/services/network.service.js.map +1 -0
- package/dist/services/screenMaskingService.d.ts +47 -0
- package/dist/services/screenMaskingService.js +1 -0
- package/dist/services/screenMaskingService.js.map +1 -0
- package/dist/services/storage.service.d.ts +18 -2
- package/dist/services/storage.service.js +1 -1
- package/dist/services/storage.service.js.map +1 -1
- package/dist/session-recorder.d.ts +18 -33
- package/dist/session-recorder.js +1 -1
- package/dist/session-recorder.js.map +1 -1
- package/dist/types/configs.d.ts +85 -0
- package/dist/types/configs.js +1 -0
- package/dist/types/configs.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/session-recorder.d.ts +105 -132
- package/dist/types/session-recorder.js +1 -1
- package/dist/types/session-recorder.js.map +1 -1
- package/dist/utils/constants.optional.d.ts +21 -0
- package/dist/utils/constants.optional.expo.d.ts +3 -0
- package/dist/utils/constants.optional.expo.js +1 -0
- package/dist/utils/constants.optional.expo.js.map +1 -0
- package/dist/utils/constants.optional.js +1 -0
- package/dist/utils/constants.optional.js.map +1 -0
- package/dist/utils/createStore.d.ts +8 -0
- package/dist/utils/createStore.js +1 -0
- package/dist/utils/createStore.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -7
- package/dist/utils/logger.js +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/platform.d.ts +11 -0
- package/dist/utils/platform.js +1 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/rrweb-events.d.ts +4 -3
- package/dist/utils/rrweb-events.js +1 -1
- package/dist/utils/rrweb-events.js.map +1 -1
- package/dist/utils/session.d.ts +2 -1
- package/dist/utils/session.js +1 -1
- package/dist/utils/session.js.map +1 -1
- package/dist/utils/shallowEqual.d.ts +1 -0
- package/dist/utils/shallowEqual.js +1 -0
- package/dist/utils/shallowEqual.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/ios/GestureRecorderNative.m +21 -0
- package/ios/GestureRecorderNative.swift +316 -0
- package/ios/SessionRecorderNative.m +17 -0
- package/ios/SessionRecorderNative.podspec +26 -0
- package/ios/SessionRecorderNative.swift +599 -0
- package/package.json +15 -16
- package/react-native.config.js +12 -0
- package/RRWEB_INTEGRATION.md +0 -336
- package/VIEWSHOT_INTEGRATION_TEST.md +0 -123
- package/babel.config.js +0 -13
- package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.d.ts +0 -6
- package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js +0 -1
- package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js.map +0 -1
- package/dist/components/GestureCaptureWrapper/index.d.ts +0 -1
- package/dist/components/GestureCaptureWrapper/index.js +0 -1
- package/dist/components/GestureCaptureWrapper/index.js.map +0 -1
- package/dist/components/GestureCaptureWrapper.d.ts +0 -6
- package/dist/components/GestureCaptureWrapper.js +0 -1
- package/dist/components/GestureCaptureWrapper.js.map +0 -1
- package/dist/expo.d.ts +0 -7
- package/dist/expo.js +0 -1
- package/dist/expo.js.map +0 -1
- package/dist/otel/instrumentations/gestureInstrumentation.d.ts +0 -15
- package/dist/otel/instrumentations/gestureInstrumentation.js +0 -1
- package/dist/otel/instrumentations/gestureInstrumentation.js.map +0 -1
- package/dist/otel/instrumentations/reactNativeInstrumentation.d.ts +0 -8
- package/dist/otel/instrumentations/reactNativeInstrumentation.js +0 -1
- package/dist/otel/instrumentations/reactNativeInstrumentation.js.map +0 -1
- package/dist/otel/instrumentations/reactNavigationInstrumentation.d.ts +0 -13
- package/dist/otel/instrumentations/reactNavigationInstrumentation.js +0 -1
- package/dist/otel/instrumentations/reactNavigationInstrumentation.js.map +0 -1
- package/dist/recorder/gestureHandlerRecorder.d.ts +0 -19
- package/dist/recorder/gestureHandlerRecorder.js +0 -1
- package/dist/recorder/gestureHandlerRecorder.js.map +0 -1
- package/dist/types/rrweb.d.ts +0 -118
- package/dist/types/rrweb.js +0 -1
- package/dist/types/rrweb.js.map +0 -1
- package/scripts/generate-app-metadata.js +0 -173
- package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
- package/src/components/GestureCaptureWrapper/index.ts +0 -1
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
- package/src/components/ScreenRecorderView/index.ts +0 -1
- package/src/components/index.ts +0 -1
- package/src/config/constants.ts +0 -60
- package/src/config/defaults.ts +0 -82
- package/src/config/index.ts +0 -6
- package/src/config/masking.ts +0 -27
- package/src/config/session-recorder.ts +0 -55
- package/src/config/validators.ts +0 -31
- package/src/context/SessionRecorderContext.tsx +0 -75
- package/src/expo.ts +0 -11
- package/src/index.ts +0 -17
- package/src/otel/helpers.ts +0 -275
- package/src/otel/index.ts +0 -138
- package/src/otel/instrumentations/index.ts +0 -115
- package/src/patch/index.ts +0 -1
- package/src/patch/xhr.ts +0 -142
- package/src/recorder/eventExporter.ts +0 -141
- package/src/recorder/gestureRecorder.ts +0 -498
- package/src/recorder/index.ts +0 -179
- package/src/recorder/navigationTracker.ts +0 -449
- package/src/recorder/screenRecorder.ts +0 -498
- package/src/services/api.service.ts +0 -203
- package/src/services/storage.service.ts +0 -158
- package/src/session-recorder.ts +0 -600
- package/src/types/expo.d.ts +0 -23
- package/src/types/index.ts +0 -28
- package/src/types/session-recorder.ts +0 -423
- package/src/types/session.ts +0 -65
- package/src/utils/app-metadata.ts +0 -31
- package/src/utils/index.ts +0 -8
- package/src/utils/logger.ts +0 -225
- package/src/utils/platform.ts +0 -384
- package/src/utils/request-utils.ts +0 -61
- package/src/utils/rrweb-events.ts +0 -309
- package/src/utils/session.ts +0 -18
- package/src/utils/time.ts +0 -17
- package/src/utils/type-utils.ts +0 -75
- package/src/version.ts +0 -1
- package/tsconfig.json +0 -24
package/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Multiplayer Session Recorder for React Native
|
|
2
2
|
|
|
3
|
-
The Multiplayer Session Recorder for React Native provides session recording capabilities for React Native applications, including gesture tracking, navigation monitoring, and
|
|
3
|
+
The Multiplayer Session Recorder for React Native provides comprehensive session recording capabilities for React Native applications, including gesture tracking, navigation monitoring, screen recording, and full-stack debugging. It includes full support for both bare React Native and Expo applications.
|
|
4
|
+
|
|
5
|
+
## ⚠️ Important: Web Platform Limitations
|
|
6
|
+
|
|
7
|
+
**This package does NOT support React Native Web.** The session recorder relies on native modules for core functionality:
|
|
8
|
+
|
|
9
|
+
- **Screen Recording**: Requires native screen capture capabilities
|
|
10
|
+
- **Gesture Recording**: Uses native gesture detection systems
|
|
11
|
+
- **Native Module Dependencies**: Core features depend on iOS/Android native modules
|
|
12
|
+
|
|
13
|
+
If you need web support, consider using the browser-specific session recorder package instead.
|
|
4
14
|
|
|
5
15
|
## Installation
|
|
6
16
|
|
|
@@ -15,44 +25,223 @@ yarn add @multiplayer-app/session-recorder-react-native
|
|
|
15
25
|
This package requires the following dependencies to be installed in your React Native application:
|
|
16
26
|
|
|
17
27
|
```bash
|
|
18
|
-
npm install @react-native-async-storage/async-storage @react-native-community/netinfo react-native-
|
|
28
|
+
npm install @react-native-async-storage/async-storage @react-native-community/netinfo react-native-svg react-native-safe-area-context
|
|
19
29
|
# or
|
|
20
|
-
yarn add @react-native-async-storage/async-storage @react-native-community/netinfo react-native-
|
|
30
|
+
yarn add @react-native-async-storage/async-storage @react-native-community/netinfo react-native-svg react-native-safe-area-context
|
|
21
31
|
```
|
|
22
32
|
|
|
23
|
-
**
|
|
33
|
+
**Important**: Native modules must be installed directly in your app's `package.json`. React Native autolinking only links native modules that are declared by the app itself, not modules pulled in transitively by libraries. If you don't add them directly, you may see errors like "NativeModule: AsyncStorage is null" or SVGs not rendering.
|
|
34
|
+
|
|
35
|
+
#### Bare React Native projects
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install native dependencies in your app
|
|
39
|
+
npm install @react-native-async-storage/async-storage @react-native-community/netinfo react-native-svg react-native-safe-area-context
|
|
40
|
+
|
|
41
|
+
# iOS: Install pods from your app's ios directory
|
|
42
|
+
cd ios && pod install && cd -
|
|
43
|
+
|
|
44
|
+
# Android: Clean and rebuild
|
|
45
|
+
cd android && ./gradlew clean && cd -
|
|
46
|
+
```
|
|
24
47
|
|
|
25
|
-
|
|
48
|
+
#### Expo projects
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
Use Expo's version-aware installer so versions match the SDK:
|
|
28
51
|
|
|
29
52
|
```bash
|
|
30
|
-
npx expo install @
|
|
53
|
+
npx expo install @react-native-async-storage/async-storage @react-native-community/netinfo react-native-svg react-native-safe-area-context
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If you use Expo Router or a managed workflow, no extra autolinking steps are required beyond installing the packages.
|
|
57
|
+
|
|
58
|
+
#### Why direct install is required
|
|
59
|
+
|
|
60
|
+
- Autolinking scans only the app's `package.json`
|
|
61
|
+
- iOS CocoaPods/Android Gradle include native modules only when the app declares them
|
|
62
|
+
- Libraries should list native requirements as `peerDependencies` and document installation
|
|
63
|
+
|
|
64
|
+
<!-- Removed separate Expo Installation block to avoid duplication. Expo users should install native deps with `expo install` as shown above. -->
|
|
65
|
+
|
|
66
|
+
### Troubleshooting AsyncStorage
|
|
67
|
+
|
|
68
|
+
If you encounter:
|
|
69
|
+
|
|
31
70
|
```
|
|
71
|
+
[@RNC/AsyncStorage]: NativeModule: AsyncStorage is null
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
1. Ensure `@react-native-async-storage/async-storage` is installed in your app (not only in this library)
|
|
75
|
+
2. iOS: run `cd ios && pod install`, then rebuild the app
|
|
76
|
+
3. Clear Metro cache: `npm start -- --reset-cache` (or `expo start -c`)
|
|
77
|
+
4. Clean builds: uninstall the app from device/simulator and rebuild
|
|
78
|
+
|
|
79
|
+
## Quick Start
|
|
32
80
|
|
|
33
|
-
|
|
81
|
+
### ⚠️ Important: SessionRecorderProvider Required
|
|
34
82
|
|
|
35
|
-
|
|
83
|
+
**The `SessionRecorderProvider` is required for the session recorder to work properly.** It provides:
|
|
84
|
+
|
|
85
|
+
- Context for session state management
|
|
86
|
+
- Widget modal functionality
|
|
87
|
+
- React hooks for session control
|
|
88
|
+
- Store management for session state
|
|
89
|
+
|
|
90
|
+
### Minimal Setup (Recommended for getting started)
|
|
91
|
+
|
|
92
|
+
#### For Basic React Native Apps (App.tsx)
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
import React from 'react'
|
|
96
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
97
|
+
|
|
98
|
+
// Initialize with minimal required options
|
|
99
|
+
SessionRecorder.init({
|
|
100
|
+
application: 'my-react-native-app',
|
|
101
|
+
version: '1.0.0',
|
|
102
|
+
environment: 'production',
|
|
103
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY'
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
export default function App() {
|
|
107
|
+
return <SessionRecorderProvider>{/* Your app content */}</SessionRecorderProvider>
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### For Expo Apps (\_layout.tsx)
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
import React from 'react'
|
|
115
|
+
import { Stack } from 'expo-router'
|
|
116
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
117
|
+
|
|
118
|
+
// Initialize with minimal required options
|
|
119
|
+
SessionRecorder.init({
|
|
120
|
+
application: 'my-expo-app',
|
|
121
|
+
version: '1.0.0',
|
|
122
|
+
environment: 'production',
|
|
123
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY'
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
export default function RootLayout() {
|
|
127
|
+
return (
|
|
128
|
+
<SessionRecorderProvider>
|
|
129
|
+
<Stack />
|
|
130
|
+
</SessionRecorderProvider>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This minimal setup will:
|
|
136
|
+
|
|
137
|
+
- ✅ Record gestures and navigation automatically
|
|
138
|
+
- ✅ Enable HTTP request/response monitoring
|
|
139
|
+
- ✅ Provide basic session recording capabilities
|
|
140
|
+
- ✅ Screen recording enabled (captures app UI)
|
|
36
141
|
|
|
37
142
|
### Basic Configuration
|
|
38
143
|
|
|
144
|
+
#### For Basic React Native Apps (App.tsx)
|
|
145
|
+
|
|
39
146
|
```javascript
|
|
40
|
-
import
|
|
147
|
+
import React from 'react'
|
|
148
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
41
149
|
|
|
42
150
|
SessionRecorder.init({
|
|
43
151
|
application: 'my-react-native-app',
|
|
44
152
|
version: '1.0.0',
|
|
45
153
|
environment: 'production',
|
|
46
|
-
apiKey: '
|
|
154
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
155
|
+
recordGestures: true, // default is true
|
|
156
|
+
recordNavigation: true, // default is true
|
|
157
|
+
recordScreen: true // default is true
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
export default function App() {
|
|
161
|
+
return <SessionRecorderProvider>{/* Your app content */}</SessionRecorderProvider>
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### For Expo Apps (\_layout.tsx)
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
import React from 'react'
|
|
169
|
+
import { Stack } from 'expo-router'
|
|
170
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
171
|
+
|
|
172
|
+
SessionRecorder.init({
|
|
173
|
+
application: 'my-expo-app',
|
|
174
|
+
version: '1.0.0',
|
|
175
|
+
environment: 'production',
|
|
176
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
177
|
+
recordGestures: true, // default is true
|
|
178
|
+
recordNavigation: true, // default is true
|
|
179
|
+
recordScreen: true // default is true
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
export default function RootLayout() {
|
|
183
|
+
return (
|
|
184
|
+
<SessionRecorderProvider>
|
|
185
|
+
<Stack />
|
|
186
|
+
</SessionRecorderProvider>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Complete App Integration Example
|
|
192
|
+
|
|
193
|
+
Here's a complete example showing how to integrate the session recorder in your React Native app:
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
import React, { useEffect, useRef } from 'react'
|
|
197
|
+
import { NavigationContainer } from '@react-navigation/native'
|
|
198
|
+
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
|
199
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
200
|
+
import { AppNavigator } from './navigation/AppNavigator'
|
|
201
|
+
|
|
202
|
+
// Initialize session recorder
|
|
203
|
+
SessionRecorder.init({
|
|
204
|
+
application: 'my-react-native-app',
|
|
205
|
+
version: '1.0.0',
|
|
206
|
+
environment: __DEV__ ? 'development' : 'production',
|
|
207
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
47
208
|
recordGestures: true,
|
|
48
209
|
recordNavigation: true,
|
|
49
|
-
recordScreen: false //
|
|
210
|
+
recordScreen: false // Enable after adding permissions
|
|
50
211
|
})
|
|
212
|
+
|
|
213
|
+
export default function App() {
|
|
214
|
+
const navigationRef = useRef(null)
|
|
215
|
+
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
// Set session attributes for better debugging context
|
|
218
|
+
SessionRecorder.setSessionAttributes({
|
|
219
|
+
userId: 'user123',
|
|
220
|
+
userType: 'premium',
|
|
221
|
+
appVersion: '1.0.0'
|
|
222
|
+
})
|
|
223
|
+
}, [])
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<SessionRecorderProvider>
|
|
227
|
+
<SafeAreaProvider>
|
|
228
|
+
<NavigationContainer
|
|
229
|
+
ref={navigationRef}
|
|
230
|
+
onReady={() => {
|
|
231
|
+
SessionRecorder.setNavigationRef(navigationRef.current)
|
|
232
|
+
}}
|
|
233
|
+
>
|
|
234
|
+
<AppNavigator />
|
|
235
|
+
</NavigationContainer>
|
|
236
|
+
</SafeAreaProvider>
|
|
237
|
+
</SessionRecorderProvider>
|
|
238
|
+
)
|
|
239
|
+
}
|
|
51
240
|
```
|
|
52
241
|
|
|
53
242
|
### Expo Configuration
|
|
54
243
|
|
|
55
|
-
For Expo applications, the package automatically detects the Expo environment
|
|
244
|
+
For Expo applications, the package automatically detects the Expo environment:
|
|
56
245
|
|
|
57
246
|
```javascript
|
|
58
247
|
import SessionRecorder from '@multiplayer-app/session-recorder-react-native'
|
|
@@ -61,11 +250,10 @@ SessionRecorder.init({
|
|
|
61
250
|
application: 'my-expo-app',
|
|
62
251
|
version: '1.0.0',
|
|
63
252
|
environment: 'production',
|
|
64
|
-
apiKey: '
|
|
65
|
-
platform: 'expo', // Optional: explicitly set platform
|
|
253
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
66
254
|
recordGestures: true,
|
|
67
255
|
recordNavigation: true,
|
|
68
|
-
recordScreen:
|
|
256
|
+
recordScreen: true
|
|
69
257
|
})
|
|
70
258
|
```
|
|
71
259
|
|
|
@@ -75,148 +263,585 @@ The package will automatically:
|
|
|
75
263
|
- Add Expo-specific attributes to traces
|
|
76
264
|
- Optimize performance for Expo runtime
|
|
77
265
|
|
|
78
|
-
###
|
|
266
|
+
### Navigation Integration
|
|
79
267
|
|
|
80
|
-
|
|
268
|
+
#### Expo Router (Recommended for Expo apps)
|
|
269
|
+
|
|
270
|
+
Expo Router already manages the NavigationContainer. Don't add your own.
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
import { useEffect } from 'react'
|
|
274
|
+
import { Stack, useNavigationContainerRef } from 'expo-router'
|
|
275
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
276
|
+
|
|
277
|
+
export default function RootLayout() {
|
|
278
|
+
const navigationRef = useNavigationContainerRef()
|
|
279
|
+
|
|
280
|
+
useEffect(() => {
|
|
281
|
+
const unsub = navigationRef.addListener?.('state', () => {
|
|
282
|
+
SessionRecorder.setNavigationRef(navigationRef)
|
|
283
|
+
unsub?.()
|
|
284
|
+
})
|
|
285
|
+
return unsub
|
|
286
|
+
}, [navigationRef])
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
<SessionRecorderProvider>
|
|
290
|
+
<Stack />
|
|
291
|
+
</SessionRecorderProvider>
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Classic React Navigation (Bare React Native)
|
|
297
|
+
|
|
298
|
+
If you own the `NavigationContainer`, set the ref in `onReady`:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
81
301
|
import { NavigationContainer } from '@react-navigation/native'
|
|
82
|
-
import
|
|
302
|
+
import { useRef } from 'react'
|
|
303
|
+
import { SessionRecorderProvider, SessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
83
304
|
|
|
84
305
|
export default function App() {
|
|
85
|
-
const navigationRef = useRef(null)
|
|
306
|
+
const navigationRef = useRef<any>(null)
|
|
86
307
|
|
|
87
308
|
return (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
309
|
+
<SessionRecorderProvider>
|
|
310
|
+
<NavigationContainer
|
|
311
|
+
ref={navigationRef}
|
|
312
|
+
onReady={() => {
|
|
313
|
+
SessionRecorder.setNavigationRef(navigationRef.current)
|
|
314
|
+
}}
|
|
315
|
+
>
|
|
316
|
+
{/* Your navigation stack */}
|
|
317
|
+
</NavigationContainer>
|
|
318
|
+
</SessionRecorderProvider>
|
|
96
319
|
)
|
|
97
320
|
}
|
|
98
321
|
```
|
|
99
322
|
|
|
100
|
-
### Manual Control
|
|
323
|
+
### Manual Session Control
|
|
101
324
|
|
|
102
325
|
```javascript
|
|
103
|
-
// Start recording
|
|
326
|
+
// Start a new recording session
|
|
104
327
|
SessionRecorder.start()
|
|
105
328
|
|
|
106
|
-
// Pause recording
|
|
329
|
+
// Pause current recording
|
|
107
330
|
SessionRecorder.pause()
|
|
108
331
|
|
|
109
|
-
// Resume recording
|
|
332
|
+
// Resume paused recording
|
|
110
333
|
SessionRecorder.resume()
|
|
111
334
|
|
|
112
|
-
// Stop recording
|
|
335
|
+
// Stop recording with optional reason
|
|
113
336
|
SessionRecorder.stop('Session completed')
|
|
114
337
|
|
|
115
|
-
// Save continuous recording
|
|
338
|
+
// Save continuous recording (for continuous mode)
|
|
116
339
|
SessionRecorder.save()
|
|
340
|
+
|
|
341
|
+
// Set session attributes for better context
|
|
342
|
+
SessionRecorder.setSessionAttributes({
|
|
343
|
+
userId: 'user123',
|
|
344
|
+
feature: 'checkout',
|
|
345
|
+
version: '2.1.0'
|
|
346
|
+
})
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Session Provider & Hooks
|
|
350
|
+
|
|
351
|
+
### Disable Widget Button
|
|
352
|
+
|
|
353
|
+
To hide the floating widget button but keep the modal functionality:
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
SessionRecorder.init({
|
|
357
|
+
application: 'my-app',
|
|
358
|
+
version: '1.0.0',
|
|
359
|
+
environment: 'production',
|
|
360
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
361
|
+
|
|
362
|
+
// Disable the floating button
|
|
363
|
+
widget: {
|
|
364
|
+
enabled: true,
|
|
365
|
+
button: {
|
|
366
|
+
visible: false // Hide the floating button
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Programmatic Widget Control
|
|
373
|
+
|
|
374
|
+
Use the `useSessionRecorder` hook to control the widget modal programmatically:
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
import React from 'react'
|
|
378
|
+
import { View, Button } from 'react-native'
|
|
379
|
+
import { useSessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
380
|
+
|
|
381
|
+
function MyComponent() {
|
|
382
|
+
const { openWidgetModal, closeWidgetModal } = useSessionRecorder()
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
<View>
|
|
386
|
+
<Button title='Open Session Recorder' onPress={openWidgetModal} />
|
|
387
|
+
<Button title='Close Session Recorder' onPress={closeWidgetModal} />
|
|
388
|
+
</View>
|
|
389
|
+
)
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Session Control with Hooks
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
import React from 'react'
|
|
397
|
+
import { View, Button } from 'react-native'
|
|
398
|
+
import { useSessionRecorder } from '@multiplayer-app/session-recorder-react-native'
|
|
399
|
+
|
|
400
|
+
function SessionControls() {
|
|
401
|
+
const { startSession, stopSession, pauseSession, resumeSession, saveSession } = useSessionRecorder()
|
|
402
|
+
|
|
403
|
+
return (
|
|
404
|
+
<View>
|
|
405
|
+
<Button title='Start Session' onPress={() => startSession()} />
|
|
406
|
+
<Button title='Pause Session' onPress={() => pauseSession()} />
|
|
407
|
+
<Button title='Resume Session' onPress={() => resumeSession()} />
|
|
408
|
+
<Button title='Stop Session' onPress={() => stopSession('User completed')} />
|
|
409
|
+
<Button title='Save Session' onPress={() => saveSession()} />
|
|
410
|
+
</View>
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Session State with Hooks
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
import React from 'react'
|
|
419
|
+
import { View, Text } from 'react-native'
|
|
420
|
+
import { useSessionRecorderStore } from '@multiplayer-app/session-recorder-react-native'
|
|
421
|
+
|
|
422
|
+
function SessionStatus() {
|
|
423
|
+
const sessionType = useSessionRecorderStore((s) => s.sessionType)
|
|
424
|
+
const isWidgetModalVisible = useSessionRecorderStore((s) => s.isWidgetModalVisible)
|
|
425
|
+
const sessionState = useSessionRecorderStore((s) => s.sessionState)
|
|
426
|
+
const isOnline = useSessionRecorderStore((s) => s.isOnline)
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
<View>
|
|
430
|
+
<Text>Session State: {sessionState}</Text>
|
|
431
|
+
<Text>Session Type: {sessionType}</Text>
|
|
432
|
+
<Text>Widget Visible: {isWidgetModalVisible ? 'Yes' : 'No'}</Text>
|
|
433
|
+
<Text>Online: {isOnline ? 'Yes' : 'No'}</Text>
|
|
434
|
+
</View>
|
|
435
|
+
)
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Complete Example with Custom UI
|
|
440
|
+
|
|
441
|
+
```javascript
|
|
442
|
+
import React, { useEffect } from 'react'
|
|
443
|
+
import { View, Button, Text, Alert } from 'react-native'
|
|
444
|
+
import {
|
|
445
|
+
SessionRecorderProvider,
|
|
446
|
+
useSessionRecorder,
|
|
447
|
+
useSessionRecorderStore
|
|
448
|
+
} from '@multiplayer-app/session-recorder-react-native'
|
|
449
|
+
|
|
450
|
+
function SessionRecorderUI() {
|
|
451
|
+
const { startSession, stopSession, openWidgetModal } = useSessionRecorder()
|
|
452
|
+
const { sessionState, isWidgetModalVisible } = useSessionRecorderStore((state) => ({
|
|
453
|
+
sessionState: state.sessionState,
|
|
454
|
+
isWidgetModalVisible: state.isWidgetModalVisible
|
|
455
|
+
}))
|
|
456
|
+
|
|
457
|
+
const handleStartRecording = async () => {
|
|
458
|
+
try {
|
|
459
|
+
await startSession()
|
|
460
|
+
Alert.alert('Success', 'Session recording started')
|
|
461
|
+
} catch (error) {
|
|
462
|
+
Alert.alert('Error', 'Failed to start recording')
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const handleStopRecording = async () => {
|
|
467
|
+
try {
|
|
468
|
+
await stopSession('User manually stopped')
|
|
469
|
+
Alert.alert('Success', 'Session recording stopped')
|
|
470
|
+
} catch (error) {
|
|
471
|
+
Alert.alert('Error', 'Failed to stop recording')
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return (
|
|
476
|
+
<View style={{ padding: 20 }}>
|
|
477
|
+
<Text>Session State: {sessionState}</Text>
|
|
478
|
+
<Text>Widget Modal: {isWidgetModalVisible ? 'Open' : 'Closed'}</Text>
|
|
479
|
+
|
|
480
|
+
<Button title='Start Recording' onPress={handleStartRecording} />
|
|
481
|
+
<Button title='Stop Recording' onPress={handleStopRecording} />
|
|
482
|
+
<Button title='Open Widget' onPress={openWidgetModal} />
|
|
483
|
+
</View>
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export default function App() {
|
|
488
|
+
return (
|
|
489
|
+
<SessionRecorderProvider>
|
|
490
|
+
<SessionRecorderUI />
|
|
491
|
+
</SessionRecorderProvider>
|
|
492
|
+
)
|
|
493
|
+
}
|
|
117
494
|
```
|
|
118
495
|
|
|
119
496
|
## Features
|
|
120
497
|
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
498
|
+
- **🎯 Gesture Recording**: Track taps, swipes, and other touch interactions with target element information
|
|
499
|
+
- **🧭 Navigation Tracking**: Monitor screen transitions and navigation state changes
|
|
500
|
+
- **📱 Screen Recording**: Capture periodic screenshots (requires permissions)
|
|
501
|
+
- **🔗 OpenTelemetry Integration**: Correlate frontend actions with backend traces
|
|
502
|
+
- **🔒 HTTP Masking**: Protect sensitive data in request/response headers and bodies
|
|
503
|
+
- **⚡ Session Management**: Start, pause, resume, and stop sessions programmatically
|
|
504
|
+
- **📦 Expo Support**: Full compatibility with Expo applications including automatic environment detection
|
|
505
|
+
- **🎨 Session Widget**: Built-in UI widget for user-initiated session recording
|
|
506
|
+
- **📊 Continuous Recording**: Background recording with automatic error capture
|
|
507
|
+
- **🌐 Network Monitoring**: Track HTTP requests and responses with correlation
|
|
508
|
+
|
|
509
|
+
## Gesture Recording & Target Element Information
|
|
510
|
+
|
|
511
|
+
The session recorder automatically captures target element information for all gesture interactions, enriching your OpenTelemetry traces with valuable context about what users are interacting with.
|
|
128
512
|
|
|
129
|
-
|
|
513
|
+
### Captured Attributes
|
|
130
514
|
|
|
131
|
-
|
|
515
|
+
When users interact with elements, the following attributes are automatically added to gesture spans:
|
|
132
516
|
|
|
133
|
-
|
|
517
|
+
| Attribute | Description | Example |
|
|
518
|
+
| ------------------------ | ----------------------------------------- | ----------------- |
|
|
519
|
+
| `gesture.target` | Primary identifier for the target element | `"Submit Button"` |
|
|
520
|
+
| `gesture.target.label` | Accessibility label of the element | `"Submit form"` |
|
|
521
|
+
| `gesture.target.role` | Accessibility role of the element | `"button"` |
|
|
522
|
+
| `gesture.target.test_id` | Test ID of the element | `"submit-btn"` |
|
|
523
|
+
| `gesture.target.text` | Text content of the element | `"Submit"` |
|
|
134
524
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
525
|
+
### How Target Information is Extracted
|
|
526
|
+
|
|
527
|
+
The recorder automatically extracts target information from React Native elements using the following priority:
|
|
528
|
+
|
|
529
|
+
1. **`accessibilityLabel`** - Explicit accessibility label (highest priority)
|
|
530
|
+
2. **Text content** - Text from child elements
|
|
531
|
+
3. **`testID`** - Test identifier (lowest priority)
|
|
532
|
+
|
|
533
|
+
### Best Practices for Better Trace Information
|
|
534
|
+
|
|
535
|
+
To get the most useful target information in your traces, follow these practices:
|
|
536
|
+
|
|
537
|
+
#### 1. Use Accessibility Labels
|
|
538
|
+
|
|
539
|
+
```jsx
|
|
540
|
+
<TouchableOpacity accessibilityLabel='Submit user registration form' accessibilityRole='button' onPress={handleSubmit}>
|
|
541
|
+
<Text>Submit</Text>
|
|
542
|
+
</TouchableOpacity>
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### 2. Add Test IDs for Testing Context
|
|
546
|
+
|
|
547
|
+
```jsx
|
|
548
|
+
<TouchableOpacity testID='registration-submit-btn' accessibilityLabel='Submit registration' onPress={handleSubmit}>
|
|
549
|
+
<Text>Submit</Text>
|
|
550
|
+
</TouchableOpacity>
|
|
138
551
|
```
|
|
139
552
|
|
|
140
|
-
|
|
553
|
+
#### 3. Use Semantic Text Content
|
|
554
|
+
|
|
555
|
+
```jsx
|
|
556
|
+
<TouchableOpacity onPress={handleSubmit}>
|
|
557
|
+
<Text>Submit Registration</Text> {/* Clear, descriptive text */}
|
|
558
|
+
</TouchableOpacity>
|
|
559
|
+
```
|
|
141
560
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
561
|
+
#### 4. Avoid Generic Labels
|
|
562
|
+
|
|
563
|
+
```jsx
|
|
564
|
+
// ❌ Poor trace information
|
|
565
|
+
<TouchableOpacity accessibilityLabel="Button" onPress={handleSubmit}>
|
|
566
|
+
<Text>Click</Text>
|
|
567
|
+
</TouchableOpacity>
|
|
568
|
+
|
|
569
|
+
// ✅ Rich trace information
|
|
570
|
+
<TouchableOpacity
|
|
571
|
+
accessibilityLabel="Submit user registration form"
|
|
572
|
+
testID="registration-submit"
|
|
573
|
+
onPress={handleSubmit}
|
|
574
|
+
>
|
|
575
|
+
<Text>Submit Registration</Text>
|
|
576
|
+
</TouchableOpacity>
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Example Trace Output
|
|
580
|
+
|
|
581
|
+
With proper element labeling, your gesture traces will include rich context:
|
|
582
|
+
|
|
583
|
+
```json
|
|
584
|
+
{
|
|
585
|
+
"spanName": "Gesture.tap",
|
|
586
|
+
"attributes": {
|
|
587
|
+
"gesture.type": "tap",
|
|
588
|
+
"gesture.platform": "react-native",
|
|
589
|
+
"gesture.coordinates.x": 150.5,
|
|
590
|
+
"gesture.coordinates.y": 200.3,
|
|
591
|
+
"gesture.target": "Submit user registration form",
|
|
592
|
+
"gesture.target.label": "Submit user registration form",
|
|
593
|
+
"gesture.target.role": "button",
|
|
594
|
+
"gesture.target.test_id": "registration-submit",
|
|
595
|
+
"gesture.target.text": "Submit Registration"
|
|
596
|
+
}
|
|
597
|
+
}
|
|
145
598
|
```
|
|
146
599
|
|
|
600
|
+
This rich context helps you:
|
|
601
|
+
|
|
602
|
+
- **Debug user interactions** more effectively
|
|
603
|
+
- **Understand user behavior** patterns
|
|
604
|
+
- **Identify UI issues** faster
|
|
605
|
+
- **Correlate frontend actions** with backend events
|
|
606
|
+
|
|
607
|
+
## Screen Recording
|
|
608
|
+
|
|
609
|
+
The session recorder captures your app's UI using `react-native-view-shot`, which:
|
|
610
|
+
|
|
611
|
+
- ✅ **No permissions required** - Captures only your app's interface
|
|
612
|
+
- ✅ **Works out of the box** - No additional setup needed
|
|
613
|
+
- ✅ **Privacy-friendly** - Only captures your app's content, not system UI
|
|
614
|
+
- ❌ **App-only** - Cannot capture other apps or system screens
|
|
615
|
+
|
|
616
|
+
This is different from system-wide screen recording which would require permissions.
|
|
617
|
+
|
|
147
618
|
## Configuration Options
|
|
148
619
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
| `
|
|
620
|
+
### Required Options
|
|
621
|
+
|
|
622
|
+
| Option | Type | Description |
|
|
623
|
+
| ------------- | ------ | ------------------------------ |
|
|
624
|
+
| `apiKey` | string | Your Multiplayer API key |
|
|
625
|
+
| `application` | string | Application name |
|
|
626
|
+
| `version` | string | Application version |
|
|
627
|
+
| `environment` | string | Environment (production, etc.) |
|
|
628
|
+
|
|
629
|
+
### Optional Options
|
|
630
|
+
|
|
631
|
+
| Option | Type | Default | Description |
|
|
632
|
+
| ------------------------------ | ------- | ------- | -------------------------------------- |
|
|
633
|
+
| `recordGestures` | boolean | true | Enable gesture recording |
|
|
634
|
+
| `recordNavigation` | boolean | true | Enable navigation tracking |
|
|
635
|
+
| `recordScreen` | boolean | true | Enable screen recording |
|
|
636
|
+
| `sampleTraceRatio` | number | 0.15 | Trace sampling ratio (0.0-1.0) |
|
|
637
|
+
| `captureBody` | boolean | true | Capture request/response bodies |
|
|
638
|
+
| `captureHeaders` | boolean | true | Capture request/response headers |
|
|
639
|
+
| `masking` | object | - | Data masking configuration |
|
|
640
|
+
| `ignoreUrls` | array | [] | URLs to exclude from monitoring |
|
|
641
|
+
| `propagateTraceHeaderCorsUrls` | array | [] | URLs for CORS trace header propagation |
|
|
642
|
+
| `showContinuousRecording` | boolean | true | Show continuous recording option |
|
|
643
|
+
| `widget` | object | - | Session widget configuration |
|
|
163
644
|
|
|
164
645
|
## Advanced Configuration
|
|
165
646
|
|
|
647
|
+
### Full Configuration Example
|
|
648
|
+
|
|
166
649
|
```javascript
|
|
167
650
|
SessionRecorder.init({
|
|
651
|
+
// Required options
|
|
168
652
|
application: 'my-app',
|
|
169
653
|
version: '1.0.0',
|
|
170
654
|
environment: 'production',
|
|
171
|
-
apiKey: '
|
|
655
|
+
apiKey: 'YOUR_MULTIPLAYER_API_KEY',
|
|
172
656
|
|
|
173
657
|
// Recording options
|
|
174
658
|
recordGestures: true,
|
|
175
659
|
recordNavigation: true,
|
|
176
|
-
recordScreen:
|
|
660
|
+
recordScreen: true, // Captures app UI automatically
|
|
177
661
|
|
|
178
662
|
// Network monitoring
|
|
179
|
-
|
|
663
|
+
// NOTE: if frontend domain doesn't match to backend one, set backend domain to `propagateTraceHeaderCorsUrls` parameter
|
|
664
|
+
propagateTraceHeaderCorsUrls: [
|
|
665
|
+
new RegExp('https://your.backend.api.domain', 'i'), // can be regex or string
|
|
666
|
+
new RegExp('https://another.backend.api.domain', 'i')
|
|
667
|
+
],
|
|
668
|
+
ignoreUrls: [/https:\/\/analytics\.example\.com/, /https:\/\/crashlytics\.com/],
|
|
180
669
|
captureBody: true,
|
|
181
670
|
captureHeaders: true,
|
|
182
671
|
maxCapturingHttpPayloadSize: 100000,
|
|
183
672
|
|
|
184
|
-
//
|
|
185
|
-
|
|
673
|
+
// Data masking for sensitive information
|
|
674
|
+
masking: {
|
|
186
675
|
isContentMaskingEnabled: true,
|
|
187
676
|
maskHeadersList: ['authorization', 'cookie', 'x-api-key'],
|
|
188
|
-
maskBodyFieldsList: ['password', 'token', 'secret']
|
|
677
|
+
maskBodyFieldsList: ['password', 'token', 'secret', 'creditCard'],
|
|
678
|
+
maskTextInputs: true,
|
|
679
|
+
maskImages: false,
|
|
680
|
+
maskButtons: false
|
|
189
681
|
},
|
|
190
682
|
|
|
191
|
-
// Session
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
683
|
+
// Session widget configuration
|
|
684
|
+
widget: {
|
|
685
|
+
enabled: true,
|
|
686
|
+
button: {
|
|
687
|
+
visible: true,
|
|
688
|
+
placement: 'bottomRight' // or 'bottomLeft'
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
// Continuous recording
|
|
693
|
+
showContinuousRecording: true
|
|
196
694
|
})
|
|
197
695
|
```
|
|
198
696
|
|
|
697
|
+
### Environment-Specific Configuration
|
|
698
|
+
|
|
699
|
+
```javascript
|
|
700
|
+
import { SessionRecorder, LogLevel } from '@multiplayer-app/session-recorder-react-native'
|
|
701
|
+
|
|
702
|
+
const config = {
|
|
703
|
+
application: 'my-app',
|
|
704
|
+
version: '1.0.0',
|
|
705
|
+
apiKey: process.env.MULTIPLAYER_API_KEY,
|
|
706
|
+
|
|
707
|
+
// Development-specific options
|
|
708
|
+
...(__DEV__ && {
|
|
709
|
+
logger: {
|
|
710
|
+
enabled: true,
|
|
711
|
+
level: LogLevel.DEBUG
|
|
712
|
+
}
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
SessionRecorder.init(config)
|
|
717
|
+
```
|
|
718
|
+
|
|
199
719
|
## Troubleshooting
|
|
200
720
|
|
|
201
721
|
### Common Issues
|
|
202
722
|
|
|
203
|
-
1.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
723
|
+
#### 1. AsyncStorage Errors
|
|
724
|
+
|
|
725
|
+
```
|
|
726
|
+
[@RNC/AsyncStorage]: NativeModule: AsyncStorage is null
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Solution:**
|
|
730
|
+
|
|
731
|
+
- Ensure `@react-native-async-storage/async-storage` is installed in your app
|
|
732
|
+
- iOS: Run `cd ios && pod install`
|
|
733
|
+
- Clear Metro cache: `npm start -- --reset-cache`
|
|
734
|
+
- Clean builds: Uninstall app and rebuild
|
|
735
|
+
|
|
736
|
+
#### 2. Screen Recording Not Working
|
|
737
|
+
|
|
738
|
+
- Ensure `recordScreen: true` in configuration
|
|
739
|
+
- Check that `react-native-view-shot` is properly installed
|
|
740
|
+
- Verify the app has a valid view to capture
|
|
741
|
+
- Check console logs for capture errors
|
|
742
|
+
|
|
743
|
+
#### 3. Navigation Tracking Not Working
|
|
744
|
+
|
|
745
|
+
- Make sure you've set the navigation ref: `SessionRecorder.setNavigationRef(navigationRef)`
|
|
746
|
+
- For Expo Router: Use `useNavigationContainerRef()` hook
|
|
747
|
+
- For React Navigation: Set ref in `onReady` callback
|
|
748
|
+
|
|
749
|
+
#### 4. Gesture Recording Issues
|
|
750
|
+
|
|
751
|
+
- Gesture recording uses native modules and should work automatically
|
|
752
|
+
- Check that `recordGestures: true` is set
|
|
753
|
+
- Ensure app is not in background mode
|
|
754
|
+
|
|
755
|
+
#### 5. Expo Environment Not Detected
|
|
756
|
+
|
|
757
|
+
- Ensure `expo-constants` is installed: `npx expo install expo-constants`
|
|
758
|
+
- Check that you're using the correct Expo SDK version
|
|
759
|
+
|
|
760
|
+
#### 6. Build Issues
|
|
761
|
+
|
|
762
|
+
- **iOS**: Run `cd ios && pod install` after installing dependencies
|
|
763
|
+
- **Android**: Run `cd android && ./gradlew clean`
|
|
764
|
+
- Clear Metro cache: `npm start -- --reset-cache`
|
|
208
765
|
|
|
209
766
|
### Debug Mode
|
|
210
767
|
|
|
211
|
-
Enable debug logging:
|
|
768
|
+
Enable debug logging to troubleshoot issues:
|
|
212
769
|
|
|
213
770
|
```javascript
|
|
771
|
+
import { SessionRecorder, LogLevel } from '@multiplayer-app/session-recorder-react-native'
|
|
772
|
+
|
|
214
773
|
SessionRecorder.init({
|
|
215
774
|
// ... other config
|
|
216
|
-
|
|
775
|
+
logger: {
|
|
776
|
+
enabled: true,
|
|
777
|
+
level: LogLevel.DEBUG
|
|
778
|
+
}
|
|
217
779
|
})
|
|
218
780
|
```
|
|
219
781
|
|
|
782
|
+
## Examples
|
|
783
|
+
|
|
784
|
+
Check out the complete example applications in the `examples/` directory:
|
|
785
|
+
|
|
786
|
+
- **Bare React Native**: `examples/example-app/` - Full React Native app with session recording
|
|
787
|
+
- **Expo App**: `examples/example-app-expo/` - Expo app with session recording
|
|
788
|
+
|
|
789
|
+
Both examples include:
|
|
790
|
+
|
|
791
|
+
- Complete setup and configuration
|
|
792
|
+
- Navigation integration
|
|
793
|
+
- Session management
|
|
794
|
+
- Error handling
|
|
795
|
+
- Best practices
|
|
796
|
+
|
|
797
|
+
## API Reference
|
|
798
|
+
|
|
799
|
+
### SessionRecorder Methods
|
|
800
|
+
|
|
801
|
+
| Method | Description | Parameters |
|
|
802
|
+
| ----------------------------- | ------------------------------- | ------------------------ |
|
|
803
|
+
| `init(options)` | Initialize the session recorder | `SessionRecorderOptions` |
|
|
804
|
+
| `start()` | Start a new recording session | - |
|
|
805
|
+
| `stop(reason?)` | Stop current recording | `string?` |
|
|
806
|
+
| `pause()` | Pause current recording | - |
|
|
807
|
+
| `resume()` | Resume paused recording | - |
|
|
808
|
+
| `save()` | Save continuous recording | - |
|
|
809
|
+
| `setNavigationRef(ref)` | Set navigation reference | `NavigationContainerRef` |
|
|
810
|
+
| `setSessionAttributes(attrs)` | Set session metadata | `Record<string, any>` |
|
|
811
|
+
|
|
812
|
+
### Configuration Types
|
|
813
|
+
|
|
814
|
+
```typescript
|
|
815
|
+
interface SessionRecorderOptions {
|
|
816
|
+
// Required
|
|
817
|
+
apiKey: string
|
|
818
|
+
application: string
|
|
819
|
+
version: string
|
|
820
|
+
environment: string
|
|
821
|
+
|
|
822
|
+
// Optional
|
|
823
|
+
exporterEndpoint?: string
|
|
824
|
+
apiBaseUrl?: string
|
|
825
|
+
recordGestures?: boolean
|
|
826
|
+
recordNavigation?: boolean
|
|
827
|
+
recordScreen?: boolean
|
|
828
|
+
sampleTraceRatio?: number
|
|
829
|
+
captureBody?: boolean
|
|
830
|
+
captureHeaders?: boolean
|
|
831
|
+
maxCapturingHttpPayloadSize?: number
|
|
832
|
+
masking?: MaskingOptions
|
|
833
|
+
ignoreUrls?: Array<string | RegExp>
|
|
834
|
+
propagateTraceHeaderCorsUrls?: PropagateTraceHeaderCorsUrls
|
|
835
|
+
showContinuousRecording?: boolean
|
|
836
|
+
schemifyDocSpanPayload?: boolean
|
|
837
|
+
widget?: WidgetConfig
|
|
838
|
+
logger?: {
|
|
839
|
+
level?: number
|
|
840
|
+
enabled?: boolean
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
```
|
|
844
|
+
|
|
220
845
|
## Contributing
|
|
221
846
|
|
|
222
847
|
Please read our contributing guidelines before submitting pull requests.
|