@cxpinsight/react-native 0.2.0
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/LICENSE +21 -0
- package/README.md +131 -0
- package/babel.js +101 -0
- package/instrumented/Pressable.d.ts +2 -0
- package/instrumented/Pressable.js +2 -0
- package/instrumented/ScrollView.d.ts +2 -0
- package/instrumented/ScrollView.js +2 -0
- package/instrumented/TextInput.d.ts +2 -0
- package/instrumented/TextInput.js +2 -0
- package/instrumented/TouchableOpacity.d.ts +2 -0
- package/instrumented/TouchableOpacity.js +2 -0
- package/lib/CXPinsight.d.ts +113 -0
- package/lib/CXPinsight.d.ts.map +1 -0
- package/lib/CXPinsight.js +831 -0
- package/lib/CXPinsight.js.map +1 -0
- package/lib/CXPinsightProvider.d.ts +19 -0
- package/lib/CXPinsightProvider.d.ts.map +1 -0
- package/lib/CXPinsightProvider.js +382 -0
- package/lib/CXPinsightProvider.js.map +1 -0
- package/lib/core/autoScreenTracker.d.ts +20 -0
- package/lib/core/autoScreenTracker.d.ts.map +1 -0
- package/lib/core/autoScreenTracker.js +66 -0
- package/lib/core/autoScreenTracker.js.map +1 -0
- package/lib/core/deepLinkTracker.d.ts +17 -0
- package/lib/core/deepLinkTracker.d.ts.map +1 -0
- package/lib/core/deepLinkTracker.js +81 -0
- package/lib/core/deepLinkTracker.js.map +1 -0
- package/lib/core/deviceInfo.d.ts +14 -0
- package/lib/core/deviceInfo.d.ts.map +1 -0
- package/lib/core/deviceInfo.js +166 -0
- package/lib/core/deviceInfo.js.map +1 -0
- package/lib/core/eventQueue.d.ts +23 -0
- package/lib/core/eventQueue.d.ts.map +1 -0
- package/lib/core/eventQueue.js +240 -0
- package/lib/core/eventQueue.js.map +1 -0
- package/lib/core/lifecycle.d.ts +18 -0
- package/lib/core/lifecycle.d.ts.map +1 -0
- package/lib/core/lifecycle.js +127 -0
- package/lib/core/lifecycle.js.map +1 -0
- package/lib/core/mobileRecorder.d.ts +15 -0
- package/lib/core/mobileRecorder.d.ts.map +1 -0
- package/lib/core/mobileRecorder.js +231 -0
- package/lib/core/mobileRecorder.js.map +1 -0
- package/lib/core/network.d.ts +10 -0
- package/lib/core/network.d.ts.map +1 -0
- package/lib/core/network.js +74 -0
- package/lib/core/network.js.map +1 -0
- package/lib/core/networkCapture.d.ts +22 -0
- package/lib/core/networkCapture.d.ts.map +1 -0
- package/lib/core/networkCapture.js +100 -0
- package/lib/core/networkCapture.js.map +1 -0
- package/lib/core/scrollCapture.d.ts +48 -0
- package/lib/core/scrollCapture.d.ts.map +1 -0
- package/lib/core/scrollCapture.js +221 -0
- package/lib/core/scrollCapture.js.map +1 -0
- package/lib/core/session.d.ts +15 -0
- package/lib/core/session.d.ts.map +1 -0
- package/lib/core/session.js +157 -0
- package/lib/core/session.js.map +1 -0
- package/lib/core/storage.d.ts +11 -0
- package/lib/core/storage.d.ts.map +1 -0
- package/lib/core/storage.js +59 -0
- package/lib/core/storage.js.map +1 -0
- package/lib/core/triggerEngine.d.ts +56 -0
- package/lib/core/triggerEngine.d.ts.map +1 -0
- package/lib/core/triggerEngine.js +432 -0
- package/lib/core/triggerEngine.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -0
- package/lib/instrumented/Pressable.d.ts +9 -0
- package/lib/instrumented/Pressable.d.ts.map +1 -0
- package/lib/instrumented/Pressable.js +96 -0
- package/lib/instrumented/Pressable.js.map +1 -0
- package/lib/instrumented/ScrollView.d.ts +6 -0
- package/lib/instrumented/ScrollView.d.ts.map +1 -0
- package/lib/instrumented/ScrollView.js +101 -0
- package/lib/instrumented/ScrollView.js.map +1 -0
- package/lib/instrumented/TextInput.d.ts +9 -0
- package/lib/instrumented/TextInput.d.ts.map +1 -0
- package/lib/instrumented/TextInput.js +75 -0
- package/lib/instrumented/TextInput.js.map +1 -0
- package/lib/instrumented/TouchableOpacity.d.ts +11 -0
- package/lib/instrumented/TouchableOpacity.d.ts.map +1 -0
- package/lib/instrumented/TouchableOpacity.js +96 -0
- package/lib/instrumented/TouchableOpacity.js.map +1 -0
- package/lib/instrumented/index.d.ts +19 -0
- package/lib/instrumented/index.d.ts.map +1 -0
- package/lib/instrumented/index.js +28 -0
- package/lib/instrumented/index.js.map +1 -0
- package/lib/instrumented/interactionObserver.d.ts +29 -0
- package/lib/instrumented/interactionObserver.d.ts.map +1 -0
- package/lib/instrumented/interactionObserver.js +38 -0
- package/lib/instrumented/interactionObserver.js.map +1 -0
- package/lib/setup/AccessibilityScanner.d.ts +32 -0
- package/lib/setup/AccessibilityScanner.d.ts.map +1 -0
- package/lib/setup/AccessibilityScanner.js +127 -0
- package/lib/setup/AccessibilityScanner.js.map +1 -0
- package/lib/setup/ElementIdentifier.d.ts +65 -0
- package/lib/setup/ElementIdentifier.d.ts.map +1 -0
- package/lib/setup/ElementIdentifier.js +114 -0
- package/lib/setup/ElementIdentifier.js.map +1 -0
- package/lib/setup/ElementRegistry.d.ts +22 -0
- package/lib/setup/ElementRegistry.d.ts.map +1 -0
- package/lib/setup/ElementRegistry.js +47 -0
- package/lib/setup/ElementRegistry.js.map +1 -0
- package/lib/setup/SetupCodeEntry.d.ts +15 -0
- package/lib/setup/SetupCodeEntry.d.ts.map +1 -0
- package/lib/setup/SetupCodeEntry.js +198 -0
- package/lib/setup/SetupCodeEntry.js.map +1 -0
- package/lib/setup/SetupController.d.ts +29 -0
- package/lib/setup/SetupController.d.ts.map +1 -0
- package/lib/setup/SetupController.js +189 -0
- package/lib/setup/SetupController.js.map +1 -0
- package/lib/setup/SetupOverlay.d.ts +10 -0
- package/lib/setup/SetupOverlay.d.ts.map +1 -0
- package/lib/setup/SetupOverlay.js +408 -0
- package/lib/setup/SetupOverlay.js.map +1 -0
- package/lib/setup/TapInterceptor.d.ts +19 -0
- package/lib/setup/TapInterceptor.d.ts.map +1 -0
- package/lib/setup/TapInterceptor.js +98 -0
- package/lib/setup/TapInterceptor.js.map +1 -0
- package/lib/setup/TouchObserver.d.ts +25 -0
- package/lib/setup/TouchObserver.d.ts.map +1 -0
- package/lib/setup/TouchObserver.js +88 -0
- package/lib/setup/TouchObserver.js.map +1 -0
- package/lib/setup/TouchPatcher.d.ts +27 -0
- package/lib/setup/TouchPatcher.d.ts.map +1 -0
- package/lib/setup/TouchPatcher.js +182 -0
- package/lib/setup/TouchPatcher.js.map +1 -0
- package/lib/setup/index.d.ts +13 -0
- package/lib/setup/index.d.ts.map +1 -0
- package/lib/setup/index.js +45 -0
- package/lib/setup/index.js.map +1 -0
- package/lib/setup/useCXPElement.d.ts +25 -0
- package/lib/setup/useCXPElement.d.ts.map +1 -0
- package/lib/setup/useCXPElement.js +33 -0
- package/lib/setup/useCXPElement.js.map +1 -0
- package/lib/survey/SurveyModal.d.ts +10 -0
- package/lib/survey/SurveyModal.d.ts.map +1 -0
- package/lib/survey/SurveyModal.js +1650 -0
- package/lib/survey/SurveyModal.js.map +1 -0
- package/lib/survey/expressionEval.d.ts +10 -0
- package/lib/survey/expressionEval.d.ts.map +1 -0
- package/lib/survey/expressionEval.js +287 -0
- package/lib/survey/expressionEval.js.map +1 -0
- package/lib/survey/frequencyCap.d.ts +15 -0
- package/lib/survey/frequencyCap.d.ts.map +1 -0
- package/lib/survey/frequencyCap.js +116 -0
- package/lib/survey/frequencyCap.js.map +1 -0
- package/lib/survey/handsFreeVoice.d.ts +30 -0
- package/lib/survey/handsFreeVoice.d.ts.map +1 -0
- package/lib/survey/handsFreeVoice.js +312 -0
- package/lib/survey/handsFreeVoice.js.map +1 -0
- package/lib/survey/interpolate.d.ts +6 -0
- package/lib/survey/interpolate.d.ts.map +1 -0
- package/lib/survey/interpolate.js +61 -0
- package/lib/survey/interpolate.js.map +1 -0
- package/lib/survey/pagesFromV1.d.ts +6 -0
- package/lib/survey/pagesFromV1.d.ts.map +1 -0
- package/lib/survey/pagesFromV1.js +83 -0
- package/lib/survey/pagesFromV1.js.map +1 -0
- package/lib/survey/questions/CSATQuestion.d.ts +16 -0
- package/lib/survey/questions/CSATQuestion.d.ts.map +1 -0
- package/lib/survey/questions/CSATQuestion.js +37 -0
- package/lib/survey/questions/CSATQuestion.js.map +1 -0
- package/lib/survey/questions/DateQuestion.d.ts +20 -0
- package/lib/survey/questions/DateQuestion.d.ts.map +1 -0
- package/lib/survey/questions/DateQuestion.js +103 -0
- package/lib/survey/questions/DateQuestion.js.map +1 -0
- package/lib/survey/questions/ImagePickerQuestion.d.ts +33 -0
- package/lib/survey/questions/ImagePickerQuestion.d.ts.map +1 -0
- package/lib/survey/questions/ImagePickerQuestion.js +68 -0
- package/lib/survey/questions/ImagePickerQuestion.js.map +1 -0
- package/lib/survey/questions/ImageQuestion.d.ts +26 -0
- package/lib/survey/questions/ImageQuestion.d.ts.map +1 -0
- package/lib/survey/questions/ImageQuestion.js +24 -0
- package/lib/survey/questions/ImageQuestion.js.map +1 -0
- package/lib/survey/questions/MatrixCell.d.ts +45 -0
- package/lib/survey/questions/MatrixCell.d.ts.map +1 -0
- package/lib/survey/questions/MatrixCell.js +54 -0
- package/lib/survey/questions/MatrixCell.js.map +1 -0
- package/lib/survey/questions/MatrixDropdownQuestion.d.ts +29 -0
- package/lib/survey/questions/MatrixDropdownQuestion.d.ts.map +1 -0
- package/lib/survey/questions/MatrixDropdownQuestion.js +42 -0
- package/lib/survey/questions/MatrixDropdownQuestion.js.map +1 -0
- package/lib/survey/questions/MatrixDynamicQuestion.d.ts +26 -0
- package/lib/survey/questions/MatrixDynamicQuestion.d.ts.map +1 -0
- package/lib/survey/questions/MatrixDynamicQuestion.js +52 -0
- package/lib/survey/questions/MatrixDynamicQuestion.js.map +1 -0
- package/lib/survey/questions/MatrixQuestion.d.ts +38 -0
- package/lib/survey/questions/MatrixQuestion.d.ts.map +1 -0
- package/lib/survey/questions/MatrixQuestion.js +64 -0
- package/lib/survey/questions/MatrixQuestion.js.map +1 -0
- package/lib/survey/questions/MultiTextQuestion.d.ts +19 -0
- package/lib/survey/questions/MultiTextQuestion.d.ts.map +1 -0
- package/lib/survey/questions/MultiTextQuestion.js +64 -0
- package/lib/survey/questions/MultiTextQuestion.js.map +1 -0
- package/lib/survey/questions/MultipleChoiceQuestion.d.ts +25 -0
- package/lib/survey/questions/MultipleChoiceQuestion.d.ts.map +1 -0
- package/lib/survey/questions/MultipleChoiceQuestion.js +111 -0
- package/lib/survey/questions/MultipleChoiceQuestion.js.map +1 -0
- package/lib/survey/questions/NPSQuestion.d.ts +18 -0
- package/lib/survey/questions/NPSQuestion.d.ts.map +1 -0
- package/lib/survey/questions/NPSQuestion.js +62 -0
- package/lib/survey/questions/NPSQuestion.js.map +1 -0
- package/lib/survey/questions/PanelDynamicQuestion.d.ts +50 -0
- package/lib/survey/questions/PanelDynamicQuestion.d.ts.map +1 -0
- package/lib/survey/questions/PanelDynamicQuestion.js +62 -0
- package/lib/survey/questions/PanelDynamicQuestion.js.map +1 -0
- package/lib/survey/questions/RankingQuestion.d.ts +34 -0
- package/lib/survey/questions/RankingQuestion.d.ts.map +1 -0
- package/lib/survey/questions/RankingQuestion.js +85 -0
- package/lib/survey/questions/RankingQuestion.js.map +1 -0
- package/lib/survey/questions/RatingQuestion.d.ts +20 -0
- package/lib/survey/questions/RatingQuestion.d.ts.map +1 -0
- package/lib/survey/questions/RatingQuestion.js +53 -0
- package/lib/survey/questions/RatingQuestion.js.map +1 -0
- package/lib/survey/questions/TextQuestion.d.ts +17 -0
- package/lib/survey/questions/TextQuestion.d.ts.map +1 -0
- package/lib/survey/questions/TextQuestion.js +46 -0
- package/lib/survey/questions/TextQuestion.js.map +1 -0
- package/lib/survey/styleContract.d.ts +230 -0
- package/lib/survey/styleContract.d.ts.map +1 -0
- package/lib/survey/styleContract.js +365 -0
- package/lib/survey/styleContract.js.map +1 -0
- package/lib/survey/themePalette.d.ts +56 -0
- package/lib/survey/themePalette.d.ts.map +1 -0
- package/lib/survey/themePalette.js +63 -0
- package/lib/survey/themePalette.js.map +1 -0
- package/lib/survey/translationLookup.d.ts +4 -0
- package/lib/survey/translationLookup.d.ts.map +1 -0
- package/lib/survey/translationLookup.js +62 -0
- package/lib/survey/translationLookup.js.map +1 -0
- package/lib/survey/validate.d.ts +3 -0
- package/lib/survey/validate.d.ts.map +1 -0
- package/lib/survey/validate.js +159 -0
- package/lib/survey/validate.js.map +1 -0
- package/lib/survey/variablesResolver.d.ts +10 -0
- package/lib/survey/variablesResolver.d.ts.map +1 -0
- package/lib/survey/variablesResolver.js +107 -0
- package/lib/survey/variablesResolver.js.map +1 -0
- package/lib/survey/voiceParsers.d.ts +47 -0
- package/lib/survey/voiceParsers.d.ts.map +1 -0
- package/lib/survey/voiceParsers.js +310 -0
- package/lib/survey/voiceParsers.js.map +1 -0
- package/lib/types.d.ts +349 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +20 -0
- package/lib/types.js.map +1 -0
- package/metro.js +55 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CXPinsight
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @cxpinsight/react-native
|
|
2
|
+
|
|
3
|
+
Engagement tracking, native survey modals, session replay and visual setup mode for React Native and Expo apps.
|
|
4
|
+
|
|
5
|
+
Install once. New surveys, triggers and capture settings ship from the CXPinsight dashboard — no app release required.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @cxpinsight/react-native
|
|
9
|
+
npx expo install react-native-view-shot # optional — screenshots in the replay
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
### 1. Auto-instrument taps, inputs and scroll
|
|
15
|
+
|
|
16
|
+
Add the Babel plugin so taps, text input and scroll are captured without touching your screens.
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
// babel.config.js
|
|
20
|
+
module.exports = function (api) {
|
|
21
|
+
api.cache(true);
|
|
22
|
+
return {
|
|
23
|
+
presets: ['babel-preset-expo'],
|
|
24
|
+
plugins: ['@cxpinsight/react-native/babel'],
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The plugin rewrites `TouchableOpacity`, `Pressable`, `TextInput` and `ScrollView` imports in **your** source only — never inside `node_modules`, and never inside the SDK itself.
|
|
30
|
+
|
|
31
|
+
### 2. Initialise at startup
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { CXPinsight } from '@cxpinsight/react-native';
|
|
35
|
+
import { captureScreen } from 'react-native-view-shot';
|
|
36
|
+
|
|
37
|
+
CXPinsight.init({
|
|
38
|
+
applicationId: 'YOUR_APPLICATION_ID',
|
|
39
|
+
apiKey: 'YOUR_API_KEY',
|
|
40
|
+
apiBase: 'https://your-gateway.example.com',
|
|
41
|
+
|
|
42
|
+
record: true, // session replay: screens, taps, scroll, inputs
|
|
43
|
+
recordMaskInputs: true, // never store typed text
|
|
44
|
+
captureScreen: () => // optional screenshots in the replay timeline
|
|
45
|
+
captureScreen({ format: 'jpg', quality: 0.3, result: 'base64' }),
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
On a physical device `apiBase` must be reachable from the device — use your machine's LAN IP, not `localhost`. The SDK checks this at startup and logs a specific message if it looks wrong.
|
|
50
|
+
|
|
51
|
+
### 3. Report screen changes
|
|
52
|
+
|
|
53
|
+
```jsx
|
|
54
|
+
import { useRef } from 'react';
|
|
55
|
+
import { CXPinsightProvider, CXPinsight } from '@cxpinsight/react-native';
|
|
56
|
+
|
|
57
|
+
const navigationRef = useRef(null);
|
|
58
|
+
|
|
59
|
+
<CXPinsightProvider navigationRef={navigationRef}>
|
|
60
|
+
<NavigationContainer
|
|
61
|
+
ref={navigationRef}
|
|
62
|
+
onStateChange={() => {
|
|
63
|
+
const name = navigationRef.current?.getCurrentRoute()?.name;
|
|
64
|
+
if (name) CXPinsight.trackScreen(name);
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
{/* your navigators */}
|
|
68
|
+
</NavigationContainer>
|
|
69
|
+
</CXPinsightProvider>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`CXPinsightProvider` also hosts the survey modal and setup overlay, so it must wrap the app for surveys to appear.
|
|
73
|
+
|
|
74
|
+
### 4. Identify the user after sign-in
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
CXPinsight.identify({ id: user.id, email: user.email, name: user.name });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Events recorded before `identify()` are re-attributed to the user automatically, so one visitor does not show up as two.
|
|
81
|
+
|
|
82
|
+
## API
|
|
83
|
+
|
|
84
|
+
| Method | Purpose |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| `init(config, callbacks?)` | Start the SDK. Call once at startup. |
|
|
87
|
+
| `identify(user)` | Attach a real user identity; re-attributes prior anonymous activity. |
|
|
88
|
+
| `track(name, data?)` | Record a custom event. |
|
|
89
|
+
| `trackScreen(name, data?)` | Record a screen view. |
|
|
90
|
+
| `trackFunnelStep(...)` / `trackExperiment(...)` / `trackConversion(...)` | Typed helpers over `track`. |
|
|
91
|
+
| `showSurvey(surveyId)` | Present a survey immediately. |
|
|
92
|
+
| `startRecording()` / `stopRecording()` | Session replay, for hosts that gate on their own consent UI. |
|
|
93
|
+
| `enterSetupMode()` / `exitSetupMode()` | Visual element mapping — tap an element to make it trackable. |
|
|
94
|
+
| `flush()` | Force-send queued events. |
|
|
95
|
+
| `reset()` | Clear the stored identity, session and frequency caps. |
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
| Option | Default | |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| `applicationId` | — | **Required.** |
|
|
102
|
+
| `apiKey` | — | **Required.** |
|
|
103
|
+
| `apiBase` | — | Your CXPinsight gateway URL. |
|
|
104
|
+
| `record` | dashboard | Session replay. Omit to follow the dashboard toggle. |
|
|
105
|
+
| `recordMaskInputs` | `true` | Never persist typed text. |
|
|
106
|
+
| `captureScreen` | — | Screenshot provider; omit for a timeline-only replay. |
|
|
107
|
+
| `captureNetwork` | `true` | Sanitised `api_call` events — method, host, path, status. Never bodies or headers. |
|
|
108
|
+
| `sessionTimeout` | 30 min | Inactivity before a new session starts. |
|
|
109
|
+
| `flushInterval` / `flushThreshold` | 30 s / 10 | Event batching. |
|
|
110
|
+
| `theme` | OS | `'light'` / `'dark'` if your app has its own toggle. |
|
|
111
|
+
| `brandingPalette` | — | Your app's colours, so surveys can match them. |
|
|
112
|
+
| `debug` | `false` | Verbose logging. |
|
|
113
|
+
|
|
114
|
+
Values omitted here are filled from the application's dashboard settings at startup, so capture behaviour can change without an app release.
|
|
115
|
+
|
|
116
|
+
## Privacy
|
|
117
|
+
|
|
118
|
+
- Typed text is never stored in replays when `recordMaskInputs` is on (the default).
|
|
119
|
+
- Network capture records method, host, path, status and duration only. Query strings are stripped; request and response bodies and headers are never read.
|
|
120
|
+
- The SDK's own backend calls are excluded from network capture.
|
|
121
|
+
- Events are queued locally and persist across launches, so nothing is lost offline.
|
|
122
|
+
|
|
123
|
+
## Requirements
|
|
124
|
+
|
|
125
|
+
- React Native 0.72+ or Expo SDK 49+
|
|
126
|
+
- `@react-native-async-storage/async-storage` (required peer dependency)
|
|
127
|
+
- Optional: `@react-native-community/datetimepicker` for date questions, `expo-speech` and `expo-speech-recognition` for voice surveys, `react-native-view-shot` for replay screenshots, `expo-constants` and `expo-localization` for richer device metadata
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
package/babel.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CXP Babel Plugin — automatically replaces React Native touch component
|
|
3
|
+
* imports with CXP's instrumented versions at build time.
|
|
4
|
+
*
|
|
5
|
+
* Usage in babel.config.js:
|
|
6
|
+
*
|
|
7
|
+
* module.exports = function(api) {
|
|
8
|
+
* api.cache(true);
|
|
9
|
+
* return {
|
|
10
|
+
* presets: ['babel-preset-expo'],
|
|
11
|
+
* plugins: ['@cxpinsight/react-native/babel'],
|
|
12
|
+
* };
|
|
13
|
+
* };
|
|
14
|
+
*
|
|
15
|
+
* This transforms:
|
|
16
|
+
* import { TouchableOpacity, Pressable, TextInput } from 'react-native';
|
|
17
|
+
*
|
|
18
|
+
* Into:
|
|
19
|
+
* import { TouchableOpacity } from '@cxpinsight/react-native/instrumented/TouchableOpacity';
|
|
20
|
+
*
|
|
21
|
+
* That path is a re-export of the package's own build output (see
|
|
22
|
+
* scripts/make-shims.js), so the instrumented components an app loads are the
|
|
23
|
+
* SAME module instance the SDK subscribes to. Pointing it anywhere else — src/,
|
|
24
|
+
* or a second module format — gives the app one copy and the SDK another, and
|
|
25
|
+
* taps are then delivered to a listener list nobody is subscribed to.
|
|
26
|
+
* import { Pressable } from '@cxpinsight/react-native/instrumented/Pressable';
|
|
27
|
+
* import { TextInput } from '@cxpinsight/react-native/instrumented/TextInput';
|
|
28
|
+
* // (other imports from 'react-native' are left untouched)
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const INSTRUMENTED_COMPONENTS = {
|
|
32
|
+
TouchableOpacity: '@cxpinsight/react-native/instrumented/TouchableOpacity',
|
|
33
|
+
Pressable: '@cxpinsight/react-native/instrumented/Pressable',
|
|
34
|
+
TextInput: '@cxpinsight/react-native/instrumented/TextInput',
|
|
35
|
+
ScrollView: '@cxpinsight/react-native/instrumented/ScrollView',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = function cxpInsightBabelPlugin({ types: t }) {
|
|
39
|
+
return {
|
|
40
|
+
name: 'cxpinsight-auto-instrument',
|
|
41
|
+
visitor: {
|
|
42
|
+
ImportDeclaration(path, state) {
|
|
43
|
+
if (path.node.source.value !== 'react-native') return;
|
|
44
|
+
|
|
45
|
+
// CRITICAL: Only instrument the app's own source. Never rewrite files inside
|
|
46
|
+
// node_modules — rewriting react-native's own internals (e.g. VirtualizedList,
|
|
47
|
+
// which imports ScrollView from 'react-native') creates a circular dependency
|
|
48
|
+
// that leaves react-native's contexts half-initialized ("Cannot read property
|
|
49
|
+
// 'Consumer' of undefined"). Also skip the SDK itself, whose instrumented
|
|
50
|
+
// components must import from the real 'react-native'.
|
|
51
|
+
const filename = state.filename || state.file?.opts?.filename || '';
|
|
52
|
+
if (
|
|
53
|
+
filename.includes('/node_modules/') ||
|
|
54
|
+
filename.includes('cxpinsight-react-native') ||
|
|
55
|
+
filename.includes('@cxpinsight/react-native') ||
|
|
56
|
+
filename.includes('cxpinsight/react-native')
|
|
57
|
+
) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const specifiersToRedirect = [];
|
|
62
|
+
const specifiersToKeep = [];
|
|
63
|
+
|
|
64
|
+
for (const specifier of path.node.specifiers) {
|
|
65
|
+
if (
|
|
66
|
+
t.isImportSpecifier(specifier) &&
|
|
67
|
+
t.isIdentifier(specifier.imported) &&
|
|
68
|
+
INSTRUMENTED_COMPONENTS[specifier.imported.name]
|
|
69
|
+
) {
|
|
70
|
+
specifiersToRedirect.push(specifier);
|
|
71
|
+
} else {
|
|
72
|
+
specifiersToKeep.push(specifier);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (specifiersToRedirect.length === 0) return;
|
|
77
|
+
|
|
78
|
+
// Create new import declarations for instrumented components
|
|
79
|
+
const newImports = specifiersToRedirect.map((specifier) => {
|
|
80
|
+
const componentName = specifier.imported.name;
|
|
81
|
+
const source = INSTRUMENTED_COMPONENTS[componentName];
|
|
82
|
+
return t.importDeclaration(
|
|
83
|
+
[t.importSpecifier(specifier.local, t.identifier(componentName))],
|
|
84
|
+
t.stringLiteral(source),
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (specifiersToKeep.length > 0) {
|
|
89
|
+
// Replace original with remaining specifiers + add new imports
|
|
90
|
+
path.node.specifiers = specifiersToKeep;
|
|
91
|
+
for (const imp of newImports) {
|
|
92
|
+
path.insertAfter(imp);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
// All specifiers were redirected — replace entire import
|
|
96
|
+
path.replaceWithMultiple(newImports);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { CXPinsightConfig, CXPinsightCallbacks, UserIdentity, FunnelStepOptions, ExperimentOptions, ConversionOptions } from './types';
|
|
2
|
+
type SurveyPresenter = (surveyId: string) => void;
|
|
3
|
+
type SetupPresenter = (show: boolean) => void;
|
|
4
|
+
declare class CXPinsightSDK {
|
|
5
|
+
private initialized;
|
|
6
|
+
private config;
|
|
7
|
+
private callbacks;
|
|
8
|
+
private userId;
|
|
9
|
+
private userIdentity;
|
|
10
|
+
private surveyPresenter;
|
|
11
|
+
private setupPresenter;
|
|
12
|
+
private autoEventUnsub;
|
|
13
|
+
private currentScreen;
|
|
14
|
+
private previousScreen;
|
|
15
|
+
private engagementStartTs;
|
|
16
|
+
private engagementAccumMs;
|
|
17
|
+
private engagementActive;
|
|
18
|
+
private startEngagementClock;
|
|
19
|
+
private pauseEngagementClock;
|
|
20
|
+
private resumeEngagementClock;
|
|
21
|
+
private getEngagementMs;
|
|
22
|
+
private static errorHandlerInstalled;
|
|
23
|
+
/** Initialize the SDK. Call once at app startup. */
|
|
24
|
+
init(config: CXPinsightConfig, callbacks?: CXPinsightCallbacks): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* P1 — merge the server's canonical SdkConfig into `config`, filling only the
|
|
27
|
+
* flat init() fields the app left undefined (client always wins). Bounded to a
|
|
28
|
+
* short timeout so a slow network never stalls init; any failure is swallowed
|
|
29
|
+
* and the app's config/defaults stand. Runs before the capture/session/queue
|
|
30
|
+
* consumers in init().
|
|
31
|
+
*/
|
|
32
|
+
private applyServerSdkConfig;
|
|
33
|
+
/** Roll the recording + engagement clock onto a freshly-started session. */
|
|
34
|
+
private onSessionRollover;
|
|
35
|
+
/** Wire native signals → typed analytics events (shared taxonomy). */
|
|
36
|
+
private startAutoEvents;
|
|
37
|
+
/** Track a custom event */
|
|
38
|
+
/**
|
|
39
|
+
* One-shot reachability check of `apiBase` at init. Logs a precise, actionable
|
|
40
|
+
* warning for the common misconfigurations (frontend port, a service instead of the
|
|
41
|
+
* gateway, or localhost on a physical device). Never throws or blocks init.
|
|
42
|
+
*/
|
|
43
|
+
private verifyConnectivity;
|
|
44
|
+
track(eventName: string, data?: Record<string, unknown>, eventType?: string, teeToRecording?: boolean): void;
|
|
45
|
+
/** Track a screen view (triggers remote page_view rules) */
|
|
46
|
+
trackScreen(screenName: string, data?: Record<string, unknown>): void;
|
|
47
|
+
/** Identify the current user */
|
|
48
|
+
identify(user: UserIdentity): Promise<void>;
|
|
49
|
+
/** Track a funnel step */
|
|
50
|
+
trackFunnelStep(funnelId: string, stepNumber: number, stepName?: string, options?: FunnelStepOptions): void;
|
|
51
|
+
/** Track an experiment impression */
|
|
52
|
+
trackExperiment(experimentId: string, variantId: string, options?: ExperimentOptions): void;
|
|
53
|
+
/** Track a conversion event */
|
|
54
|
+
trackConversion(eventName: string, options?: ConversionOptions): void;
|
|
55
|
+
/** Enter setup mode. Shows the setup code entry UI. */
|
|
56
|
+
enterSetupMode(): void;
|
|
57
|
+
/** Exit setup mode and clean up. */
|
|
58
|
+
exitSetupMode(): Promise<void>;
|
|
59
|
+
/** Check if setup mode is currently active. */
|
|
60
|
+
isInSetupMode(): boolean;
|
|
61
|
+
/** Get the current setup session state. */
|
|
62
|
+
getSetupState(): import("./setup/SetupController").SetupSessionState | null;
|
|
63
|
+
/** Get the stable device ID (generates one if first time). */
|
|
64
|
+
getDeviceId(): Promise<string>;
|
|
65
|
+
/** Programmatically show a survey */
|
|
66
|
+
showSurvey(surveyId: string): void;
|
|
67
|
+
/**
|
|
68
|
+
* Start mobile session (timeline) recording. Use this when gating on your own
|
|
69
|
+
* consent UI: show your banner, then call after the user accepts. No-op if
|
|
70
|
+
* already recording or the SDK isn't initialized.
|
|
71
|
+
*/
|
|
72
|
+
startRecording(): Promise<void>;
|
|
73
|
+
/** Stop mobile session recording and flush the final chunk. */
|
|
74
|
+
stopRecording(): Promise<void>;
|
|
75
|
+
/** Reset all SDK state (call on logout) */
|
|
76
|
+
reset(): Promise<void>;
|
|
77
|
+
/** Manual flush for testing */
|
|
78
|
+
flush(): Promise<void>;
|
|
79
|
+
/** @internal Register the survey presenter from CXPinsightProvider */
|
|
80
|
+
_registerSurveyPresenter(presenter: SurveyPresenter): void;
|
|
81
|
+
/** @internal Unregister the survey presenter */
|
|
82
|
+
_unregisterSurveyPresenter(): void;
|
|
83
|
+
/** @internal Register the setup presenter from CXPinsightProvider */
|
|
84
|
+
_registerSetupPresenter(presenter: SetupPresenter): void;
|
|
85
|
+
/** @internal Unregister the setup presenter */
|
|
86
|
+
_unregisterSetupPresenter(): void;
|
|
87
|
+
/** @internal Get callbacks */
|
|
88
|
+
_getCallbacks(): CXPinsightCallbacks;
|
|
89
|
+
/** @internal Get userId */
|
|
90
|
+
_getUserId(): string;
|
|
91
|
+
/** @internal Get the full identity blob (or null if identify() was
|
|
92
|
+
* never called). Consumed by the variables resolver so
|
|
93
|
+
* {source: 'sdk'} v1.1 variables interpolate to identify()-supplied
|
|
94
|
+
* values. Return type kept broad ({[k]:unknown}) because the caller
|
|
95
|
+
* looks up variable-name keys against it, not typed properties. */
|
|
96
|
+
_getUserIdentity(): Record<string, unknown> | null;
|
|
97
|
+
/** @internal Get config */
|
|
98
|
+
_getConfig(): CXPinsightConfig | null;
|
|
99
|
+
/** @internal Host-supplied palette override from CXPinsight.init({ brandingPalette }).
|
|
100
|
+
* Read by SurveyModal to layer over survey.branding.palette + defaults.
|
|
101
|
+
* Returns null when the app didn't pass one — palette resolver falls back. */
|
|
102
|
+
_getInitBrandingPalette(): {
|
|
103
|
+
light?: Record<string, string>;
|
|
104
|
+
dark?: Record<string, string>;
|
|
105
|
+
} | null;
|
|
106
|
+
/** @internal Check initialization */
|
|
107
|
+
_isInitialized(): boolean;
|
|
108
|
+
private log;
|
|
109
|
+
}
|
|
110
|
+
/** Singleton SDK instance */
|
|
111
|
+
export declare const CXPinsight: CXPinsightSDK;
|
|
112
|
+
export {};
|
|
113
|
+
//# sourceMappingURL=CXPinsight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CXPinsight.d.ts","sourceRoot":"","sources":["../src/CXPinsight.ts"],"names":[],"mappings":"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"}
|