react-native-uxrate 0.2.1 → 0.3.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.
@@ -39,5 +39,5 @@ repositories {
39
39
 
40
40
  dependencies {
41
41
  implementation 'com.facebook.react:react-native:+'
42
- implementation 'com.uxrate:uxrate-sdk:[0.2.0, 0.3.0)'
42
+ implementation 'com.uxrate:uxrate-sdk:[0.3.0, 0.4.0)'
43
43
  }
@@ -3,18 +3,10 @@ package com.uxrate.reactnative
3
3
  import android.app.Application
4
4
  import com.facebook.react.bridge.*
5
5
  import com.uxrate.sdk.UXRate
6
+ import com.uxrate.sdk.models.Environment
6
7
  import com.uxrate.sdk.models.OverlapStrategy
7
8
  import com.uxrate.sdk.models.SDKTheme
8
9
 
9
- /**
10
- * React Native native module for the UXRate Android SDK.
11
- *
12
- * Exposes the same 4 methods as the iOS module:
13
- * - configure(apiKey, options)
14
- * - identify(userId, properties)
15
- * - track(event)
16
- * - setScreen(name)
17
- */
18
10
  class UXRateModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
19
11
 
20
12
  override fun getName(): String = "UXRate"
@@ -32,9 +24,16 @@ class UXRateModule(reactContext: ReactApplicationContext) : ReactContextBaseJava
32
24
  options.getBoolean("autoTrackScreens")
33
25
  } else false
34
26
 
35
- val useMock = if (options.hasKey("useMockService")) {
36
- options.getBoolean("useMockService")
37
- } else false
27
+ val environment = Environment.from(
28
+ if (options.hasKey("environment")) options.getString("environment") else null
29
+ )
30
+
31
+ val mockScreens: List<String>? = if (options.hasKey("mockScreens") && !options.isNull("mockScreens")) {
32
+ val array = options.getArray("mockScreens")
33
+ if (array != null) {
34
+ (0 until array.size()).map { array.getString(it) }
35
+ } else null
36
+ } else null
38
37
 
39
38
  val strategy = if (options.hasKey("overlapStrategy")) {
40
39
  OverlapStrategy.from(options.getString("overlapStrategy"))
@@ -48,8 +47,9 @@ class UXRateModule(reactContext: ReactApplicationContext) : ReactContextBaseJava
48
47
  UXRate.configure(
49
48
  application = application,
50
49
  apiKey = apiKey,
50
+ environment = environment,
51
51
  autoTrackScreens = autoTrack,
52
- useMockService = useMock,
52
+ mockScreens = mockScreens,
53
53
  overlapStrategy = strategy,
54
54
  theme = theme
55
55
  )
@@ -69,7 +69,6 @@ class UXRateModule(reactContext: ReactApplicationContext) : ReactContextBaseJava
69
69
  val key = iterator.nextKey()
70
70
  props[key] = properties.getString(key) ?: ""
71
71
  }
72
-
73
72
  UiThreadUtil.runOnUiThread {
74
73
  UXRate.identify(userId, props)
75
74
  promise.resolve(null)
@@ -24,16 +24,18 @@ All methods return `Promise<void>`.
24
24
  ```ts
25
25
  interface ConfigureOptions {
26
26
  apiKey: string;
27
- autoTrackScreens?: boolean; // default: false
28
- useMockService?: boolean; // default: false
27
+ environment?: 'production' | 'development' | 'local' | 'mock';
28
+ autoTrackScreens?: boolean;
29
+ mockScreens?: string[];
29
30
  }
30
31
  ```
31
32
 
32
33
  | Parameter | Type | Required | Description |
33
34
  |-----------|------|----------|-------------|
34
35
  | `apiKey` | `string` | Yes | Your UXRate API key. |
36
+ | `environment` | `string` | No | Backend environment: `'production'` (default), `'development'`, `'local'`, or `'mock'`. |
35
37
  | `autoTrackScreens` | `boolean` | No | Enable native auto screen tracking. In React Native apps manual `setScreen` calls are preferred. |
36
- | `useMockService` | `boolean` | No | Use the built-in mock backend for local testing. |
38
+ | `mockScreens` | `string[]` | No | Screen names for mock survey targeting. Only used when environment is `'mock'`. |
37
39
 
38
40
  ---
39
41
 
@@ -1,24 +1,19 @@
1
- # Event Tracking
1
+ # Event Tracking — React Native
2
2
 
3
- ## Custom events
3
+ > For concepts and best practices, see [Event Tracking](Event-Tracking).
4
4
 
5
- Use `UXRate.track` to record events that can trigger surveys:
5
+ ## Custom Events
6
6
 
7
7
  ```tsx
8
8
  UXRate.track({ event: 'purchase_complete' });
9
9
  UXRate.track({ event: 'onboarding_finished' });
10
10
  ```
11
11
 
12
- Event names are arbitrary strings. Define matching trigger rules in the UXRate
13
- dashboard to show a survey when a specific event fires.
12
+ ## Screen Tracking
14
13
 
15
- ## Screen tracking
14
+ React Native runs inside a single native view, so auto-track sees only one screen. Report screens manually.
16
15
 
17
- React Native apps run inside a single native ViewController (iOS) or Activity
18
- (Android), so the native auto-track feature sees only one screen. You should
19
- report screens manually using `setScreen`.
20
-
21
- ### Per-screen tracking with `useFocusEffect`
16
+ ### Per-screen with `useFocusEffect`
22
17
 
23
18
  ```tsx
24
19
  import { useFocusEffect } from '@react-navigation/native';
@@ -33,13 +28,9 @@ function SettingsScreen() {
33
28
  }
34
29
  ```
35
30
 
36
- ### Global tracking with React Navigation
37
-
38
- You can report every navigation change from a single place:
31
+ ### Global with React Navigation
39
32
 
40
33
  ```tsx
41
- import { NavigationContainer } from '@react-navigation/native';
42
-
43
34
  <NavigationContainer
44
35
  onStateChange={(state) => {
45
36
  const route = state?.routes[state.index];
@@ -49,12 +40,3 @@ import { NavigationContainer } from '@react-navigation/native';
49
40
  {/* screens */}
50
41
  </NavigationContainer>
51
42
  ```
52
-
53
- See the [React Navigation integration tutorial](../tutorials/react-navigation-integration.md) for a full walkthrough.
54
-
55
- ## Best practices
56
-
57
- - Keep event names short and consistent (e.g. `snake_case`).
58
- - Report screens as early as possible so survey targeting is accurate.
59
- - Avoid tracking high-frequency events (e.g. scroll positions) -- they add
60
- noise without improving targeting.
@@ -6,11 +6,19 @@ Get UXRate running in your React Native app in four steps.
6
6
 
7
7
  Call `configure` once at app startup, typically in your root `App.tsx`:
8
8
 
9
+ **Quick test with mock surveys (no backend needed):**
10
+
11
+ ```tsx
12
+ UXRate.configure({ apiKey: 'YOUR_API_KEY', environment: 'mock' });
13
+ ```
14
+
15
+ **Production:**
16
+
9
17
  ```tsx
10
18
  import { UXRate } from 'react-native-uxrate';
11
19
 
12
20
  useEffect(() => {
13
- UXRate.configure({ apiKey: 'YOUR_API_KEY' });
21
+ UXRate.configure({ apiKey: 'uxr_your_api_key' });
14
22
  }, []);
15
23
  ```
16
24
 
@@ -1,33 +1,19 @@
1
- # Session Replay Configuration
1
+ # Session Replay — React Native
2
2
 
3
- ## Overview
3
+ > For concepts, quality presets, and capture modes, see [Session Replay](Session-Replay).
4
4
 
5
- Session replay is handled entirely by the native UXRate SDKs (iOS and Android).
6
- The React Native module does not expose separate replay APIs -- replay capture
7
- is started automatically by the native SDK when it is enabled for your project.
5
+ Replay is handled entirely by the native UXRate SDKs (iOS and Android). The React Native module does not expose separate replay APIs.
8
6
 
9
- ## Enabling replay
7
+ ## Enabling Replay
10
8
 
11
9
  1. Open the UXRate dashboard.
12
10
  2. Navigate to your project settings.
13
11
  3. Toggle **Session Replay** on.
14
- 4. Configure the desired sampling rate and privacy masking options.
12
+ 4. Configure sampling rate and privacy masking.
15
13
 
16
- Once enabled on the dashboard the native SDKs begin capturing replay data
17
- without any additional code changes in your React Native app.
18
-
19
- ## Privacy masking
20
-
21
- Sensitive views can be masked from replays. Masking rules are configured in
22
- the UXRate dashboard and applied at the native layer. Because React Native
23
- renders through native view hierarchies, the standard masking rules apply
24
- to RN-rendered content as well.
14
+ No additional code changes are needed in your React Native app.
25
15
 
26
16
  ## Troubleshooting
27
17
 
28
- - **Replay not appearing**: Make sure the native SDK versions match the
29
- minimum required for replay support (check the native SDK changelogs).
30
- - **Missing frames**: Replay capture runs at a reduced frame rate to minimise
31
- performance impact. Short interactions may not produce visible frames.
32
- - **Large payload warnings**: If your app has complex view hierarchies,
33
- consider increasing the masking scope to reduce payload size.
18
+ - **Replay not appearing**: Check native SDK versions match minimum required for replay support.
19
+ - **Missing frames**: Replay runs at a reduced frame rate — short interactions may not produce visible frames.
package/example/App.tsx CHANGED
@@ -13,14 +13,11 @@ const Stack = createNativeStackNavigator();
13
13
  // ------------------------------------------------------------------
14
14
  function App(): React.JSX.Element {
15
15
  useEffect(() => {
16
+ // Mock environment — works immediately without dashboard setup.
17
+ // Switch to 'production' with your real API key for live surveys.
16
18
  UXRate.configure({
17
19
  apiKey: 'YOUR_API_KEY',
18
- useMockService: true, // set false in production
19
- });
20
-
21
- UXRate.identify({
22
- userId: 'demo-user-1',
23
- properties: { plan: 'trial' },
20
+ environment: 'mock',
24
21
  });
25
22
  }, []);
26
23
 
package/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export interface ConfigureOptions {
2
2
  apiKey: string;
3
+ environment?: 'production' | 'development' | 'local' | 'mock';
3
4
  autoTrackScreens?: boolean;
4
- useMockService?: boolean;
5
+ mockScreens?: string[];
5
6
  }
6
7
 
7
8
  export interface IdentifyOptions {
package/index.js CHANGED
@@ -6,7 +6,6 @@ const LINKING_ERROR =
6
6
  ? `run \`pod install\` in your iOS project directory.\n`
7
7
  : `rebuild your Android project.\n`);
8
8
 
9
- // Throw a helpful error if the native module is not linked
10
9
  const NativeUXRate = NativeModules.UXRate
11
10
  ? NativeModules.UXRate
12
11
  : new Proxy(
@@ -18,73 +17,31 @@ const NativeUXRate = NativeModules.UXRate
18
17
  }
19
18
  );
20
19
 
21
- /**
22
- * React Native bridge for the UXRate SDK (iOS & Android).
23
- *
24
- * @example
25
- * // Minimal setup (App.js / App.tsx)
26
- * import { UXRate } from 'react-native-uxrate';
27
- *
28
- * useEffect(() => {
29
- * UXRate.configure({ apiKey: 'uxr_xxx' });
30
- * }, []);
31
- *
32
- * @example
33
- * // Manual screen tracking
34
- * useFocusEffect(() => {
35
- * UXRate.setScreen('Home');
36
- * });
37
- */
38
20
  export const UXRate = {
39
21
  /**
40
22
  * Initialise the UXRate SDK. Call once at app startup.
41
23
  *
42
24
  * @param {string} apiKey - Your UXRate API key (required).
43
- * @param {boolean} [autoTrackScreens=false] - Auto-detect screens via
44
- * UIViewController swizzle (iOS) or ActivityLifecycleCallbacks (Android).
45
- * In React Native, manual setScreen() calls are preferred.
46
- * @param {boolean} [useMockService=false] - Use the built-in mock backend.
25
+ * @param {string} [environment='production'] - Backend environment:
26
+ * 'production', 'development', 'local', or 'mock'.
27
+ * @param {boolean} [autoTrackScreens=false] - Auto-detect screens.
28
+ * @param {string[]} [mockScreens] - Screen names for mock survey targeting.
47
29
  */
48
- configure({ apiKey, autoTrackScreens = false, useMockService = false }) {
30
+ configure({ apiKey, environment = 'production', autoTrackScreens = false, mockScreens }) {
49
31
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') return Promise.resolve();
50
- return NativeUXRate.configure(apiKey, { autoTrackScreens, useMockService });
32
+ return NativeUXRate.configure(apiKey, { environment, autoTrackScreens, mockScreens });
51
33
  },
52
34
 
53
- /**
54
- * Identify the current user for segment-based survey targeting.
55
- *
56
- * @param {string} userId - A stable user identifier.
57
- * @param {Object} [properties={}] - Optional key/value properties.
58
- */
59
35
  identify({ userId, properties = {} }) {
60
36
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') return Promise.resolve();
61
37
  return NativeUXRate.identify(userId, properties);
62
38
  },
63
39
 
64
- /**
65
- * Track a custom event. Used for event-based trigger rules.
66
- *
67
- * @param {string} event - The event name.
68
- */
69
40
  track({ event }) {
70
41
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') return Promise.resolve();
71
42
  return NativeUXRate.track(event);
72
43
  },
73
44
 
74
- /**
75
- * Report the current screen name. Call this on every navigation event.
76
- *
77
- * @param {string} name - The screen name to report.
78
- *
79
- * @example
80
- * // With React Navigation
81
- * <NavigationContainer
82
- * onStateChange={(state) => {
83
- * const route = state?.routes[state.index];
84
- * if (route) UXRate.setScreen(route.name);
85
- * }}
86
- * >
87
- */
88
45
  setScreen(name) {
89
46
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') return Promise.resolve();
90
47
  return NativeUXRate.setScreen(name);
@@ -1,32 +1,67 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
 
3
- // Registers UXRateModule.swift with React Native's Objective-C bridge.
4
- // Each RCT_EXTERN_METHOD must match an @objc method in UXRateModule.swift.
5
-
6
- RCT_EXTERN_MODULE(UXRate, NSObject)
7
-
8
- RCT_EXTERN_METHOD(
9
- configure:(NSString *)apiKey
10
- options:(NSDictionary *)options
11
- resolve:(RCTPromiseResolveBlock)resolve
12
- reject:(RCTPromiseRejectBlock)reject
13
- )
14
-
15
- RCT_EXTERN_METHOD(
16
- identify:(NSString *)userId
17
- properties:(NSDictionary *)properties
18
- resolve:(RCTPromiseResolveBlock)resolve
19
- reject:(RCTPromiseRejectBlock)reject
20
- )
21
-
22
- RCT_EXTERN_METHOD(
23
- track:(NSString *)event
24
- resolve:(RCTPromiseResolveBlock)resolve
25
- reject:(RCTPromiseRejectBlock)reject
26
- )
27
-
28
- RCT_EXTERN_METHOD(
29
- setScreen:(NSString *)name
30
- resolve:(RCTPromiseResolveBlock)resolve
31
- reject:(RCTPromiseRejectBlock)reject
32
- )
3
+ #if __has_include(<react_native_uxrate/react_native_uxrate-Swift.h>)
4
+ #import <react_native_uxrate/react_native_uxrate-Swift.h>
5
+ #else
6
+ #import "react_native_uxrate-Swift.h"
7
+ #endif
8
+
9
+ @interface UXRate : NSObject <RCTBridgeModule>
10
+ @end
11
+
12
+ @implementation UXRate
13
+
14
+ RCT_EXPORT_MODULE()
15
+
16
+ RCT_EXPORT_METHOD(configure:(NSString *)apiKey
17
+ options:(NSDictionary *)options
18
+ resolve:(RCTPromiseResolveBlock)resolve
19
+ reject:(RCTPromiseRejectBlock)reject)
20
+ {
21
+ BOOL autoTrack = [options[@"autoTrackScreens"] boolValue];
22
+ NSString *environment = options[@"environment"];
23
+ NSArray<NSString *> *mockScreens = options[@"mockScreens"];
24
+
25
+ [UXRateBridge configure:apiKey
26
+ environment:environment
27
+ autoTrackScreens:autoTrack
28
+ mockScreens:mockScreens];
29
+ resolve(nil);
30
+ }
31
+
32
+ RCT_EXPORT_METHOD(identify:(NSString *)userId
33
+ properties:(NSDictionary *)properties
34
+ resolve:(RCTPromiseResolveBlock)resolve
35
+ reject:(RCTPromiseRejectBlock)reject)
36
+ {
37
+ NSMutableDictionary<NSString *, NSString *> *props = [NSMutableDictionary new];
38
+ [properties enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
39
+ if ([key isKindOfClass:[NSString class]] && [obj isKindOfClass:[NSString class]]) {
40
+ props[key] = obj;
41
+ }
42
+ }];
43
+ [UXRateBridge identify:userId properties:props];
44
+ resolve(nil);
45
+ }
46
+
47
+ RCT_EXPORT_METHOD(track:(NSString *)event
48
+ resolve:(RCTPromiseResolveBlock)resolve
49
+ reject:(RCTPromiseRejectBlock)reject)
50
+ {
51
+ [UXRateBridge track:event];
52
+ resolve(nil);
53
+ }
54
+
55
+ RCT_EXPORT_METHOD(setScreen:(NSString *)name
56
+ resolve:(RCTPromiseResolveBlock)resolve
57
+ reject:(RCTPromiseRejectBlock)reject)
58
+ {
59
+ [UXRateBridge setScreen:name];
60
+ resolve(nil);
61
+ }
62
+
63
+ + (BOOL)requiresMainQueueSetup {
64
+ return NO;
65
+ }
66
+
67
+ @end
@@ -1,91 +1,55 @@
1
1
  import Foundation
2
2
  import UXRateSDK
3
3
 
4
- /// React Native bridge module that exposes the UXRate iOS SDK to JavaScript.
5
- ///
6
- /// Registered as `UXRate` via `RCT_EXTERN_MODULE` in `UXRateModule.m`.
7
- /// All methods dispatch to `MainActor` since `UXRate` is `@MainActor`-isolated.
8
- @objc(UXRate)
9
- class UXRateModule: NSObject {
4
+ /// Implementation class for the React Native bridge.
5
+ /// Called from the Objective-C bridge in UXRateModule.m.
6
+ @objc(UXRateBridge)
7
+ public class UXRateBridge: NSObject {
10
8
 
11
- /// Initialise the UXRate SDK.
12
- ///
13
- /// - Parameters:
14
- /// - apiKey: Your UXRate API key.
15
- /// - options: Dictionary with optional keys:
16
- /// - `autoTrackScreens` (Bool, default false)
17
- /// - `useMockService` (Bool, default false)
18
9
  @objc
19
- func configure(
10
+ public static func configure(
20
11
  _ apiKey: String,
21
- options: NSDictionary,
22
- resolve: @escaping RCTPromiseResolveBlock,
23
- reject: @escaping RCTPromiseRejectBlock
12
+ environment: String?,
13
+ autoTrackScreens: Bool,
14
+ mockScreens: [String]?
24
15
  ) {
25
- let autoTrack = options["autoTrackScreens"] as? Bool ?? false
26
- let useMock = options["useMockService"] as? Bool ?? false
27
- let strategy = OverlapStrategy.from(string: options["overlapStrategy"] as? String)
28
- let theme = SDKTheme.from(string: options["theme"] as? String)
16
+ let env: UXRateEnvironment = {
17
+ switch environment {
18
+ case "development": return .development
19
+ case "local": return .local
20
+ case "mock": return .mock
21
+ default: return .production
22
+ }
23
+ }()
29
24
 
30
25
  DispatchQueue.main.async {
31
26
  UXRate.configure(
32
27
  apiKey: apiKey,
33
- autoTrackScreens: autoTrack,
34
- useMockService: useMock,
35
- overlapStrategy: strategy,
36
- theme: theme
28
+ environment: env,
29
+ autoTrackScreens: autoTrackScreens,
30
+ mockScreens: mockScreens
37
31
  )
38
- resolve(nil)
39
32
  }
40
33
  }
41
34
 
42
- /// Identify the current user.
43
- ///
44
- /// - Parameters:
45
- /// - userId: Stable user identifier.
46
- /// - properties: Optional `[String: String]` attributes.
47
35
  @objc
48
- func identify(
49
- _ userId: String,
50
- properties: NSDictionary,
51
- resolve: @escaping RCTPromiseResolveBlock,
52
- reject: @escaping RCTPromiseRejectBlock
53
- ) {
54
- let props = properties as? [String: String] ?? [:]
36
+ public static func identify(_ userId: String, properties: [String: String]) {
55
37
  DispatchQueue.main.async {
56
- UXRate.identify(userId: userId, properties: props)
57
- resolve(nil)
38
+ UXRate.identify(userId: userId, properties: properties)
58
39
  }
59
40
  }
60
41
 
61
- /// Track a custom event.
62
42
  @objc
63
- func track(
64
- _ event: String,
65
- resolve: @escaping RCTPromiseResolveBlock,
66
- reject: @escaping RCTPromiseRejectBlock
67
- ) {
43
+ public static func track(_ event: String) {
68
44
  DispatchQueue.main.async {
69
45
  UXRate.track(event: event)
70
- resolve(nil)
71
46
  }
72
47
  }
73
48
 
74
- /// Report the current screen name.
75
49
  @objc
76
- func setScreen(
77
- _ name: String,
78
- resolve: @escaping RCTPromiseResolveBlock,
79
- reject: @escaping RCTPromiseRejectBlock
80
- ) {
50
+ public static func setScreen(_ name: String) {
81
51
  DispatchQueue.main.async {
82
52
  UXRate.setScreen(name)
83
- resolve(nil)
84
53
  }
85
54
  }
86
-
87
- /// React Native requires this to declare that the module does not have
88
- /// a main queue setup requirement — methods are dispatched manually.
89
- @objc
90
- static func requiresMainQueueSetup() -> Bool { false }
91
55
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-uxrate",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "React Native module for the UXRate SDK — embed AI-powered surveys in your React Native app. Supports iOS and Android.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -14,5 +14,5 @@ Pod::Spec.new do |s|
14
14
  s.source_files = 'ios/**/*.{swift,m,h}'
15
15
 
16
16
  s.dependency 'React-Core'
17
- s.dependency 'UXRateSDK', '~> 0.2.0'
17
+ s.dependency 'UXRateSDK', '~> 0.3.0'
18
18
  end