@journium/react 0.1.0-alpha.3 → 0.1.0-alpha.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/readme.md +197 -290
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@journium/react",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Journium React integration - Provider, hooks, and components for React applications",
package/readme.md CHANGED
@@ -30,10 +30,12 @@ function Root() {
30
30
  <JourniumProvider
31
31
  config={{
32
32
  token: "your-journium-token",
33
- apiHost: "https://your-journium-instance.com"
34
- // autocapture: true by default - no need to specify unless disabling
33
+ apiHost: "https://your-journium-instance.com",
34
+ debug: true, // Optional: Enable debug logging
35
+ flushAt: 5, // Optional: Send events after 5 events
36
+ flushInterval: 10000 // Optional: Send events every 10 seconds
35
37
  }}
36
- autoCapture={true} // Enables auto-pageview and triggers autocapture
38
+ autoCapture={true} // Enables auto-pageview and click tracking
37
39
  >
38
40
  <App />
39
41
  </JourniumProvider>
@@ -43,20 +45,21 @@ function Root() {
43
45
  export default Root;
44
46
  ```
45
47
 
46
- ### Using the Hook
48
+ ### Track Custom Events
47
49
 
48
- Track events anywhere in your components:
50
+ Use the `useTrackEvent` hook to track custom events:
49
51
 
50
52
  ```jsx
51
53
  import React from 'react';
52
- import { useJournium } from '@journium/react';
54
+ import { useTrackEvent } from '@journium/react';
53
55
 
54
56
  function SignupButton() {
55
- const { track } = useJournium();
57
+ const trackEvent = useTrackEvent();
56
58
 
57
59
  const handleSignup = () => {
58
- track('signup_attempted', {
59
- source: 'homepage',
60
+ trackEvent('user_signup', {
61
+ method: 'email',
62
+ source: 'landing_page',
60
63
  plan: 'free'
61
64
  });
62
65
  // Your signup logic
@@ -66,71 +69,100 @@ function SignupButton() {
66
69
  }
67
70
  ```
68
71
 
69
- ## 📖 API Reference
72
+ ## 📖 Tracking Hooks
70
73
 
71
- ### JourniumProvider
74
+ ### useTrackEvent - Track Custom Events
72
75
 
73
- The main provider component that initializes Journium for your React app.
76
+ The primary hook for tracking custom business events:
74
77
 
75
78
  ```jsx
76
- <JourniumProvider
77
- token="your-token" // Required: Your project token
78
- apiHost="https://api.journium.com" // Required: API endpoint
79
- debug={false} // Optional: Enable debug mode
80
- flushAt={20} // Optional: Flush after N events
81
- flushInterval={10000} // Optional: Flush interval (ms)
82
- autocapture={true} // Optional: Enable auto-capture
83
- sessionTimeout={1800000} // Optional: Session timeout (30m)
84
- >
85
- <YourApp />
86
- </JourniumProvider>
87
- ```
88
-
89
- ### useJournium Hook
90
-
91
- Access Journium functionality throughout your React app:
92
-
93
- ```jsx
94
- import { useJournium } from '@journium/react';
79
+ import { useTrackEvent } from '@journium/react';
95
80
 
96
- function MyComponent() {
97
- const { track, capturePageview, startAutoCapture, stopAutoCapture, flush } = useJournium();
81
+ function EcommerceComponent() {
82
+ const trackEvent = useTrackEvent();
98
83
 
99
- // Track events
100
- const handleClick = () => {
101
- track('button_clicked', {
102
- button_id: 'cta-primary',
103
- page: 'pricing'
84
+ const handlePurchase = () => {
85
+ trackEvent('purchase_completed', {
86
+ product_id: 'prod_123',
87
+ price: 29.99,
88
+ currency: 'USD',
89
+ category: 'electronics'
104
90
  });
105
91
  };
106
92
 
107
- // Manual pageview
108
- const handleNavigate = () => {
109
- capturePageview({
110
- previous_page: '/home',
111
- user_type: 'premium'
93
+ const handleAddToCart = () => {
94
+ trackEvent('product_added_to_cart', {
95
+ product_id: 'prod_123',
96
+ quantity: 1,
97
+ source: 'product_page'
112
98
  });
113
99
  };
114
100
 
115
- // Control auto-capture
116
- const toggleTracking = () => {
117
- if (trackingEnabled) {
118
- stopAutoCapture();
119
- } else {
120
- startAutoCapture();
121
- }
122
- };
123
-
124
101
  return (
125
102
  <div>
126
- <button onClick={handleClick}>Track Click</button>
127
- <button onClick={handleNavigate}>Manual Pageview</button>
128
- <button onClick={toggleTracking}>Toggle Tracking</button>
103
+ <button onClick={handleAddToCart}>Add to Cart</button>
104
+ <button onClick={handlePurchase}>Buy Now</button>
129
105
  </div>
130
106
  );
131
107
  }
132
108
  ```
133
109
 
110
+ ### useTrackPageview - Manual Pageview Tracking
111
+
112
+ For tracking custom pageviews beyond automatic route tracking:
113
+
114
+ ```jsx
115
+ import { useTrackPageview } from '@journium/react';
116
+
117
+ function CustomPageTracker() {
118
+ const trackPageview = useTrackPageview();
119
+
120
+ const handleSpecialPageview = () => {
121
+ trackPageview({
122
+ page_type: 'modal',
123
+ content_type: 'pricing_calculator',
124
+ user_segment: 'premium'
125
+ });
126
+ };
127
+
128
+ return (
129
+ <button onClick={handleSpecialPageview}>
130
+ Track Modal View
131
+ </button>
132
+ );
133
+ }
134
+ ```
135
+
136
+ ### useAutoTrackPageview - Automatic Pageview on Mount
137
+
138
+ Automatically track pageviews when components mount or dependencies change:
139
+
140
+ ```jsx
141
+ import { useAutoTrackPageview } from '@journium/react';
142
+
143
+ function ProductPage({ productId, category }) {
144
+ // Tracks pageview when component mounts or productId changes
145
+ useAutoTrackPageview([productId], {
146
+ page_type: 'product_detail',
147
+ product_id: productId,
148
+ category: category
149
+ });
150
+
151
+ return <div>Product {productId}</div>;
152
+ }
153
+
154
+ function BlogPost({ postId }) {
155
+ // Track pageview for blog posts
156
+ useAutoTrackPageview([postId], {
157
+ page_type: 'blog_post',
158
+ post_id: postId,
159
+ content_type: 'article'
160
+ });
161
+
162
+ return <article>Blog post content</article>;
163
+ }
164
+ ```
165
+
134
166
  ## 🔧 Advanced Usage
135
167
 
136
168
  ### Form Tracking
@@ -138,27 +170,27 @@ function MyComponent() {
138
170
  Track form interactions and submissions:
139
171
 
140
172
  ```jsx
141
- import { useJournium } from '@journium/react';
173
+ import { useTrackEvent } from '@journium/react';
142
174
 
143
175
  function ContactForm() {
144
- const { track } = useJournium();
176
+ const trackEvent = useTrackEvent();
145
177
 
146
178
  const handleSubmit = (e) => {
147
179
  e.preventDefault();
148
180
 
149
- track('form_submitted', {
181
+ trackEvent('form_submitted', {
150
182
  form_name: 'contact',
151
183
  form_type: 'lead_generation',
152
- fields_filled: ['name', 'email', 'company']
184
+ fields_completed: ['name', 'email', 'company']
153
185
  });
154
186
 
155
187
  // Submit form logic
156
188
  };
157
189
 
158
- const handleFieldChange = (field) => {
159
- track('form_field_changed', {
190
+ const handleFieldChange = (fieldName) => {
191
+ trackEvent('form_field_completed', {
160
192
  form_name: 'contact',
161
- field_name: field
193
+ field_name: fieldName
162
194
  });
163
195
  };
164
196
 
@@ -180,174 +212,96 @@ function ContactForm() {
180
212
  }
181
213
  ```
182
214
 
183
- ### E-commerce Tracking
215
+ ### User Journey Tracking
184
216
 
185
- Track purchase flows and product interactions:
217
+ Track multi-step user flows:
186
218
 
187
219
  ```jsx
188
- import { useJournium } from '@journium/react';
220
+ import { useTrackEvent, useTrackPageview } from '@journium/react';
189
221
 
190
- function ProductPage({ product }) {
191
- const { track } = useJournium();
222
+ function OnboardingFlow({ step }) {
223
+ const trackEvent = useTrackEvent();
224
+ const trackPageview = useTrackPageview();
192
225
 
193
- const handleAddToCart = () => {
194
- track('product_added_to_cart', {
195
- product_id: product.id,
196
- product_name: product.name,
197
- category: product.category,
198
- price: product.price,
199
- currency: 'USD'
226
+ useEffect(() => {
227
+ // Track onboarding step pageview
228
+ trackPageview({
229
+ page_type: 'onboarding',
230
+ step: step,
231
+ flow: 'user_setup'
200
232
  });
201
- };
233
+ }, [step, trackPageview]);
202
234
 
203
- const handlePurchase = (orderData) => {
204
- track('purchase_completed', {
205
- order_id: orderData.id,
206
- revenue: orderData.total,
207
- currency: 'USD',
208
- products: orderData.items.map(item => ({
209
- product_id: item.id,
210
- quantity: item.quantity,
211
- price: item.price
212
- }))
235
+ const handleStepComplete = () => {
236
+ trackEvent('onboarding_step_completed', {
237
+ step: step,
238
+ time_spent: Date.now() - stepStartTime,
239
+ completed_successfully: true
213
240
  });
214
241
  };
215
242
 
216
- return (
217
- <div>
218
- <h1>{product.name}</h1>
219
- <p>${product.price}</p>
220
- <button onClick={handleAddToCart}>Add to Cart</button>
221
- </div>
222
- );
223
- }
224
- ```
225
-
226
- ### React Router Integration
227
-
228
- Track page navigation automatically:
229
-
230
- ```jsx
231
- import { useEffect } from 'react';
232
- import { useLocation } from 'react-router-dom';
233
- import { useJournium } from '@journium/react';
234
-
235
- function PageTracker() {
236
- const location = useLocation();
237
- const { capturePageview } = useJournium();
238
-
239
- useEffect(() => {
240
- capturePageview({
241
- path: location.pathname,
242
- search: location.search,
243
- referrer: document.referrer
243
+ const handleSkipStep = () => {
244
+ trackEvent('onboarding_step_skipped', {
245
+ step: step,
246
+ reason: 'user_choice'
244
247
  });
245
- }, [location, capturePageview]);
246
-
247
- return null;
248
- }
249
-
250
- // Add to your router setup
251
- function App() {
252
- return (
253
- <Router>
254
- <PageTracker />
255
- <Routes>
256
- {/* Your routes */}
257
- </Routes>
258
- </Router>
259
- );
260
- }
261
- ```
262
-
263
- ### Conditional Tracking
264
-
265
- Control tracking based on user preferences or environment:
266
-
267
- ```jsx
268
- import { useJournium } from '@journium/react';
269
-
270
- function ConditionalTracker() {
271
- const { track, startAutoCapture, stopAutoCapture } = useJournium();
272
- const [hasConsent, setHasConsent] = useState(false);
273
-
274
- useEffect(() => {
275
- if (hasConsent) {
276
- startAutoCapture();
277
- track('tracking_consent_given');
278
- } else {
279
- stopAutoCapture();
280
- }
281
- }, [hasConsent, startAutoCapture, stopAutoCapture, track]);
248
+ };
282
249
 
283
250
  return (
284
251
  <div>
285
- <label>
286
- <input
287
- type="checkbox"
288
- checked={hasConsent}
289
- onChange={(e) => setHasConsent(e.target.checked)}
290
- />
291
- Allow analytics tracking
292
- </label>
252
+ <h2>Step {step}</h2>
253
+ <button onClick={handleStepComplete}>Complete Step</button>
254
+ <button onClick={handleSkipStep}>Skip</button>
293
255
  </div>
294
256
  );
295
257
  }
296
258
  ```
297
259
 
298
- ### Custom Hook for User Actions
260
+ ### Feature Usage Tracking
299
261
 
300
- Create reusable tracking hooks:
262
+ Create reusable tracking patterns:
301
263
 
302
264
  ```jsx
303
- import { useJournium } from '@journium/react';
304
-
305
- function useUserActions() {
306
- const { track } = useJournium();
265
+ import { useTrackEvent } from '@journium/react';
307
266
 
308
- const trackSignup = (method, plan) => {
309
- track('user_signup', {
310
- signup_method: method,
311
- selected_plan: plan,
312
- timestamp: new Date().toISOString()
313
- });
314
- };
267
+ // Custom hook for feature tracking
268
+ function useFeatureTracking() {
269
+ const trackEvent = useTrackEvent();
315
270
 
316
- const trackLogin = (method) => {
317
- track('user_login', {
318
- login_method: method,
319
- timestamp: new Date().toISOString()
271
+ const trackFeatureUsed = (featureName, context = {}) => {
272
+ trackEvent('feature_used', {
273
+ feature_name: featureName,
274
+ timestamp: new Date().toISOString(),
275
+ ...context
320
276
  });
321
277
  };
322
278
 
323
- const trackFeatureUsed = (feature, context = {}) => {
324
- track('feature_used', {
325
- feature_name: feature,
326
- ...context,
327
- timestamp: new Date().toISOString()
279
+ const trackFeatureDiscovered = (featureName, discoveryMethod) => {
280
+ trackEvent('feature_discovered', {
281
+ feature_name: featureName,
282
+ discovery_method: discoveryMethod
328
283
  });
329
284
  };
330
285
 
331
- return {
332
- trackSignup,
333
- trackLogin,
334
- trackFeatureUsed
335
- };
286
+ return { trackFeatureUsed, trackFeatureDiscovered };
336
287
  }
337
288
 
338
289
  // Usage in components
339
- function LoginForm() {
340
- const { trackLogin } = useUserActions();
290
+ function AdvancedFeature() {
291
+ const { trackFeatureUsed, trackFeatureDiscovered } = useFeatureTracking();
341
292
 
342
- const handleLogin = (method) => {
343
- trackLogin(method);
344
- // Login logic
293
+ const handleFeatureClick = () => {
294
+ trackFeatureUsed('advanced_search', {
295
+ search_type: 'filters',
296
+ filter_count: 3
297
+ });
345
298
  };
346
299
 
347
300
  return (
348
301
  <div>
349
- <button onClick={() => handleLogin('email')}>Login with Email</button>
350
- <button onClick={() => handleLogin('google')}>Login with Google</button>
302
+ <button onClick={handleFeatureClick}>
303
+ Use Advanced Search
304
+ </button>
351
305
  </div>
352
306
  );
353
307
  }
@@ -357,41 +311,43 @@ function LoginForm() {
357
311
 
358
312
  ### User Consent Management
359
313
 
314
+ Control tracking based on user consent:
315
+
360
316
  ```jsx
361
317
  import { useState, useEffect } from 'react';
362
- import { useJournium } from '@journium/react';
318
+ import { useAutocapture } from '@journium/react';
363
319
 
364
- function PrivacyBanner() {
365
- const { startAutoCapture, stopAutoCapture, flush } = useJournium();
366
- const [showBanner, setShowBanner] = useState(true);
320
+ function ConsentBanner() {
321
+ const { startAutocapture, stopAutocapture } = useAutocapture();
322
+ const [hasConsent, setHasConsent] = useState(null);
323
+
324
+ useEffect(() => {
325
+ const savedConsent = localStorage.getItem('tracking_consent');
326
+ if (savedConsent === 'true') {
327
+ setHasConsent(true);
328
+ startAutocapture();
329
+ } else if (savedConsent === 'false') {
330
+ setHasConsent(false);
331
+ stopAutocapture();
332
+ }
333
+ }, [startAutocapture, stopAutocapture]);
367
334
 
368
335
  const handleAccept = () => {
369
- localStorage.setItem('journium_consent', 'true');
370
- setShowBanner(false);
371
- startAutoCapture();
336
+ setHasConsent(true);
337
+ localStorage.setItem('tracking_consent', 'true');
338
+ startAutocapture();
372
339
  };
373
340
 
374
341
  const handleDecline = () => {
375
- localStorage.setItem('journium_consent', 'false');
376
- setShowBanner(false);
377
- stopAutoCapture();
342
+ setHasConsent(false);
343
+ localStorage.setItem('tracking_consent', 'false');
344
+ stopAutocapture();
378
345
  };
379
346
 
380
- useEffect(() => {
381
- const consent = localStorage.getItem('journium_consent');
382
- if (consent === 'false') {
383
- stopAutoCapture();
384
- setShowBanner(false);
385
- } else if (consent === 'true') {
386
- startAutoCapture();
387
- setShowBanner(false);
388
- }
389
- }, [startAutoCapture, stopAutoCapture]);
390
-
391
- if (!showBanner) return null;
347
+ if (hasConsent !== null) return null;
392
348
 
393
349
  return (
394
- <div className="privacy-banner">
350
+ <div className="consent-banner">
395
351
  <p>We use analytics to improve your experience.</p>
396
352
  <button onClick={handleAccept}>Accept</button>
397
353
  <button onClick={handleDecline}>Decline</button>
@@ -402,21 +358,20 @@ function PrivacyBanner() {
402
358
 
403
359
  ### Excluding Sensitive Data
404
360
 
361
+ Configure autocapture to ignore sensitive elements:
362
+
405
363
  ```jsx
406
364
  <JourniumProvider
407
- token="your-token"
408
- apiHost="https://api.journium.com"
409
- autocapture={{
410
- captureClicks: true,
411
- captureFormSubmits: true,
412
- captureFormChanges: false,
413
- ignoreClasses: ['no-track', 'sensitive', 'pii'],
414
- ignoreElements: [
415
- 'input[type="password"]',
416
- 'input[type="email"]',
417
- '.credit-card-input',
418
- '[data-private]'
419
- ]
365
+ config={{
366
+ token: "your-token",
367
+ apiHost: "https://api.journium.com",
368
+ autocapture: {
369
+ captureClicks: true,
370
+ captureFormSubmits: true,
371
+ captureFormChanges: false,
372
+ ignoreClasses: ['no-track', 'sensitive', 'pii'],
373
+ ignoreElements: ['input[type="password"]', '.credit-card']
374
+ }
420
375
  }}
421
376
  >
422
377
  <App />
@@ -428,84 +383,36 @@ function PrivacyBanner() {
428
383
  Full TypeScript support with complete type definitions:
429
384
 
430
385
  ```typescript
431
- import { useJournium, JourniumConfig } from '@journium/react';
386
+ import { useTrackEvent, JourniumConfig } from '@journium/react';
432
387
 
433
- interface CustomEventProperties {
388
+ interface PurchaseEventProperties {
434
389
  product_id: string;
435
390
  category: string;
436
391
  price: number;
392
+ currency: string;
437
393
  }
438
394
 
439
395
  function TypedComponent() {
440
- const { track } = useJournium();
396
+ const trackEvent = useTrackEvent();
441
397
 
442
- const handlePurchase = () => {
398
+ const handlePurchase = (productData: PurchaseEventProperties) => {
443
399
  // Fully typed event tracking
444
- track('product_purchased', {
445
- product_id: 'prod_123',
446
- category: 'electronics',
447
- price: 299.99
448
- } as CustomEventProperties);
400
+ trackEvent('product_purchased', productData);
449
401
  };
450
402
 
451
403
  return <button onClick={handlePurchase}>Purchase</button>;
452
404
  }
453
-
454
- // Type-safe provider configuration
455
- const config: JourniumConfig = {
456
- token: 'your-token',
457
- apiHost: 'https://api.journium.com',
458
- autocapture: {
459
- captureClicks: true,
460
- captureFormSubmits: true,
461
- ignoreClasses: ['no-track']
462
- }
463
- };
464
405
  ```
465
406
 
466
- ## Performance Optimization
407
+ ## 🔗 Available Hooks
467
408
 
468
- ### Lazy Loading
469
-
470
- ```jsx
471
- import { lazy, Suspense } from 'react';
472
-
473
- const JourniumProvider = lazy(() => import('@journium/react').then(module => ({
474
- default: module.JourniumProvider
475
- })));
476
-
477
- function App() {
478
- return (
479
- <Suspense fallback={<div>Loading...</div>}>
480
- <JourniumProvider token="your-token" apiHost="https://api.journium.com">
481
- <YourApp />
482
- </JourniumProvider>
483
- </Suspense>
484
- );
485
- }
486
- ```
487
-
488
- ### Event Batching
489
-
490
- ```jsx
491
- import { useJournium } from '@journium/react';
492
-
493
- function BatchedTracking() {
494
- const { track, flush } = useJournium();
495
-
496
- const handleMultipleActions = async () => {
497
- // Queue multiple events
498
- track('action_1', { step: 1 });
499
- track('action_2', { step: 2 });
500
- track('action_3', { step: 3 });
501
-
502
- // Force flush all queued events
503
- await flush();
504
- };
505
-
506
- return <button onClick={handleMultipleActions}>Complete Flow</button>;
507
- }
508
- ```
409
+ | Hook | Purpose | Usage |
410
+ |------|---------|-------|
411
+ | `useTrackEvent()` | Track custom events | `trackEvent('event_name', properties)` |
412
+ | `useTrackPageview()` | Manual pageview tracking | `trackPageview(properties)` |
413
+ | `useAutoTrackPageview(deps, props)` | Automatic pageview on mount | Auto-tracks when deps change |
414
+ | `useAutocapture()` | Control autocapture | `{ startAutocapture, stopAutocapture }` |
415
+ | `useJournium()` | Direct Journium instance access | Advanced use cases only |
509
416
 
510
417
  ## 🔗 Related Packages
511
418