riuve-rn 1.0.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 +848 -0
- package/dist/Riuve.d.ts +91 -0
- package/dist/Riuve.d.ts.map +1 -0
- package/dist/Riuve.js +402 -0
- package/dist/Rive.d.ts +91 -0
- package/dist/Rive.d.ts.map +1 -0
- package/dist/Rive.js +402 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts +13 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/ExpoDeviceInfo.js +91 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts +13 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/FallbackDeviceInfo.js +36 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts +17 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/NativeDeviceInfo.js +83 -0
- package/dist/adapters/deviceInfo/index.d.ts +14 -0
- package/dist/adapters/deviceInfo/index.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/index.js +38 -0
- package/dist/adapters/deviceInfo/types.d.ts +25 -0
- package/dist/adapters/deviceInfo/types.d.ts.map +1 -0
- package/dist/adapters/deviceInfo/types.js +7 -0
- package/dist/adapters/network/ExpoNetworkManager.d.ts +20 -0
- package/dist/adapters/network/ExpoNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/ExpoNetworkManager.js +114 -0
- package/dist/adapters/network/FallbackNetworkManager.d.ts +15 -0
- package/dist/adapters/network/FallbackNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/FallbackNetworkManager.js +27 -0
- package/dist/adapters/network/NativeNetworkManager.d.ts +20 -0
- package/dist/adapters/network/NativeNetworkManager.d.ts.map +1 -0
- package/dist/adapters/network/NativeNetworkManager.js +68 -0
- package/dist/adapters/network/index.d.ts +14 -0
- package/dist/adapters/network/index.d.ts.map +1 -0
- package/dist/adapters/network/index.js +38 -0
- package/dist/adapters/network/types.d.ts +28 -0
- package/dist/adapters/network/types.d.ts.map +1 -0
- package/dist/adapters/network/types.js +7 -0
- package/dist/adapters/utils/moduleDetector.d.ts +17 -0
- package/dist/adapters/utils/moduleDetector.d.ts.map +1 -0
- package/dist/adapters/utils/moduleDetector.js +32 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +43 -0
- package/dist/core/ApiClient.d.ts +49 -0
- package/dist/core/ApiClient.d.ts.map +1 -0
- package/dist/core/ApiClient.js +184 -0
- package/dist/core/DeviceInfo.d.ts +27 -0
- package/dist/core/DeviceInfo.d.ts.map +1 -0
- package/dist/core/DeviceInfo.js +69 -0
- package/dist/core/EventQueue.d.ts +71 -0
- package/dist/core/EventQueue.d.ts.map +1 -0
- package/dist/core/EventQueue.js +216 -0
- package/dist/core/Storage.d.ts +29 -0
- package/dist/core/Storage.d.ts.map +1 -0
- package/dist/core/Storage.js +88 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/managers/BatchManager.d.ts +50 -0
- package/dist/managers/BatchManager.d.ts.map +1 -0
- package/dist/managers/BatchManager.js +277 -0
- package/dist/managers/IdentityManager.d.ts +47 -0
- package/dist/managers/IdentityManager.d.ts.map +1 -0
- package/dist/managers/IdentityManager.js +135 -0
- package/dist/managers/NetworkManager.d.ts +32 -0
- package/dist/managers/NetworkManager.d.ts.map +1 -0
- package/dist/managers/NetworkManager.js +67 -0
- package/dist/types/api.d.ts +65 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +15 -0
- package/dist/types/config.d.ts +32 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/events.d.ts +63 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +5 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/storage.d.ts +26 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +5 -0
- package/dist/utils/fetchWithTimeout.d.ts +6 -0
- package/dist/utils/fetchWithTimeout.d.ts.map +1 -0
- package/dist/utils/fetchWithTimeout.js +28 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +39 -0
- package/dist/utils/retry.d.ts +29 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +78 -0
- package/dist/utils/uuid.d.ts +12 -0
- package/dist/utils/uuid.d.ts.map +1 -0
- package/dist/utils/uuid.js +27 -0
- package/dist/utils/validators.d.ts +32 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +68 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
# Riuve SDK - React Native/Expo
|
|
2
|
+
|
|
3
|
+
> **Behavioral event tracking SDK for React Native and Expo applications**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [What is Riuve SDK?](#what-is-riuve-sdk)
|
|
10
|
+
2. [Installation](#installation)
|
|
11
|
+
3. [Quick Start](#quick-start)
|
|
12
|
+
4. [Advanced Features](#advanced-features)
|
|
13
|
+
5. [Best Practices](#best-practices)
|
|
14
|
+
6. [Troubleshooting](#troubleshooting)
|
|
15
|
+
7. [API Reference](#api-reference)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What is Riuve SDK?
|
|
20
|
+
|
|
21
|
+
**Riuve SDK** is a behavioral event tracking library for React Native and Expo applications.
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- ✅ **Offline Support**: Events are queued when offline and automatically sent when connection is restored
|
|
26
|
+
- ✅ **Intelligent Batching**: Events are automatically batched for optimal performance
|
|
27
|
+
- ✅ **Automatic Retry**: Failed requests are automatically retried with exponential backoff
|
|
28
|
+
- ✅ **Background Flush**: Events are automatically flushed when app goes to background
|
|
29
|
+
- ✅ **User Identification**: Manages both anonymous and external user IDs
|
|
30
|
+
- ✅ **Push Notification Support**: FCM token management
|
|
31
|
+
- ✅ **Zero Configuration**: Backend URL is hardcoded, only API key is required
|
|
32
|
+
- ✅ **Pending Events Queue**: Events tracked before SDK initialization are automatically processed
|
|
33
|
+
|
|
34
|
+
### Use Cases
|
|
35
|
+
|
|
36
|
+
- Track user behavior and interactions in your app
|
|
37
|
+
- Monitor which screens are viewed most
|
|
38
|
+
- Track button clicks, form submissions, and user actions
|
|
39
|
+
- Segment users based on their behavior
|
|
40
|
+
- Send targeted push notifications
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
### 1. Install the Package
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install riuve-rn
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
or
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
yarn add riuve-rn
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Install Required Dependencies
|
|
59
|
+
|
|
60
|
+
**AsyncStorage** is required for the SDK to function:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install @react-native-async-storage/async-storage
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. (Optional) Expo Modules
|
|
67
|
+
|
|
68
|
+
If you're using Expo, install these for device info and network monitoring:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx expo install expo-device expo-application expo-localization expo-network
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 4. (Optional) Native Modules
|
|
75
|
+
|
|
76
|
+
For better performance with native modules (Development Build or Bare React Native):
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install react-native-device-info @react-native-community/netinfo
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
### Step 1: Initialize the SDK
|
|
87
|
+
|
|
88
|
+
Initialize the SDK at the start of your app (typically in `App.tsx` or `_layout.tsx`):
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { useEffect } from 'react';
|
|
92
|
+
import Riuve from 'riuve-rn';
|
|
93
|
+
|
|
94
|
+
export default function App() {
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
initializeSDK();
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
const initializeSDK = async () => {
|
|
100
|
+
try {
|
|
101
|
+
// Get your API key from Nock dashboard
|
|
102
|
+
await Riuve.initialize('riuve_base_xxxxxxxxxxxxxxxxxxxxx', {
|
|
103
|
+
// Basic configuration
|
|
104
|
+
batchSize: 10, // Number of events per batch (default: 10)
|
|
105
|
+
batchTimeout: 30000, // Auto-send after 30 seconds (default: 30000ms)
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log('✅ SDK initialized successfully');
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error('❌ SDK initialization error:', error);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
// Your app content
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Important Notes:**
|
|
121
|
+
- The `baseUrl` is hardcoded in the SDK (`https://api.riuve.com`), no need to pass it
|
|
122
|
+
- Get your API key from the [Nock Dashboard](https://dashboard.riuve.com)
|
|
123
|
+
|
|
124
|
+
### Step 2: Identify Users
|
|
125
|
+
|
|
126
|
+
When a user logs in or user information is available:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import Riuve from 'riuve-rn';
|
|
130
|
+
|
|
131
|
+
// When user logs in
|
|
132
|
+
const handleLogin = async (userId: string, userEmail: string) => {
|
|
133
|
+
try {
|
|
134
|
+
await Riuve.identify(userId, {
|
|
135
|
+
email: userEmail,
|
|
136
|
+
name: 'User Name',
|
|
137
|
+
user_type: 'premium',
|
|
138
|
+
// Add any custom properties you want
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.log('✅ User identified');
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('❌ Identify error:', error);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**When to Identify:**
|
|
149
|
+
- When user logs in
|
|
150
|
+
- When user information is updated
|
|
151
|
+
- On app start (if user is already logged in)
|
|
152
|
+
|
|
153
|
+
### Step 3: Track Events
|
|
154
|
+
|
|
155
|
+
Track important actions in your app:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import Riuve from 'riuve-rn';
|
|
159
|
+
import { useFocusEffect } from '@react-navigation/native';
|
|
160
|
+
import { useCallback } from 'react';
|
|
161
|
+
|
|
162
|
+
// Screen view tracking (use useFocusEffect for tabs)
|
|
163
|
+
useFocusEffect(
|
|
164
|
+
useCallback(() => {
|
|
165
|
+
Riuve.track('screen_viewed', {
|
|
166
|
+
screen_name: 'Home',
|
|
167
|
+
screen_category: 'main',
|
|
168
|
+
}).catch(console.error);
|
|
169
|
+
}, [])
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// Button click
|
|
173
|
+
const handleButtonClick = async () => {
|
|
174
|
+
try {
|
|
175
|
+
await Riuve.track('button_clicked', {
|
|
176
|
+
button_id: 'subscribe_button',
|
|
177
|
+
button_text: 'Subscribe',
|
|
178
|
+
screen: 'Home',
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Button action
|
|
182
|
+
// ...
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error('Track error:', error);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Form submission
|
|
189
|
+
const handleFormSubmit = async (formData: any) => {
|
|
190
|
+
try {
|
|
191
|
+
await Riuve.track('form_submitted', {
|
|
192
|
+
form_name: 'contact_form',
|
|
193
|
+
form_fields: Object.keys(formData).length,
|
|
194
|
+
success: true,
|
|
195
|
+
});
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error('Track error:', error);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Event Naming Best Practices:**
|
|
203
|
+
- Use `snake_case`: `screen_viewed`, `button_clicked`
|
|
204
|
+
- Use descriptive names: `user_subscribed` ✅, `event1` ❌
|
|
205
|
+
- Be consistent: `screen_viewed` for all screens, `button_clicked` for all buttons
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Advanced Features
|
|
210
|
+
|
|
211
|
+
### 1. Custom Event Properties
|
|
212
|
+
|
|
213
|
+
Add detailed information to events:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
await Riuve.track('purchase_completed', {
|
|
217
|
+
product_id: 'prod_123',
|
|
218
|
+
product_name: 'Premium Subscription',
|
|
219
|
+
price: 99.99,
|
|
220
|
+
currency: 'USD',
|
|
221
|
+
payment_method: 'credit_card',
|
|
222
|
+
discount_code: 'SUMMER2024',
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 2. Manual Flush
|
|
227
|
+
|
|
228
|
+
Send events immediately when needed:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
await Riuve.flush();
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**When to Use:**
|
|
235
|
+
- Before user exits the app for important events
|
|
236
|
+
- After critical actions (e.g., payment completed)
|
|
237
|
+
|
|
238
|
+
### 3. Reset User
|
|
239
|
+
|
|
240
|
+
When user logs out:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
await Riuve.reset();
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
This will:
|
|
247
|
+
- Clear external user ID
|
|
248
|
+
- Clear user properties
|
|
249
|
+
- Generate a new anonymous ID
|
|
250
|
+
- Clear event queue
|
|
251
|
+
|
|
252
|
+
### 4. FCM Token Management
|
|
253
|
+
|
|
254
|
+
Register FCM token for push notifications:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import * as Notifications from 'expo-notifications';
|
|
258
|
+
|
|
259
|
+
// Get FCM token
|
|
260
|
+
const token = await Notifications.getExpoPushTokenAsync();
|
|
261
|
+
|
|
262
|
+
// Register with SDK
|
|
263
|
+
await Riuve.setFcmToken(token.data);
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Best Practices
|
|
269
|
+
|
|
270
|
+
### 1. Initialize Early
|
|
271
|
+
|
|
272
|
+
Initialize the SDK **as early as possible**:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// ✅ GOOD: At app start
|
|
276
|
+
export default function App() {
|
|
277
|
+
useEffect(() => {
|
|
278
|
+
Riuve.initialize('api_key');
|
|
279
|
+
}, []);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ❌ BAD: After user action
|
|
283
|
+
const handleButtonClick = () => {
|
|
284
|
+
Riuve.initialize('api_key'); // Too late!
|
|
285
|
+
};
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 2. Error Handling
|
|
289
|
+
|
|
290
|
+
Always use try-catch:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// ✅ GOOD
|
|
294
|
+
try {
|
|
295
|
+
await Riuve.track('event_name', {});
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error('Track failed:', error);
|
|
298
|
+
// Don't break app flow, just log it
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ❌ BAD
|
|
302
|
+
await Riuve.track('event_name', {}); // App may crash on error
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 3. Async/Await vs Promise
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// ✅ GOOD: Async/await (more readable)
|
|
309
|
+
const handleAction = async () => {
|
|
310
|
+
try {
|
|
311
|
+
await Riuve.track('action_completed');
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error(error);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// ✅ GOOD: Promise catch (for quick actions)
|
|
318
|
+
Riuve.track('quick_action').catch(console.error);
|
|
319
|
+
|
|
320
|
+
// ❌ BAD: Unhandled promise
|
|
321
|
+
Riuve.track('action'); // Fails silently on error
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### 4. Event Naming Convention
|
|
325
|
+
|
|
326
|
+
Use a consistent naming convention:
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// ✅ GOOD: Consistent and descriptive
|
|
330
|
+
Riuve.track('screen_viewed', { screen_name: 'Home' });
|
|
331
|
+
Riuve.track('screen_viewed', { screen_name: 'Profile' });
|
|
332
|
+
Riuve.track('button_clicked', { button_id: 'subscribe' });
|
|
333
|
+
Riuve.track('button_clicked', { button_id: 'cancel' });
|
|
334
|
+
|
|
335
|
+
// ❌ BAD: Inconsistent
|
|
336
|
+
Riuve.track('home_viewed');
|
|
337
|
+
Riuve.track('profile_screen');
|
|
338
|
+
Riuve.track('click_subscribe');
|
|
339
|
+
Riuve.track('cancelButton');
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 5. Tab Navigation Events
|
|
343
|
+
|
|
344
|
+
Use `useFocusEffect` for tab screens to avoid tracking events for unmounted tabs:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import { useFocusEffect } from '@react-navigation/native';
|
|
348
|
+
|
|
349
|
+
// ✅ GOOD: Only tracks when tab is actually focused
|
|
350
|
+
useFocusEffect(
|
|
351
|
+
useCallback(() => {
|
|
352
|
+
Riuve.track('screen_viewed', {
|
|
353
|
+
screen_name: 'Home',
|
|
354
|
+
}).catch(console.error);
|
|
355
|
+
}, [])
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
// ❌ BAD: Tracks even if tab is not visible
|
|
359
|
+
useEffect(() => {
|
|
360
|
+
Riuve.track('screen_viewed', {
|
|
361
|
+
screen_name: 'Home',
|
|
362
|
+
}).catch(console.error);
|
|
363
|
+
}, []);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 6. Critical Events
|
|
367
|
+
|
|
368
|
+
Use flush for critical events:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// Payment completed - send immediately
|
|
372
|
+
await Riuve.track('purchase_completed', {
|
|
373
|
+
order_id: 'order_123',
|
|
374
|
+
amount: 99.99,
|
|
375
|
+
});
|
|
376
|
+
await Riuve.flush(); // Send immediately
|
|
377
|
+
|
|
378
|
+
// Screen view - send in batch (normal)
|
|
379
|
+
Riuve.track('screen_viewed', { screen_name: 'Home' });
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Configuration Options
|
|
385
|
+
|
|
386
|
+
### All Configuration Parameters
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
await Riuve.initialize('api_key', {
|
|
390
|
+
// Debugging
|
|
391
|
+
debugMode: false, // Enable detailed logging (default: false)
|
|
392
|
+
|
|
393
|
+
// Batch Settings
|
|
394
|
+
batchSize: 10, // Number of events per batch (default: 10)
|
|
395
|
+
batchTimeout: 30000, // Auto-send timeout in ms (default: 30000)
|
|
396
|
+
|
|
397
|
+
// Network Settings
|
|
398
|
+
requestTimeout: 10000, // API request timeout in ms (default: 10000)
|
|
399
|
+
|
|
400
|
+
// Retry Settings
|
|
401
|
+
maxRetries: 3, // Maximum retry attempts (default: 3)
|
|
402
|
+
retryDelay: 1000, // Retry delay in ms (default: 1000)
|
|
403
|
+
|
|
404
|
+
// Storage Settings
|
|
405
|
+
persistEvents: true, // Save events to storage (default: true)
|
|
406
|
+
maxQueueSize: 1000, // Maximum queue size (default: 1000)
|
|
407
|
+
eventRetentionDays: 7, // Days to keep failed events (default: 7)
|
|
408
|
+
|
|
409
|
+
// Automatic Operations
|
|
410
|
+
autoFlushOnBackground: true, // Auto-flush on background (default: true)
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Recommended Configurations
|
|
415
|
+
|
|
416
|
+
**Development:**
|
|
417
|
+
```typescript
|
|
418
|
+
{
|
|
419
|
+
debugMode: true, // Enable detailed logging
|
|
420
|
+
batchSize: 5, // Smaller batches (for testing)
|
|
421
|
+
batchTimeout: 10000, // Faster sending (for testing)
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Production:**
|
|
426
|
+
```typescript
|
|
427
|
+
{
|
|
428
|
+
debugMode: false, // Only WARN and ERROR logs (default)
|
|
429
|
+
batchSize: 10, // Standard batch size
|
|
430
|
+
batchTimeout: 30000, // Wait 30 seconds
|
|
431
|
+
autoFlushOnBackground: true, // Send when backgrounded
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**High Volume (Many events):**
|
|
436
|
+
```typescript
|
|
437
|
+
{
|
|
438
|
+
batchSize: 20, // Larger batches
|
|
439
|
+
batchTimeout: 60000, // Wait 1 minute
|
|
440
|
+
maxQueueSize: 5000, // Larger queue
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Troubleshooting
|
|
447
|
+
|
|
448
|
+
### Problem 1: SDK Not Initializing
|
|
449
|
+
|
|
450
|
+
**Symptoms:**
|
|
451
|
+
- `SDK not initialized` error
|
|
452
|
+
- Events are not being tracked
|
|
453
|
+
|
|
454
|
+
**Solution:**
|
|
455
|
+
```typescript
|
|
456
|
+
// Wait for initialization to complete
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
const init = async () => {
|
|
459
|
+
await Riuve.initialize('api_key');
|
|
460
|
+
console.log('SDK initialized');
|
|
461
|
+
};
|
|
462
|
+
init();
|
|
463
|
+
}, []);
|
|
464
|
+
|
|
465
|
+
// Check before tracking
|
|
466
|
+
if (Riuve.isReady()) {
|
|
467
|
+
await Riuve.track('event');
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Note:** Events tracked before initialization are automatically queued and processed after initialization.
|
|
472
|
+
|
|
473
|
+
### Problem 2: Events Not Sending
|
|
474
|
+
|
|
475
|
+
**Checklist:**
|
|
476
|
+
1. ✅ Is SDK initialized?
|
|
477
|
+
2. ✅ Is API key correct?
|
|
478
|
+
3. ✅ Is there internet connection?
|
|
479
|
+
|
|
480
|
+
**Debug:**
|
|
481
|
+
```typescript
|
|
482
|
+
// Enable debug mode to see detailed logs
|
|
483
|
+
await Riuve.initialize('api_key', {
|
|
484
|
+
debugMode: true, // Shows DEBUG, INFO, WARN, and ERROR logs
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// With debugMode: false (default), only WARN and ERROR are visible:
|
|
488
|
+
// [Riuve SDK] [WARN] Network offline, events will be stored
|
|
489
|
+
// [Riuve SDK] [ERROR] Failed to send batch
|
|
490
|
+
|
|
491
|
+
// With debugMode: true, you'll see everything:
|
|
492
|
+
// [Riuve SDK] [DEBUG] Config: {...}
|
|
493
|
+
// [Riuve SDK] [INFO] Making HTTP request: POST /api/sdk/track
|
|
494
|
+
// [Riuve SDK] [INFO] Event tracked: button_clicked
|
|
495
|
+
// [Riuve SDK] [WARN] Retry attempt 1...
|
|
496
|
+
// [Riuve SDK] [ERROR] Failed after 3 retries
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Problem 3: Offline Events Not Sending
|
|
500
|
+
|
|
501
|
+
**Normal Behavior:**
|
|
502
|
+
- Offline events are saved to AsyncStorage
|
|
503
|
+
- Automatically sent when internet connection is restored
|
|
504
|
+
- Sent when app is reopened
|
|
505
|
+
|
|
506
|
+
**Manual Check:**
|
|
507
|
+
```typescript
|
|
508
|
+
// Manually flush
|
|
509
|
+
await Riuve.flush();
|
|
510
|
+
|
|
511
|
+
// Or on app start
|
|
512
|
+
useEffect(() => {
|
|
513
|
+
Riuve.initialize('api_key').then(() => {
|
|
514
|
+
Riuve.flush(); // Send pending events
|
|
515
|
+
});
|
|
516
|
+
}, []);
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Problem 4: Too Many Events Accumulating
|
|
520
|
+
|
|
521
|
+
**Solution:**
|
|
522
|
+
```typescript
|
|
523
|
+
// Increase batch size
|
|
524
|
+
await Riuve.initialize('api_key', {
|
|
525
|
+
batchSize: 20, // Larger batches
|
|
526
|
+
batchTimeout: 15000, // Send more frequently
|
|
527
|
+
});
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Problem 5: TypeScript Errors
|
|
531
|
+
|
|
532
|
+
**Solution:**
|
|
533
|
+
```typescript
|
|
534
|
+
// Use type assertion
|
|
535
|
+
await Riuve.track('event_name', {
|
|
536
|
+
custom_prop: value,
|
|
537
|
+
} as any); // Temporary solution
|
|
538
|
+
|
|
539
|
+
// Or proper typing
|
|
540
|
+
interface MyEventProperties {
|
|
541
|
+
custom_prop: string;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
await Riuve.track('event_name', {
|
|
545
|
+
custom_prop: 'value',
|
|
546
|
+
} as MyEventProperties);
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## API Reference
|
|
552
|
+
|
|
553
|
+
### Riuve.initialize()
|
|
554
|
+
|
|
555
|
+
Initializes the SDK.
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
await Riuve.initialize(apiKey: string, config?: RiuveConfig): Promise<void>
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Parameters:**
|
|
562
|
+
- `apiKey` (string, required): Your API key from Nock dashboard
|
|
563
|
+
- `config` (object, optional): Configuration object
|
|
564
|
+
|
|
565
|
+
**Example:**
|
|
566
|
+
```typescript
|
|
567
|
+
await Riuve.initialize('nock_live_xxx', {
|
|
568
|
+
batchSize: 10,
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Riuve.identify()
|
|
573
|
+
|
|
574
|
+
Identifies a user.
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
await Riuve.identify(externalUserId: string, properties?: object): Promise<void>
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Parameters:**
|
|
581
|
+
- `externalUserId` (string, required): User's unique ID
|
|
582
|
+
- `properties` (object, optional): User properties
|
|
583
|
+
|
|
584
|
+
**Example:**
|
|
585
|
+
```typescript
|
|
586
|
+
await Riuve.identify('user_123', {
|
|
587
|
+
email: 'user@example.com',
|
|
588
|
+
name: 'John Doe',
|
|
589
|
+
});
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**Note:** If user properties are updated, call `identify` again with the new properties.
|
|
593
|
+
|
|
594
|
+
### Riuve.track()
|
|
595
|
+
|
|
596
|
+
Tracks an event.
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
await Riuve.track(eventName: string, properties?: object): Promise<void>
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Parameters:**
|
|
603
|
+
- `eventName` (string, required): Event name
|
|
604
|
+
- `properties` (object, optional): Event properties
|
|
605
|
+
|
|
606
|
+
**Example:**
|
|
607
|
+
```typescript
|
|
608
|
+
await Riuve.track('button_clicked', {
|
|
609
|
+
button_id: 'subscribe',
|
|
610
|
+
screen: 'Home',
|
|
611
|
+
});
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Note:** Can be called before SDK initialization. Events will be queued and processed after initialization.
|
|
615
|
+
|
|
616
|
+
### Riuve.flush()
|
|
617
|
+
|
|
618
|
+
Immediately sends all pending events.
|
|
619
|
+
|
|
620
|
+
```typescript
|
|
621
|
+
await Riuve.flush(): Promise<void>
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
**Example:**
|
|
625
|
+
```typescript
|
|
626
|
+
await Riuve.track('purchase_completed');
|
|
627
|
+
await Riuve.flush(); // Send immediately
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### Riuve.reset()
|
|
631
|
+
|
|
632
|
+
Clears user information and queue.
|
|
633
|
+
|
|
634
|
+
```typescript
|
|
635
|
+
await Riuve.reset(): Promise<void>
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Example:**
|
|
639
|
+
```typescript
|
|
640
|
+
// When user logs out
|
|
641
|
+
await Riuve.reset();
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Riuve.setFcmToken()
|
|
645
|
+
|
|
646
|
+
Registers FCM token (for push notifications).
|
|
647
|
+
|
|
648
|
+
```typescript
|
|
649
|
+
await Riuve.setFcmToken(token: string): Promise<void>
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Example:**
|
|
653
|
+
```typescript
|
|
654
|
+
const token = await Notifications.getExpoPushTokenAsync();
|
|
655
|
+
await Riuve.setFcmToken(token.data);
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### Riuve.isReady()
|
|
659
|
+
|
|
660
|
+
Checks if SDK is initialized.
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
const isReady: boolean = Riuve.isReady();
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
**Example:**
|
|
667
|
+
```typescript
|
|
668
|
+
if (Riuve.isReady()) {
|
|
669
|
+
await Riuve.track('event');
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### Riuve.getQueueSize()
|
|
674
|
+
|
|
675
|
+
Gets current queue size.
|
|
676
|
+
|
|
677
|
+
```typescript
|
|
678
|
+
const queueSize: number = Riuve.getQueueSize();
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Riuve.getFailedBatchCount()
|
|
682
|
+
|
|
683
|
+
Gets number of failed batches waiting for retry.
|
|
684
|
+
|
|
685
|
+
```typescript
|
|
686
|
+
const failedCount: number = await Riuve.getFailedBatchCount();
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Example Scenarios
|
|
692
|
+
|
|
693
|
+
### Scenario 1: E-Commerce App
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
// 1. On app start
|
|
697
|
+
useEffect(() => {
|
|
698
|
+
Riuve.initialize('api_key');
|
|
699
|
+
}, []);
|
|
700
|
+
|
|
701
|
+
// 2. When user logs in
|
|
702
|
+
const handleLogin = async (user: User) => {
|
|
703
|
+
await Riuve.identify(user.id, {
|
|
704
|
+
email: user.email,
|
|
705
|
+
name: user.name,
|
|
706
|
+
membership_type: user.membershipType,
|
|
707
|
+
});
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// 3. Product view
|
|
711
|
+
const handleProductView = (product: Product) => {
|
|
712
|
+
Riuve.track('product_viewed', {
|
|
713
|
+
product_id: product.id,
|
|
714
|
+
product_name: product.name,
|
|
715
|
+
product_category: product.category,
|
|
716
|
+
price: product.price,
|
|
717
|
+
});
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
// 4. Add to cart
|
|
721
|
+
const handleAddToCart = (product: Product) => {
|
|
722
|
+
Riuve.track('add_to_cart', {
|
|
723
|
+
product_id: product.id,
|
|
724
|
+
product_name: product.name,
|
|
725
|
+
price: product.price,
|
|
726
|
+
quantity: 1,
|
|
727
|
+
});
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
// 5. Purchase completed
|
|
731
|
+
const handlePurchaseComplete = async (order: Order) => {
|
|
732
|
+
await Riuve.track('purchase_completed', {
|
|
733
|
+
order_id: order.id,
|
|
734
|
+
total_amount: order.total,
|
|
735
|
+
items_count: order.items.length,
|
|
736
|
+
payment_method: order.paymentMethod,
|
|
737
|
+
});
|
|
738
|
+
await Riuve.flush(); // Critical event, send immediately
|
|
739
|
+
};
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Scenario 2: Social Media App
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
// 1. Post view
|
|
746
|
+
const handlePostView = (post: Post) => {
|
|
747
|
+
Riuve.track('post_viewed', {
|
|
748
|
+
post_id: post.id,
|
|
749
|
+
author_id: post.authorId,
|
|
750
|
+
post_type: post.type,
|
|
751
|
+
});
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
// 2. Like/Unlike
|
|
755
|
+
const handleLike = (post: Post) => {
|
|
756
|
+
Riuve.track('post_liked', {
|
|
757
|
+
post_id: post.id,
|
|
758
|
+
author_id: post.authorId,
|
|
759
|
+
});
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// 3. Comment
|
|
763
|
+
const handleComment = (post: Post, comment: string) => {
|
|
764
|
+
Riuve.track('comment_added', {
|
|
765
|
+
post_id: post.id,
|
|
766
|
+
comment_length: comment.length,
|
|
767
|
+
});
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// 4. Profile view
|
|
771
|
+
const handleProfileView = (userId: string) => {
|
|
772
|
+
Riuve.track('profile_viewed', {
|
|
773
|
+
profile_user_id: userId,
|
|
774
|
+
});
|
|
775
|
+
};
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
### Scenario 3: Game App
|
|
779
|
+
|
|
780
|
+
```typescript
|
|
781
|
+
// 1. Level start
|
|
782
|
+
const handleLevelStart = (level: number) => {
|
|
783
|
+
Riuve.track('level_started', {
|
|
784
|
+
level_number: level,
|
|
785
|
+
difficulty: 'normal',
|
|
786
|
+
});
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
// 2. Level completion
|
|
790
|
+
const handleLevelComplete = async (level: number, score: number) => {
|
|
791
|
+
await Riuve.track('level_completed', {
|
|
792
|
+
level_number: level,
|
|
793
|
+
score: score,
|
|
794
|
+
time_spent: getTimeSpent(),
|
|
795
|
+
});
|
|
796
|
+
await Riuve.flush(); // Important event
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
// 3. In-app purchase
|
|
800
|
+
const handleInAppPurchase = async (item: Item) => {
|
|
801
|
+
await Riuve.track('in_app_purchase', {
|
|
802
|
+
item_id: item.id,
|
|
803
|
+
item_name: item.name,
|
|
804
|
+
price: item.price,
|
|
805
|
+
currency: 'USD',
|
|
806
|
+
});
|
|
807
|
+
await Riuve.flush();
|
|
808
|
+
};
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
813
|
+
## Security
|
|
814
|
+
|
|
815
|
+
### API Key Security
|
|
816
|
+
|
|
817
|
+
- ✅ **Never** commit API keys to public repositories
|
|
818
|
+
- ✅ Use environment variables or secure storage
|
|
819
|
+
- ✅ Use different API keys for different projects
|
|
820
|
+
|
|
821
|
+
**Example:**
|
|
822
|
+
```typescript
|
|
823
|
+
// ✅ GOOD: Environment variable
|
|
824
|
+
const API_KEY = process.env.EXPO_PUBLIC_RIUVE_API_KEY || '';
|
|
825
|
+
|
|
826
|
+
// ❌ BAD: Hardcoded
|
|
827
|
+
const API_KEY = 'nock_live_xxxxxxxxxxxxx';
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## Support
|
|
833
|
+
|
|
834
|
+
For questions and support:
|
|
835
|
+
- 📧 Email: support@riuve.com
|
|
836
|
+
- 📚 Documentation: https://docs.riuve.com
|
|
837
|
+
- 💬 Discord: [Nock Community](https://discord.gg/nock)
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## License
|
|
842
|
+
|
|
843
|
+
MIT
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
847
|
+
**Last Updated:** 2025-01-29
|
|
848
|
+
**SDK Version:** 1.1.1
|