@datalyr/web 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/README.md ADDED
@@ -0,0 +1,727 @@
1
+ # @datalyr/web
2
+
3
+ The official Datalyr Web SDK for browser-based analytics. Track user behavior, measure conversions, and understand your customer journey with enterprise-grade analytics.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@datalyr/web.svg)](https://www.npmjs.com/package/@datalyr/web)
6
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@datalyr/web)](https://bundlephobia.com/package/@datalyr/web)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
+ [![License](https://img.shields.io/npm/l/@datalyr/web.svg)](https://github.com/datalyr/web/blob/main/LICENSE)
9
+
10
+ ## Features
11
+
12
+ - 🚀 **Zero Configuration** - Start tracking with just your workspace ID
13
+ - 📦 **Lightweight** - ~15KB minified + gzipped with zero dependencies
14
+ - 🔒 **Privacy First** - GDPR compliant with built-in consent management
15
+ - 🎯 **Smart Batching** - Optimized network usage with intelligent event queuing
16
+ - 📱 **Cross-Platform** - Works on all modern browsers including mobile
17
+ - 🔄 **Offline Support** - Events are queued and sent when connection restored
18
+ - 🏷️ **Attribution Tracking** - Automatic UTM and click ID capture
19
+ - 🔍 **Session Management** - Automatic session tracking with configurable timeout
20
+ - 🎨 **TypeScript Support** - Full type definitions included
21
+ - 🔌 **Extensible** - Plugin system for custom functionality
22
+ - 📦 **Container Scripts** - Securely manage third-party pixels and tracking scripts
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @datalyr/web
28
+ # or
29
+ yarn add @datalyr/web
30
+ # or
31
+ pnpm add @datalyr/web
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```javascript
37
+ import { Datalyr } from '@datalyr/web';
38
+
39
+ // Initialize with your workspace ID
40
+ const datalyr = new Datalyr({
41
+ workspaceId: 'YOUR_WORKSPACE_ID'
42
+ });
43
+
44
+ // Initialize the SDK
45
+ await datalyr.init();
46
+
47
+ // Track an event
48
+ datalyr.track('Button Clicked', {
49
+ button_name: 'Sign Up',
50
+ location: 'Header'
51
+ });
52
+
53
+ // Identify a user
54
+ datalyr.identify('user_123', {
55
+ email: 'user@example.com',
56
+ name: 'John Doe',
57
+ plan: 'premium'
58
+ });
59
+ ```
60
+
61
+ ## Core Methods
62
+
63
+ ### Initialization
64
+
65
+ ```javascript
66
+ const datalyr = new Datalyr({
67
+ workspaceId: 'YOUR_WORKSPACE_ID',
68
+
69
+ // Optional configuration
70
+ // endpoint: 'https://custom.endpoint.com', // Optional: Custom endpoint
71
+ debug: false, // Enable debug logging
72
+ // batchSize: 10, // Optional: Events per batch
73
+ // flushInterval: 5000, // Optional: Flush interval (ms)
74
+ sessionTimeout: 1800000, // 30 minutes
75
+ privacyMode: 'standard', // 'standard' or 'strict'
76
+ respectDoNotTrack: false, // Honor browser DNT
77
+ respectGlobalPrivacyControl: true, // Honor GPC
78
+ cookieDomain: 'auto', // Auto-detect for subdomains
79
+ trackSPA: true, // Track SPA route changes
80
+ trackPageViews: true // Track initial page view
81
+ });
82
+
83
+ await datalyr.init();
84
+ ```
85
+
86
+ ### Track Events
87
+
88
+ Track custom events with properties:
89
+
90
+ ```javascript
91
+ // Simple event
92
+ datalyr.track('Video Played');
93
+
94
+ // Event with properties
95
+ datalyr.track('Product Viewed', {
96
+ product_id: 'SKU-123',
97
+ product_name: 'Premium Widget',
98
+ category: 'Electronics',
99
+ price: 99.99,
100
+ currency: 'USD'
101
+ });
102
+
103
+ // E-commerce events
104
+ datalyr.track('Purchase', {
105
+ order_id: 'ORD-456',
106
+ total: 299.99,
107
+ currency: 'USD',
108
+ items: [
109
+ { product_id: 'SKU-123', quantity: 2, price: 99.99 },
110
+ { product_id: 'SKU-456', quantity: 1, price: 100.01 }
111
+ ]
112
+ });
113
+ ```
114
+
115
+ ### Identify Users
116
+
117
+ Associate events with users:
118
+
119
+ ```javascript
120
+ // Identify with user ID only
121
+ datalyr.identify('user_123');
122
+
123
+ // Identify with traits
124
+ datalyr.identify('user_123', {
125
+ email: 'user@example.com',
126
+ name: 'John Doe',
127
+ firstName: 'John',
128
+ lastName: 'Doe',
129
+ phone: '+1234567890',
130
+ plan: 'premium',
131
+ createdAt: '2024-01-01'
132
+ });
133
+
134
+ // Update user traits without changing ID
135
+ datalyr.identify(null, {
136
+ plan: 'enterprise',
137
+ company: 'Acme Corp'
138
+ });
139
+ ```
140
+
141
+ ### Page Tracking
142
+
143
+ Track page views:
144
+
145
+ ```javascript
146
+ // Track current page
147
+ datalyr.page();
148
+
149
+ // Track with custom properties
150
+ datalyr.page({
151
+ title: 'Pricing Page',
152
+ category: 'Marketing',
153
+ author: 'Marketing Team'
154
+ });
155
+
156
+ // Track with page name
157
+ datalyr.page('Pricing', {
158
+ plan: 'premium',
159
+ variant: 'A'
160
+ });
161
+ ```
162
+
163
+ ### Managing Identity
164
+
165
+ ```javascript
166
+ // Get current user IDs
167
+ const anonymousId = datalyr.getAnonymousId();
168
+ const userId = datalyr.getUserId();
169
+ const distinctId = datalyr.getDistinctId();
170
+
171
+ // Reset identity (for logout)
172
+ datalyr.reset();
173
+
174
+ // Create alias (link anonymous to identified user)
175
+ datalyr.alias('user_123');
176
+ ```
177
+
178
+ ### User Consent
179
+
180
+ Manage user privacy preferences:
181
+
182
+ ```javascript
183
+ // Opt user out of tracking
184
+ datalyr.optOut();
185
+
186
+ // Opt user back in
187
+ datalyr.optIn();
188
+
189
+ // Check opt-out status
190
+ const isOptedOut = datalyr.isOptedOut();
191
+
192
+ // Set consent preferences
193
+ datalyr.setConsent({
194
+ analytics: true,
195
+ marketing: false,
196
+ preferences: true,
197
+ sale: false // CCPA "Do Not Sell"
198
+ });
199
+ ```
200
+
201
+ ### Session Management
202
+
203
+ ```javascript
204
+ // Get current session ID
205
+ const sessionId = datalyr.getSessionId();
206
+
207
+ // Manually end session
208
+ datalyr.endSession();
209
+
210
+ // Start new session
211
+ datalyr.startNewSession();
212
+ ```
213
+
214
+ ## Advanced Features
215
+
216
+ ### Event Priority
217
+
218
+ Important events like purchases are automatically prioritized for faster delivery:
219
+
220
+ ```javascript
221
+ // Important conversion events
222
+ datalyr.track('Purchase', { value: 99.99 });
223
+ datalyr.track('Signup', { plan: 'premium' });
224
+ datalyr.track('Subscribe', { plan: 'annual' });
225
+
226
+ // E-commerce events
227
+ datalyr.track('Add to Cart', { product_id: 'SKU-123' });
228
+ datalyr.track('Begin Checkout', { cart_value: 199.99 });
229
+ ```
230
+
231
+ ### Attribution Tracking
232
+
233
+ The SDK automatically captures:
234
+ - UTM parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content)
235
+ - Click IDs (gclid, fbclid, ttclid, msclkid, twclid, li_fat_id)
236
+ - Referrer information
237
+ - Landing page
238
+ - Customer journey touchpoints
239
+
240
+ ```javascript
241
+ // Attribution data is automatically added to events
242
+ datalyr.track('Signup');
243
+ // Includes: utm_source, utm_medium, first_touch_source, last_touch_source, etc.
244
+
245
+ // Track custom URL parameters
246
+ const datalyr = new Datalyr({
247
+ workspaceId: 'YOUR_WORKSPACE_ID',
248
+ trackedParams: ['ref', 'affiliate_id', 'promo_code']
249
+ });
250
+ ```
251
+
252
+ ### SPA Support
253
+
254
+ For single-page applications:
255
+
256
+ ```javascript
257
+ const datalyr = new Datalyr({
258
+ workspaceId: 'YOUR_WORKSPACE_ID',
259
+ trackSPA: true // Auto-track route changes (default: true)
260
+ });
261
+
262
+ // Manual route tracking
263
+ datalyr.page('Product Details', {
264
+ product_id: 'SKU-123'
265
+ });
266
+ ```
267
+
268
+ ### Privacy Modes
269
+
270
+ Control data collection:
271
+
272
+ ```javascript
273
+ // Standard mode (default) - balanced privacy
274
+ const datalyr = new Datalyr({
275
+ workspaceId: 'YOUR_WORKSPACE_ID',
276
+ privacyMode: 'standard'
277
+ });
278
+
279
+ // Strict mode - minimal data collection
280
+ const datalyr = new Datalyr({
281
+ workspaceId: 'YOUR_WORKSPACE_ID',
282
+ privacyMode: 'strict'
283
+ });
284
+ ```
285
+
286
+ ### Offline Support
287
+
288
+ Events are automatically saved when offline and sent when connection is restored:
289
+
290
+ ```javascript
291
+ // Events work seamlessly offline
292
+ datalyr.track('Button Clicked'); // Automatically queued if offline
293
+
294
+ // Manually flush pending events
295
+ await datalyr.flush();
296
+ ```
297
+
298
+ ### Cross-Subdomain Tracking
299
+
300
+ Automatically track users across subdomains:
301
+
302
+ ```javascript
303
+ // Auto-detect domain for *.example.com
304
+ const datalyr = new Datalyr({
305
+ workspaceId: 'YOUR_WORKSPACE_ID',
306
+ cookieDomain: 'auto' // Default
307
+ });
308
+
309
+ // Or set explicitly
310
+ const datalyr = new Datalyr({
311
+ workspaceId: 'YOUR_WORKSPACE_ID',
312
+ cookieDomain: '.example.com'
313
+ });
314
+ ```
315
+
316
+ ### Container Scripts
317
+
318
+ The SDK can automatically load and manage third-party tracking scripts with built-in security:
319
+
320
+ ```javascript
321
+ const datalyr = new Datalyr({
322
+ workspaceId: 'YOUR_WORKSPACE_ID',
323
+ enableContainer: true // Default: true
324
+ });
325
+
326
+ // Container scripts are loaded automatically based on your
327
+ // configuration in the Datalyr dashboard
328
+
329
+ // Manually trigger a custom script
330
+ datalyr.loadScript('custom-script-id');
331
+
332
+ // Get list of loaded scripts
333
+ const loadedScripts = datalyr.getLoadedScripts();
334
+ ```
335
+
336
+ The container manager supports:
337
+ - **Third-party pixels**: Meta (Facebook), Google, TikTok
338
+ - **Custom scripts**: Inline JavaScript or external scripts
339
+ - **Tracking pixels**: Image-based tracking pixels
340
+ - **Conditional loading**: Based on URL, device type, etc.
341
+ - **Frequency control**: Once per session, once per page, or always
342
+
343
+ **Security Features:**
344
+ - ✅ HTTPS-only script loading (except localhost)
345
+ - ✅ XSS protection with pattern detection
346
+ - ✅ URL validation and protocol blocking
347
+ - ✅ CSP nonce support for inline scripts
348
+ - ✅ Automatic async loading for better performance
349
+
350
+ ### Plugins
351
+
352
+ Extend SDK functionality:
353
+
354
+ ```javascript
355
+ // Create a plugin
356
+ const myPlugin = {
357
+ name: 'my-plugin',
358
+
359
+ initialize(datalyr) {
360
+ console.log('Plugin initialized');
361
+ },
362
+
363
+ track(eventName, properties) {
364
+ console.log('Event tracked:', eventName);
365
+ },
366
+
367
+ identify(userId, traits) {
368
+ console.log('User identified:', userId);
369
+ },
370
+
371
+ page(properties) {
372
+ console.log('Page tracked');
373
+ }
374
+ };
375
+
376
+ // Register plugin
377
+ const datalyr = new Datalyr({
378
+ workspaceId: 'YOUR_WORKSPACE_ID',
379
+ plugins: [myPlugin]
380
+ });
381
+ ```
382
+
383
+ ## TypeScript Support
384
+
385
+ Full TypeScript definitions are included:
386
+
387
+ ```typescript
388
+ import { Datalyr, EventProperties, UserTraits } from '@datalyr/web';
389
+
390
+ const datalyr = new Datalyr({
391
+ workspaceId: 'YOUR_WORKSPACE_ID'
392
+ });
393
+
394
+ // Type-safe event properties
395
+ const properties: EventProperties = {
396
+ product_id: 'SKU-123',
397
+ price: 99.99,
398
+ quantity: 2
399
+ };
400
+
401
+ datalyr.track('Product Added', properties);
402
+
403
+ // Type-safe user traits
404
+ const traits: UserTraits = {
405
+ email: 'user@example.com',
406
+ name: 'John Doe',
407
+ plan: 'premium'
408
+ };
409
+
410
+ datalyr.identify('user_123', traits);
411
+ ```
412
+
413
+ ## Framework Integration
414
+
415
+ ### React
416
+
417
+ ```jsx
418
+ import { useEffect } from 'react';
419
+ import { Datalyr } from '@datalyr/web';
420
+
421
+ const datalyr = new Datalyr({
422
+ workspaceId: 'YOUR_WORKSPACE_ID'
423
+ });
424
+
425
+ function App() {
426
+ useEffect(() => {
427
+ datalyr.init();
428
+ }, []);
429
+
430
+ const handleClick = () => {
431
+ datalyr.track('Button Clicked', {
432
+ button_name: 'CTA'
433
+ });
434
+ };
435
+
436
+ return <button onClick={handleClick}>Click Me</button>;
437
+ }
438
+ ```
439
+
440
+ ### Vue
441
+
442
+ ```vue
443
+ <script setup>
444
+ import { onMounted } from 'vue';
445
+ import { Datalyr } from '@datalyr/web';
446
+
447
+ const datalyr = new Datalyr({
448
+ workspaceId: 'YOUR_WORKSPACE_ID'
449
+ });
450
+
451
+ onMounted(() => {
452
+ datalyr.init();
453
+ });
454
+
455
+ const trackClick = () => {
456
+ datalyr.track('Button Clicked');
457
+ };
458
+ </script>
459
+
460
+ <template>
461
+ <button @click="trackClick">Click Me</button>
462
+ </template>
463
+ ```
464
+
465
+ ### Next.js
466
+
467
+ ```jsx
468
+ // app/providers.tsx
469
+ 'use client';
470
+
471
+ import { useEffect } from 'react';
472
+ import { Datalyr } from '@datalyr/web';
473
+
474
+ const datalyr = new Datalyr({
475
+ workspaceId: process.env.NEXT_PUBLIC_DATALYR_WORKSPACE_ID
476
+ });
477
+
478
+ export function AnalyticsProvider({ children }) {
479
+ useEffect(() => {
480
+ datalyr.init();
481
+ }, []);
482
+
483
+ return children;
484
+ }
485
+
486
+ // app/layout.tsx
487
+ import { AnalyticsProvider } from './providers';
488
+
489
+ export default function RootLayout({ children }) {
490
+ return (
491
+ <html>
492
+ <body>
493
+ <AnalyticsProvider>
494
+ {children}
495
+ </AnalyticsProvider>
496
+ </body>
497
+ </html>
498
+ );
499
+ }
500
+ ```
501
+
502
+ ## Best Practices
503
+
504
+ ### 1. Initialize Early
505
+ Initialize the SDK as early as possible in your application lifecycle:
506
+
507
+ ```javascript
508
+ // In your main entry file
509
+ import { Datalyr } from '@datalyr/web';
510
+
511
+ const datalyr = new Datalyr({
512
+ workspaceId: 'YOUR_WORKSPACE_ID'
513
+ });
514
+
515
+ // Initialize before other code
516
+ datalyr.init().then(() => {
517
+ // Start your app
518
+ });
519
+ ```
520
+
521
+ ### 2. Use Consistent Event Naming
522
+ Adopt a naming convention for your events:
523
+
524
+ ```javascript
525
+ // Good: Consistent, descriptive names
526
+ datalyr.track('Product Viewed');
527
+ datalyr.track('Cart Updated');
528
+ datalyr.track('Checkout Started');
529
+
530
+ // Avoid: Inconsistent naming
531
+ datalyr.track('view_product');
532
+ datalyr.track('Cart-Update');
533
+ datalyr.track('CHECKOUT_START');
534
+ ```
535
+
536
+ ### 3. Include Relevant Properties
537
+ Add properties that will help with analysis:
538
+
539
+ ```javascript
540
+ // Good: Rich context
541
+ datalyr.track('Product Viewed', {
542
+ product_id: 'SKU-123',
543
+ product_name: 'Premium Widget',
544
+ category: 'Electronics',
545
+ price: 99.99,
546
+ currency: 'USD',
547
+ in_stock: true,
548
+ view_type: 'quick_view'
549
+ });
550
+
551
+ // Avoid: Missing context
552
+ datalyr.track('Product Viewed', {
553
+ id: '123'
554
+ });
555
+ ```
556
+
557
+ ### 4. Identify Users After Authentication
558
+ Call identify as soon as you know who the user is:
559
+
560
+ ```javascript
561
+ // After login
562
+ async function handleLogin(email, password) {
563
+ const user = await loginUser(email, password);
564
+
565
+ // Identify immediately after login
566
+ datalyr.identify(user.id, {
567
+ email: user.email,
568
+ name: user.name,
569
+ plan: user.subscription
570
+ });
571
+ }
572
+
573
+ // After signup
574
+ async function handleSignup(data) {
575
+ const user = await createUser(data);
576
+
577
+ datalyr.identify(user.id, {
578
+ email: data.email,
579
+ name: data.name,
580
+ signup_date: new Date().toISOString()
581
+ });
582
+
583
+ datalyr.track('Signup Completed', {
584
+ method: 'email'
585
+ });
586
+ }
587
+ ```
588
+
589
+ ### 5. Handle Errors Gracefully
590
+ The SDK handles errors internally, but you can add your own error tracking:
591
+
592
+ ```javascript
593
+ window.addEventListener('error', (event) => {
594
+ datalyr.track('JavaScript Error', {
595
+ message: event.message,
596
+ source: event.filename,
597
+ line: event.lineno,
598
+ column: event.colno,
599
+ error: event.error?.toString()
600
+ });
601
+ });
602
+ ```
603
+
604
+ ## Migration from Script Tag
605
+
606
+ If you're currently using the Datalyr script tag, migration is straightforward:
607
+
608
+ ### Before (Script Tag):
609
+ ```html
610
+ <script>
611
+ window.datalyr = window.datalyr || [];
612
+ window.datalyr.push(['init', { workspace_id: 'YOUR_WORKSPACE_ID' }]);
613
+ window.datalyr.push(['track', 'Button Clicked']);
614
+ </script>
615
+ <script async src="https://cdn.datalyr.io/datalyr.js"></script>
616
+ ```
617
+
618
+ ### After (Web SDK):
619
+ ```javascript
620
+ import { Datalyr } from '@datalyr/web';
621
+
622
+ const datalyr = new Datalyr({
623
+ workspaceId: 'YOUR_WORKSPACE_ID'
624
+ });
625
+
626
+ await datalyr.init();
627
+ datalyr.track('Button Clicked');
628
+ ```
629
+
630
+ ## Browser Support
631
+
632
+ The SDK supports all modern browsers:
633
+ - Chrome/Edge 90+
634
+ - Firefox 88+
635
+ - Safari 14+
636
+ - Opera 76+
637
+
638
+ For older browsers, the SDK will gracefully degrade with fallback implementations.
639
+
640
+ ## Performance
641
+
642
+ - **Bundle Size**: ~15KB minified + gzipped
643
+ - **Zero Dependencies**: No external dependencies
644
+ - **Optimized**: Smart event batching reduces network requests
645
+ - **Fast**: Deferred loading for non-critical operations
646
+ - **Memory Management**: Automatic cleanup of resources
647
+
648
+ ## Privacy & Compliance
649
+
650
+ The SDK is designed with privacy in mind:
651
+
652
+ - **GDPR Compliant**: Built-in consent management
653
+ - **CCPA Support**: "Do Not Sell" preference support
654
+ - **Cookie Control**: Configurable cookie settings
655
+ - **Data Minimization**: Collect only what you need
656
+ - **User Rights**: Easy opt-out and data deletion
657
+
658
+ ## Debugging
659
+
660
+ Enable debug mode for detailed logging:
661
+
662
+ ```javascript
663
+ const datalyr = new Datalyr({
664
+ workspaceId: 'YOUR_WORKSPACE_ID',
665
+ debug: true
666
+ });
667
+
668
+ // Check console for detailed logs:
669
+ // [Datalyr] Event tracked: Button Clicked
670
+ // [Datalyr] Events sent successfully
671
+ ```
672
+
673
+ ## API Reference
674
+
675
+ ### Constructor Options
676
+
677
+ | Option | Type | Default | Description |
678
+ |--------|------|---------|-------------|
679
+ | `workspaceId` | `string` | *required* | Your Datalyr workspace ID |
680
+ | `endpoint` | `string` | Default API | Custom endpoint URL |
681
+ | `debug` | `boolean` | `false` | Enable debug logging |
682
+ | `batchSize` | `number` | `10` | Number of events per batch |
683
+ | `flushInterval` | `number` | `5000` | Time between flushes (ms) |
684
+ | `sessionTimeout` | `number` | `1800000` | Session timeout (ms) |
685
+ | `privacyMode` | `'standard' \| 'strict'` | `'standard'` | Privacy level |
686
+ | `respectDoNotTrack` | `boolean` | `false` | Honor browser DNT |
687
+ | `respectGlobalPrivacyControl` | `boolean` | `true` | Honor GPC |
688
+ | `cookieDomain` | `string \| 'auto'` | `'auto'` | Cookie domain |
689
+ | `trackSPA` | `boolean` | `true` | Track SPA routes |
690
+ | `trackPageViews` | `boolean` | `true` | Track page views |
691
+ | `enableContainer` | `boolean` | `true` | Enable secure container script loading |
692
+
693
+ ### Methods
694
+
695
+ | Method | Description |
696
+ |--------|-------------|
697
+ | `init()` | Initialize the SDK |
698
+ | `track(event, properties?)` | Track an event |
699
+ | `identify(userId?, traits?)` | Identify a user |
700
+ | `page(name?, properties?)` | Track a page view |
701
+ | `alias(userId)` | Create an alias |
702
+ | `reset()` | Reset identity |
703
+ | `optOut()` | Opt out of tracking |
704
+ | `optIn()` | Opt back in |
705
+ | `setConsent(config)` | Set consent preferences |
706
+ | `flush()` | Force send events |
707
+ | `getAnonymousId()` | Get anonymous ID |
708
+ | `getUserId()` | Get user ID |
709
+ | `getDistinctId()` | Get distinct ID |
710
+ | `getSessionId()` | Get session ID |
711
+ | `loadScript(scriptId)` | Manually trigger a container script |
712
+ | `getLoadedScripts()` | Get list of loaded container scripts |
713
+ | `destroy()` | Clean up resources |
714
+
715
+ ## Support
716
+
717
+ - **Documentation**: [https://docs.datalyr.com](https://docs.datalyr.com)
718
+ - **Issues**: [GitHub Issues](https://github.com/datalyr/web/issues)
719
+ - **Email**: support@datalyr.com
720
+
721
+ ## License
722
+
723
+ MIT License - see [LICENSE](LICENSE) file for details.
724
+
725
+ ---
726
+
727
+ Built with ❤️ by the Datalyr team