UNPKG

websparks-analytics-sdk

Version:

JavaScript SDK for WebSparks analytics tracking with geolocation, fingerprinting, and session management

1,891 lines (1,498 loc) β€’ 47.3 kB
# WebSparks Analytics SDK JavaScript/TypeScript SDK for tracking analytics events with comprehensive user data collection including geolocation, browser fingerprinting, IP detection, and session management. ## Features - 🎯 **Event Tracking** - Track custom events with properties - πŸ‘€ **User Identification** - Identify users and track their properties - πŸ†” **Anonymous & Identified Users** - Fingerprint-based distinct IDs for anonymous users, custom distinct IDs for identified users - πŸ“„ **Page View Tracking** - Automatic page view tracking - πŸ—ΊοΈ **Geolocation** - Browser GPS + IP-based geolocation - πŸ” **Browser Fingerprinting** - Device, browser, OS detection - 🌐 **IP Detection** - WebRTC + external services for public IP - ⏱️ **Session Management** - Persistent sessions across page refreshes - πŸ”š **Session End Tracking** - Automatic tracking when tab/browser closes - πŸ”‘ **API Key Validation** - Secure authentication with backend - πŸ“Š **Debug Mode** - Comprehensive logging for development ## Installation ```bash npm install websparks-analytics-sdk ``` ## Quick Start **JavaScript:** ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; // Initialize the SDK const analytics = new WebSparksAnalytics({ apiKey: 'your-api-key-here', projectId: 'your-project-id-here', userId: 30, // Optional debug: true, // Enable console logging trackSessionEnd: true, // Track session end on tab close trackLocation: false // Request location permission (optional) }); // ✨ session_start is automatically tracked on initialization (for new sessions) // Track events analytics.track('button_clicked', { button_name: 'donate', amount: 100 }); // Identify users analytics.identify(123, { name: 'John Doe', email: 'john@example.com' }); // Track page views analytics.page('Home Page', { section: 'landing' }); ``` **TypeScript:** ```typescript import WebSparksAnalytics, { AnalyticsConfig, EventData, UserProperties, FingerprintData, LocationData } from 'websparks-analytics-sdk'; // Typed configuration const config: AnalyticsConfig = { apiKey: 'your-api-key-here', projectId: 'your-project-id-here', userId: 30, debug: true, trackSessionEnd: true, trackLocation: false }; const analytics = new WebSparksAnalytics(config); // ✨ session_start is automatically tracked on initialization (for new sessions) // Track events with typed data const eventData: EventData = { button_name: 'donate', amount: 100 }; analytics.track('button_clicked', eventData); // Identify users with typed properties const userProps: UserProperties = { name: 'John Doe', email: 'john@example.com' }; analytics.identify(123, userProps); // Track page views analytics.page('Home Page', { section: 'landing' }); ``` --- ## Table of Contents 1. [Initialization](#initialization) 2. [Configuration Options](#configuration-options) 3. [API Methods](#api-methods) 4. [Anonymous vs Identified Users](#anonymous-vs-identified-users) 5. [Session Management](#session-management) 6. [Data Collected](#data-collected) 7. [Examples](#examples) 8. [TypeScript Support](#typescript-support) 9. [Browser Support](#browser-support) 10. [Privacy](#privacy) --- ## Initialization ### Basic Initialization **JavaScript:** ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; const analytics = new WebSparksAnalytics({ apiKey: 'your-api-key-here', projectId: 'your-project-id-here' }); ``` **TypeScript:** ```typescript import WebSparksAnalytics, { AnalyticsConfig } from 'websparks-analytics-sdk'; const config: AnalyticsConfig = { apiKey: 'your-api-key-here', projectId: 'your-project-id-here' }; const analytics = new WebSparksAnalytics(config); ``` ### Full Initialization with All Options **JavaScript:** ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; const analytics = new WebSparksAnalytics({ apiKey: 'EBvk5C...............', // Required: Your API key projectId: 'websparks-....-...-fui893j', // Required: Your project ID userId: 30, // Optional: User ID (can be set later) debug: true, // Optional: Enable debug logs (default: false) trackSessionEnd: true, // Optional: Auto-track session end (default: true) trackLocation: false // Optional: Request GPS location (default: false) }); ``` **TypeScript:** ```typescript import WebSparksAnalytics, { AnalyticsConfig } from 'websparks-analytics-sdk'; const config: AnalyticsConfig = { apiKey: 'EBvk5C...............', // Required: Your API key projectId: 'websparks-....-...-fui893j', // Required: Your project ID userId: 30, // Optional: User ID (can be set later) debug: true, // Optional: Enable debug logs (default: false) trackSessionEnd: true, // Optional: Auto-track session end (default: true) trackLocation: false // Optional: Request GPS location (default: false) }; const analytics = new WebSparksAnalytics(config); ``` ### What Happens During Initialization? 1. **API Key Validation** - Validates your API key with the backend 2. **Session Creation/Restoration** - Creates new session or restores existing from localStorage 3. **Fingerprint Generation** - Generates browser fingerprint automatically 4. **IP Detection** - Detects client IP address (both local and public) 5. **Location Detection** - Requests GPS location if `trackLocation: true` 6. **✨ Automatic Session Start** - Automatically calls `session('start')` for **new sessions only** - If session exists in localStorage (page refresh), session is restored without new `session_start` - If no session exists, a new session is created and `session_start` is tracked 7. **Session End Listener** - Sets up automatic `session_end` tracking on tab close --- ## Configuration Options | Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | `apiKey` | `string` | βœ… Yes | - | Your API key from WebSparks backend | | `projectId` | `string` | βœ… Yes | - | Your project ID from WebSparks | | `userId` | `number` | ❌ No | `null` | User ID to associate with events | | `debug` | `boolean` | ❌ No | `false` | Enable detailed console logging | | `trackSessionEnd` | `boolean` | ❌ No | `true` | Automatically track when user closes tab/browser | | `trackLocation` | `boolean` | ❌ No | `false` | Request GPS location permission on init | ### Configuration Examples #### Production Setup (Minimal) ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; const analytics = new WebSparksAnalytics({ apiKey: 'prod-api-key', projectId: 'prod-project-id' }); ``` #### Development Setup (Full Debugging) ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; const analytics = new WebSparksAnalytics({ apiKey: 'dev-api-key', projectId: 'dev-project-id', debug: true, trackLocation: true }); ``` #### With User Already Logged In ```javascript import WebSparksAnalytics from 'websparks-analytics-sdk'; const analytics = new WebSparksAnalytics({ apiKey: 'your-api-key', projectId: 'your-project-id', userId: getCurrentUserId() // Get from your auth system }); ``` --- ## API Methods ### 1. `track(eventName, eventData?)` Track a custom event with optional properties. **Parameters:** - `eventName` (string, required): Name of the event - `eventData` (object, optional): Event properties/data **Returns:** `Promise<void>` **Examples:** ```javascript // Simple event analytics.track('button_clicked'); // Event with data analytics.track('product_viewed', { product_id: 'SKU-12345', product_name: 'Winter Jacket', price: 99.99, category: 'Clothing' }); // Async/await usage await analytics.track('purchase_completed', { order_id: 'ORD-789', total_amount: 299.99, items_count: 3 }); // Promise usage analytics.track('video_played', { video_id: 'VID-123', duration: 180 }) .then(() => console.log('Event tracked')) .catch(err => console.error('Tracking failed:', err)); ``` **Automatic Data Included:** - `timestamp`: ISO timestamp when event occurred - `sessionId`: Current session ID - `userId`: User ID (if identified) - `fingerprint`: Browser fingerprint - `location`: GPS coordinates (if available) - `clientIp`: User's IP address --- ### 2. `identify(userId, userProperties?)` Identify a user and optionally set their properties. Transitions user from anonymous to identified. **Parameters:** - `userId` (number, required): Unique user identifier - `userProperties` (object, optional): User properties to store - `distinctId` (string, optional): Custom distinct ID from your backend **Returns:** `Promise<void>` **Examples:** ```javascript // Basic identification analytics.identify(123); // With user properties analytics.identify(456, { name: 'Jane Smith', email: 'jane@example.com', plan: 'premium', signup_date: '2025-01-15' }); // With custom distinct ID from backend (NEW in v1.4.0) analytics.identify(456, { name: 'Jane Smith', email: 'jane@example.com', distinctId: 'user-uuid-abc123-from-backend' // Your custom distinct_id }); // β†’ distinct_id changes from "anon-{fingerprint-hash}" to "user-uuid-abc123-from-backend" // Update user properties later analytics.identify(456, { last_login: new Date().toISOString(), login_count: 42 }); // On user login async function handleLogin(user) { await analytics.identify(user.id, { name: user.name, email: user.email, role: user.role, distinctId: user.distinct_id // Optional: from your backend }); } ``` **Important Notes:** - Once identified, `userId` persists in session storage - All subsequent events include this `userId` - **Distinct ID Transition:** Anonymous users get fingerprint-based distinct_id, identified users can use custom distinct_id - Use `reset()` to clear user identification --- ### 3. `page(pageName?, pageProperties?)` Track a page view. **Parameters:** - `pageName` (string, optional): Name of the page (defaults to `document.title`) - `pageProperties` (object, optional): Page-specific properties **Returns:** `Promise<void>` **Examples:** ```javascript // Simple page view (uses document.title) analytics.page(); // Named page view analytics.page('Home Page'); // With properties analytics.page('Product Page', { category: 'electronics', product_id: 'SKU-12345', referrer: document.referrer }); // In React Router function ProductPage({ productId }) { useEffect(() => { analytics.page('Product Detail', { product_id: productId, section: 'catalog' }); }, [productId]); } // In Vue Router router.afterEach((to, from) => { analytics.page(to.name, { path: to.path, previous_page: from.name }); }); ``` **Automatic Data Included:** - `url`: Full current URL - `path`: URL pathname - `timestamp`: ISO timestamp - `sessionId`: Current session ID - `userId`: User ID (if identified) --- ### 4. `reset()` Clear current user identification and start a new session. **Parameters:** None **Returns:** `void` **Examples:** ```javascript // On user logout function handleLogout() { analytics.reset(); // Clears userId and starts new session // Your logout logic... } // Clear and restart analytics.reset(); // The reset method: // 1. Clears userId // 2. Clears session from localStorage // 3. Generates new sessionId // 4. Tracks new session_start event ``` **What Gets Reset:** - User ID β†’ `null` - Session ID β†’ New ID generated - Session start time β†’ Reset to now - localStorage session data β†’ Cleared **What Stays the Same:** - Browser fingerprint (device-based) - IP address - Location data (if already collected) --- ### 5. `endSession(eventData?)` Manually end the current session. **Parameters:** - `eventData` (object, optional): Additional data to include with session_end event **Returns:** `Promise<void>` **Examples:** ```javascript // Simple session end analytics.endSession(); // With custom data analytics.endSession({ reason: 'user_logout', logout_method: 'button_click' }); // On user logout async function handleLogout() { await analytics.endSession({ reason: 'logout' }); // Then logout user... } // On inactivity timeout let inactivityTimer; function resetInactivityTimer() { clearTimeout(inactivityTimer); inactivityTimer = setTimeout(() => { analytics.endSession({ reason: 'inactivity_timeout', timeout_duration: 1800000 // 30 minutes in ms }); }, 1800000); } // On navigation away router.beforeEach((to, from, next) => { if (to.path === '/goodbye') { analytics.endSession({ reason: 'navigation', destination: to.path }); } next(); }); ``` **Automatic Data Included:** - `sessionDuration`: Total session time in milliseconds - `sessionDurationMinutes`: Duration in minutes (rounded) - `sessionDurationSeconds`: Duration in seconds (rounded) - `sessionId`: The session being ended - `timestamp`: When session ended --- ### 6. `sessionEnd(eventData?)` Alias for `endSession()`. Works exactly the same. **Parameters:** - `eventData` (object, optional): Additional data to include **Returns:** `Promise<void>` **Examples:** ```javascript // Same as endSession() analytics.sessionEnd(); // With data analytics.sessionEnd({ reason: 'user_action' }); ``` --- ### 7. `session(eventType, eventData?)` Dedicated method for tracking session events with `'session'` event_type (separate from general tracking). **Parameters:** - `eventType` (string, required): Either `'start'` or `'end'` - `eventData` (object, optional): Additional event data **Returns:** `Promise<void>` **Examples:** ```javascript // NOTE: session('start') is automatically called when SDK initializes // You typically don't need to call it manually // Track session end manually analytics.session('end', { reason: 'user_logout', duration_visible: 1200 }); // Session end automatically includes duration analytics.session('end', { reason: 'timeout' }); // Automatically adds: // - sessionDuration (ms) // - sessionDurationMinutes // - sessionDurationSeconds // Manual session start (only for custom flows) analytics.session('start', { source: 'homepage', campaign: 'winter_2025' }); // On user logout async function handleLogout() { await analytics.session('end', { reason: 'user_logout', logout_method: 'button_click' }); analytics.reset(); // This also triggers a new session_start } ``` **Important Notes:** - **Session start is automatic** - Called automatically on SDK initialization for new sessions - Uses `event_type: 'session'` (not `'track'`) - Session end automatically calculates duration - Typically used internally by SDK, but available for custom session flows - All `endSession()` and automatic session tracking use this method - When you call `reset()`, it automatically triggers a new `session('start')` --- ### 8. `requestLocation()` Manually request user's GPS location. **Parameters:** None **Returns:** `Promise<LocationData>` **LocationData Type:** ```typescript interface LocationData { latitude: number; longitude: number; accuracy: number; // in meters } ``` **Examples:** ```javascript // Request location analytics.requestLocation() .then(location => { console.log('Latitude:', location.latitude); console.log('Longitude:', location.longitude); console.log('Accuracy:', location.accuracy, 'meters'); }) .catch(error => { console.error('Location denied:', error); }); // Async/await async function getLocation() { try { const location = await analytics.requestLocation(); console.log('User location:', location); } catch (error) { console.log('User denied location permission'); } } // Request on button click document.getElementById('shareLocation').addEventListener('click', async () => { try { const location = await analytics.requestLocation(); analytics.track('location_shared', { lat: location.latitude, lng: location.longitude }); } catch (error) { analytics.track('location_denied'); } }); ``` **Important Notes:** - Requires user permission - Browser will show permission prompt - If already granted, returns cached location - Works even if `trackLocation: false` in config --- ## Anonymous vs Identified Users The SDK automatically tracks both anonymous and identified users with persistent distinct IDs. ### How It Works **Anonymous Users** (Before signup/login): - Get a fingerprint-based `distinct_id` automatically - Format: `anon-{fingerprint-hash}-{timestamp}` - Based on device/browser characteristics - Persists across sessions via localStorage **Identified Users** (After signup/login): - Can use custom `distinct_id` from your backend - Or keep the fingerprint-based one - User transitions tracked with `previous_distinct_id` ### User Journey Example ```javascript // 1. User arrives anonymously const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project' }); // β†’ distinct_id: "anon-abc123def-xyz789" // β†’ user_type: "anonymous" // β†’ is_anonymous: true // User browses (all events include anonymous distinct_id) analytics.track('product_viewed', { product_id: 'SKU-123' }); // Event includes: // - distinct_id: "anon-abc123def-xyz789" // - user_id: null // - user_type: "anonymous" // 2. User signs up / logs in analytics.identify(12345, { email: 'user@example.com', name: 'John Doe', distinctId: 'user-uuid-from-backend-12345' // Optional: Your custom distinct_id }); // β†’ distinct_id: "user-uuid-from-backend-12345" (transitioned) // β†’ user_id: 12345 // β†’ user_type: "identified" // β†’ is_identified: true // β†’ previous_distinct_id: "anon-abc123def-xyz789" (for tracking transition) // User continues browsing (all events now include identified data) analytics.track('purchase_completed', { order_id: 'ORD-789', amount: 99.99 }); // Event includes: // - distinct_id: "user-uuid-from-backend-12345" // - user_id: 12345 // - user_type: "identified" ``` ### Distinct ID Options #### Option 1: Use Custom Distinct ID from Backend (Recommended) ```javascript // On signup/login, provide your own distinct_id analytics.identify(12345, { email: 'user@example.com', name: 'John Doe', distinctId: 'user-uuid-abc123-from-backend' // Your custom distinct_id }); // β†’ distinct_id: "user-uuid-abc123-from-backend" ``` **Use Case:** When you have your own user identification system with UUIDs or distinct IDs in your database. #### Option 2: Keep Fingerprint-Based Distinct ID ```javascript // Don't provide distinctId - keeps the fingerprint-based one analytics.identify(12345, { email: 'user@example.com', name: 'John Doe' }); // β†’ distinct_id: "anon-abc123def-xyz789" (stays the same) ``` **Use Case:** When you want consistent tracking across anonymous and identified states without managing distinct IDs. ### Automatic Data Included in All Events Every event automatically includes these user identification fields: ```javascript { distinct_id: "user-uuid-from-backend" or "anon-{hash}", user_id: 12345 or null, user_id_component: 12345 or "anonymous", user_type: "identified" or "anonymous", is_anonymous: false or true, is_identified: true or false } ``` ### Tracking Anonymous to Identified Transition When a user transitions from anonymous to identified, the identify event includes: ```javascript { distinct_id: "user-uuid-from-backend-12345", // New distinct_id user_id: 12345, user_type: "identified", previous_distinct_id: "anon-abc123def-xyz789" // Previous anonymous distinct_id } ``` This allows you to link anonymous activity to the identified user in your analytics. ### Full Example: E-commerce User Journey ```javascript // Initialize SDK const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project' }); // 1. Anonymous user browses products analytics.track('product_viewed', { product_id: 'PRODUCT-123', category: 'Electronics' }); // distinct_id: "anon-abc123-xyz" // user_type: "anonymous" analytics.track('add_to_cart', { product_id: 'PRODUCT-123', price: 99.99 }); // distinct_id: "anon-abc123-xyz" // user_type: "anonymous" // 2. User creates account / logs in async function handleSignup(user) { await analytics.identify(user.id, { email: user.email, name: user.name, distinctId: user.distinct_id // From your backend }); analytics.track('user_signed_up', { signup_method: 'email', referral_source: 'google' }); } // β†’ User transitions to identified // β†’ distinct_id: "user-uuid-from-backend" // β†’ previous_distinct_id: "anon-abc123-xyz" // 3. Identified user completes purchase analytics.track('purchase_completed', { order_id: 'ORD-789', total: 99.99, items: 1 }); // distinct_id: "user-uuid-from-backend" // user_id: 12345 // user_type: "identified" // 4. User logs out analytics.reset(); // β†’ Clears user_id // β†’ Creates new anonymous distinct_id // β†’ New session starts ``` ### Benefits βœ… **Track anonymous users across sessions** - Using fingerprint-based distinct_id βœ… **Link anonymous activity to identified users** - Via previous_distinct_id field βœ… **Use your own distinct IDs** - Optionally provide custom distinct_id from backend βœ… **Consistent tracking** - Works seamlessly across anonymous and identified states βœ… **No data loss** - All events tracked from first visit to conversion --- ## Session Management ### What is a Session? A **session** represents a single visit to your website/app. It includes: - Unique `sessionId` - Session start time - User ID (if identified) - All events during that visit ### Session Lifecycle ``` 1. User opens page ↓ 2. SDK initializes ↓ 3. Check localStorage for existing session ↓ β”œβ”€β†’ Session found β†’ Restore session (same sessionId) β”‚ └─→ No session_start event (continuing session) β”‚ └─→ No session found β†’ Create new session └─→ Generate new sessionId └─→ Track session_start event └─→ Save to localStorage ↓ 4. User interacts (events tracked with sessionId) ↓ 5. User closes tab/browser ↓ 6. Track session_end event └─→ Clear localStorage ``` ### Session Persistence Sessions persist across: - βœ… Page refreshes - βœ… Navigation within site - βœ… Browser back/forward - βœ… Tab switching - βœ… Browser minimize Sessions end when: - ❌ Tab is closed - ❌ Browser is closed - ❌ `analytics.reset()` is called - ❌ `analytics.endSession()` is called - ❌ localStorage is cleared ### Session Storage Session data is stored in `localStorage` with key: ``` websparks_analytics_session ``` Stored data: ```javascript { sessionId: "1704123456789-abc123def", startTime: 1704123456789, userId: 30 // if identified } ``` ### Session Start **✨ Automatic Tracking (Recommended):** ```javascript // When SDK initializes - session_start is AUTOMATICALLY tracked const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project' }); // β†’ Automatically calls: session('start') for NEW sessions // β†’ On page refresh: Restores existing session (NO new session_start) ``` **How it works:** - **First visit / New tab**: New session created β†’ `session('start')` automatically tracked - **Page refresh / Navigation**: Existing session restored β†’ No new `session_start` - **After `reset()`**: New session created β†’ `session('start')` automatically tracked **Manual Tracking (Rare):** ```javascript // Only for custom session management flows analytics.session('start', { custom_property: 'value' }); ``` ### Session End **Automatic Tracking** (Default): ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackSessionEnd: true // default }); // Now when user closes tab/browser: // β†’ Automatically tracks: session_end // β†’ Includes: sessionDuration, sessionId, etc. ``` **Manual Tracking:** ```javascript // Method 1: Using endSession() analytics.endSession({ reason: 'logout' }); // Method 2: Using sessionEnd() alias analytics.sessionEnd({ reason: 'logout' }); // Method 3: Using track() analytics.track('session_end', { reason: 'manual', custom_data: 'value' }); ``` ### Session End Detection The SDK automatically detects tab/browser close using: 1. **`beforeunload` event** - Fires when tab/browser closing 2. **`pagehide` event** - More reliable on mobile (iOS Safari) 3. **`freeze` event** - Safari iOS when page is frozen **Implementation:** ```javascript // Automatic - just enable it const analytics = new WebSparksAnalytics({ trackSessionEnd: true // Listens for tab/browser close }); // When user closes tab: // β†’ session_end event sent via navigator.sendBeacon // β†’ Session cleared from localStorage // β†’ sessionId included in event ``` ### Session ID Every session has a unique ID: ```javascript // Format: timestamp-randomstring // Example: "1704123456789-xyz789abc" ``` **Accessing Session ID:** ```javascript // Session ID is private, but included in all events analytics.track('my_event', { // Custom properties }); // β†’ Event payload includes: sessionId automatically ``` ### Session Duration Session duration is calculated on `session_end`: ```javascript analytics.endSession(); // Sends: { sessionDuration: 300000, // 300,000ms = 5 minutes sessionDurationMinutes: 5, // 5 minutes sessionDurationSeconds: 300 // 300 seconds } ``` ### Session Examples **Example 1: Normal Session Flow** ```javascript // Page load (first visit) const analytics = new WebSparksAnalytics({ ... }); // β†’ ✨ Automatically calls: session('start') // β†’ session_start tracked (sessionId: "1234-abc") // User clicks button analytics.track('button_clicked'); // β†’ Includes sessionId: "1234-abc" // User refreshes page // β†’ SDK restores session "1234-abc" from localStorage // β†’ ✨ No new session_start (session continues) // User closes tab // β†’ session_end (sessionId: "1234-abc", duration: 180s) ``` **Example 2: Multi-Tab Session** ```javascript // Tab 1: User opens page const analytics1 = new WebSparksAnalytics({ ... }); // β†’ ✨ Automatically calls: session('start') // β†’ session_start (sessionId: "1234-abc") // Tab 2: User opens same site in new tab const analytics2 = new WebSparksAnalytics({ ... }); // β†’ ✨ Automatically calls: session('start') // β†’ session_start (sessionId: "5678-def") - NEW session (different tab = different session) // User closes Tab 1 // β†’ session_end (sessionId: "1234-abc") // Tab 2 still running // β†’ sessionId: "5678-def" continues ``` **Example 3: User Login Mid-Session** ```javascript // User arrives (anonymous) const analytics = new WebSparksAnalytics({ ... }); // β†’ ✨ Automatically calls: session('start') // β†’ session_start (sessionId: "1234-abc", userId: null) // User logs in analytics.identify(789, { name: 'John Doe' }); // β†’ Now all events include userId: 789 // User clicks analytics.track('button_clicked'); // β†’ sessionId: "1234-abc", userId: 789 // User logs out analytics.reset(); // β†’ session_end (old session) // β†’ ✨ Automatically calls: session('start') // β†’ session_start (new session, userId: null) ``` **Example 4: Session Timeout** ```javascript // Implement custom timeout let inactivityTimer; const SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes function resetTimer() { clearTimeout(inactivityTimer); inactivityTimer = setTimeout(() => { analytics.endSession({ reason: 'inactivity_timeout', timeout_duration: SESSION_TIMEOUT }); // Optionally start new session analytics.reset(); }, SESSION_TIMEOUT); } // Reset timer on user activity window.addEventListener('mousemove', resetTimer); window.addEventListener('keypress', resetTimer); window.addEventListener('click', resetTimer); window.addEventListener('scroll', resetTimer); // Start timer on init resetTimer(); ``` ### Disable Session End Tracking ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackSessionEnd: false // Disable automatic tracking }); // Now session_end won't fire automatically // You must call it manually: analytics.endSession(); ``` --- ## Data Collected ### Automatic Data Collection Every event automatically includes: #### 1. Event Metadata ```javascript { event_type: 'track', // 'track', 'identify', 'page', or 'session' event_name: 'button_clicked', // Your event name timestamp: '2025-10-10T...', // ISO timestamp sessionId: '1234-abc', // Current session ID userId: 123 // User ID (if identified) } ``` #### 2. Browser Fingerprint ```javascript { fingerprint: { userAgent: 'Mozilla/5.0...', browserName: 'Chrome', browserVersion: '120.0.6099.109', osName: 'Windows 10/11', deviceType: 'Desktop', platform: 'Win32', language: 'en-US', languages: ['en-US', 'en'], screenResolution: '1920x1080', screenColorDepth: 24, timezone: 'Asia/Dhaka', timezoneOffset: -360, deviceMemory: 8, // GB hardwareConcurrency: 8, // CPU cores cookieEnabled: true, doNotTrack: null, vendor: 'Google Inc.' } } ``` #### 3. Location Data (if available) ```javascript { location: { latitude: 23.8103, longitude: 90.4125, accuracy: 50 // meters } } ``` #### 4. Network Data ```javascript { clientIp: '103.45.67.89' // Public IP address } ``` #### 5. Page Data (for page views) ```javascript { url: 'https://example.com/products/123', path: '/products/123', name: 'Product Page' } ``` ### Data Privacy All data collection is transparent and includes: - **No PII by default** - Unless you explicitly pass it - **Browser fingerprinting** - For fraud detection - **IP addresses** - For geolocation and analytics - **GPS location** - Only if `trackLocation: true` and user grants permission --- ## Examples ### E-Commerce Tracking ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'ecommerce-key', projectId: 'ecommerce-project' }); // Product viewed analytics.track('product_viewed', { product_id: 'SKU-12345', product_name: 'Winter Jacket', category: 'Clothing', price: 99.99, currency: 'BDT' }); // Add to cart analytics.track('add_to_cart', { product_id: 'SKU-12345', quantity: 2, price: 99.99, cart_total: 199.98 }); // Checkout started analytics.track('checkout_started', { cart_total: 199.98, items_count: 2, shipping_method: 'express' }); // Purchase completed analytics.track('purchase_completed', { order_id: 'ORD-789', total_amount: 299.99, items_count: 2, payment_method: 'credit_card', shipping_address: 'Dhaka, Bangladesh' }); ``` ### Donation Platform Tracking ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'donation-key', projectId: 'donation-project' }); // Donation started analytics.track('donation_started', { amount: 1000, currency: 'BDT', campaign: 'winter_shelter', recurring: false }); // Payment method selected analytics.track('payment_method_selected', { method: 'bkash', amount: 1000 }); // Donation completed analytics.track('donation_completed', { donation_id: 'DON-456', amount: 1000, currency: 'BDT', campaign: 'winter_shelter', payment_method: 'bkash', transaction_id: 'TXN-789' }); // Thank you page viewed analytics.page('Thank You', { donation_id: 'DON-456', amount: 1000 }); ``` ### SaaS Application Tracking ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'saas-key', projectId: 'saas-project' }); // User signup analytics.identify(789, { email: 'user@example.com', plan: 'free', signup_date: new Date().toISOString() }); // Feature used analytics.track('feature_used', { feature_name: 'export_pdf', usage_count: 5 }); // Upgrade initiated analytics.track('upgrade_initiated', { from_plan: 'free', to_plan: 'premium', billing_cycle: 'monthly' }); // Subscription upgraded analytics.identify(789, { plan: 'premium', billing_cycle: 'monthly', mrr: 19.99 }); analytics.track('subscription_upgraded', { from_plan: 'free', to_plan: 'premium', payment_method: 'stripe' }); ``` ### React Application ```javascript import { useEffect } from 'react'; import WebSparksAnalytics from '@websparks/analytics-sdk'; // Initialize once const analytics = new WebSparksAnalytics({ apiKey: process.env.REACT_APP_ANALYTICS_KEY, projectId: process.env.REACT_APP_PROJECT_ID, debug: process.env.NODE_ENV === 'development' }); // Track page views function ProductPage({ productId }) { useEffect(() => { analytics.page('Product Detail', { product_id: productId }); }, [productId]); const handleAddToCart = () => { analytics.track('add_to_cart', { product_id: productId, source: 'product_page' }); }; return ( <div> <button onClick={handleAddToCart}>Add to Cart</button> </div> ); } // Track user login function LoginPage() { const handleLogin = async (user) => { await analytics.identify(user.id, { email: user.email, name: user.name }); analytics.track('user_logged_in', { method: 'email_password' }); }; return <LoginForm onSuccess={handleLogin} />; } // Track user logout function LogoutButton() { const handleLogout = async () => { await analytics.endSession({ reason: 'user_logout' }); analytics.reset(); // Your logout logic... }; return <button onClick={handleLogout}>Logout</button>; } ``` ### Vue Application ```javascript import WebSparksAnalytics from '@websparks/analytics-sdk'; // main.js const analytics = new WebSparksAnalytics({ apiKey: import.meta.env.VITE_ANALYTICS_KEY, projectId: import.meta.env.VITE_PROJECT_ID }); // Make available globally app.config.globalProperties.$analytics = analytics; // Router tracking router.afterEach((to, from) => { analytics.page(to.name, { path: to.path, previous_page: from.name }); }); // Component usage export default { methods: { trackButtonClick() { this.$analytics.track('button_clicked', { button_name: 'subscribe', page: this.$route.name }); } } }; ``` ### Next.js Application ```javascript // lib/analytics.js import WebSparksAnalytics from '@websparks/analytics-sdk'; export const analytics = new WebSparksAnalytics({ apiKey: process.env.NEXT_PUBLIC_ANALYTICS_KEY, projectId: process.env.NEXT_PUBLIC_PROJECT_ID }); // pages/_app.js import { useEffect } from 'react'; import { useRouter } from 'next/router'; import { analytics } from '../lib/analytics'; function MyApp({ Component, pageProps }) { const router = useRouter(); useEffect(() => { const handleRouteChange = (url) => { analytics.page(url); }; router.events.on('routeChangeComplete', handleRouteChange); return () => { router.events.off('routeChangeComplete', handleRouteChange); }; }, [router.events]); return <Component {...pageProps} />; } // pages/product/[id].js import { analytics } from '../../lib/analytics'; export default function Product({ product }) { useEffect(() => { analytics.track('product_viewed', { product_id: product.id, product_name: product.name }); }, [product]); return <div>{product.name}</div>; } ``` --- ## TypeScript Support The SDK is written in TypeScript and includes full type definitions. ### Import Types ```typescript import WebSparksAnalytics, { AnalyticsConfig, EventData, UserProperties, FingerprintData, LocationData } from 'websparks-analytics-sdk'; ``` ### Type Definitions ```typescript interface AnalyticsConfig { apiKey: string; projectId: string; userId?: number; debug?: boolean; trackSessionEnd?: boolean; trackLocation?: boolean; } interface EventData { [key: string]: any; } interface UserProperties { [key: string]: any; } interface FingerprintData { userAgent: string; language: string; languages: string[]; platform: string; screenResolution: string; screenColorDepth: number; timezone: string; timezoneOffset: number; deviceMemory?: number; hardwareConcurrency?: number; cookieEnabled: boolean; doNotTrack: string | null; vendor: string; browserName: string; browserVersion: string; osName: string; deviceType: string; } interface LocationData { latitude: number; longitude: number; accuracy: number; } ``` ### Usage with TypeScript ```typescript // Typed configuration const config: AnalyticsConfig = { apiKey: 'your-api-key', projectId: 'your-project-id', userId: 30, debug: true }; const analytics = new WebSparksAnalytics(config); // Typed event data const eventData: EventData = { product_id: 'SKU-12345', price: 99.99 }; analytics.track('product_viewed', eventData); // Typed user properties const userProps: UserProperties = { name: 'John Doe', email: 'john@example.com', plan: 'premium' }; analytics.identify(123, userProps); // Location with type analytics.requestLocation() .then((location: LocationData) => { console.log(location.latitude, location.longitude); }); ``` --- ## Browser Support ### Supported Browsers - βœ… Chrome/Edge (latest 2 versions) - βœ… Firefox (latest 2 versions) - βœ… Safari (latest 2 versions) - βœ… Opera (latest 2 versions) - βœ… iOS Safari (latest 2 versions) - βœ… Chrome Mobile (latest 2 versions) ### Browser Features Used - **localStorage** - For session persistence - **navigator.sendBeacon** - For reliable session_end tracking - **Geolocation API** - For GPS location (optional) - **WebRTC** - For local IP detection - **Fetch API** - For API requests ### Fallbacks - If `sendBeacon` unavailable β†’ Falls back to synchronous XHR - If `localStorage` unavailable β†’ Session won't persist across refreshes - If `Geolocation` unavailable β†’ Location features disabled --- ## Debug Mode ### Enable Debug Mode ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', debug: true // Enable detailed logging }); ``` ### Console Output When debug mode is enabled, you'll see: ``` βœ“ API Key is valid [Websparks Analytics] New session started: 1704123456789-abc123 [Websparks Analytics] Public IP: 103.45.67.89 [Websparks Analytics] Event sent successfully [Websparks Analytics] Sending session_end event for session: 1704123456789-abc123 [Websparks Analytics] sendBeacon result: true ``` ### Debug Information Includes: - βœ… API key validation results - βœ… Session creation/restoration - βœ… IP address detection (WebRTC + external) - βœ… Geolocation requests/results - βœ… All event tracking - βœ… Session end tracking - βœ… Error messages ### Production vs Development ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', debug: process.env.NODE_ENV === 'development' // Only in dev }); ``` --- ## Privacy & GDPR Compliance ### Data Collection The SDK collects: - βœ… Browser fingerprint (for fraud detection) - βœ… IP address (for geolocation) - βœ… GPS location (only if `trackLocation: true` and user consents) - βœ… Page views and custom events - βœ… Session data ### User Consent ```javascript // Wait for consent before initializing let analytics; function handleConsentGranted() { analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackLocation: false // Don't request GPS by default }); } // Show consent banner showConsentBanner({ onAccept: handleConsentGranted }); ``` ### Disable Location Tracking ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackLocation: false // Never request GPS permission }); ``` ### Privacy Best Practices 1. βœ… Have a clear privacy policy 2. βœ… Get user consent where required (GDPR, CCPA) 3. βœ… Set `trackLocation: false` unless GPS is needed 4. βœ… Don't send PII in event properties 5. βœ… Anonymize user data when possible --- ## API Key Setup ### Get Your API Key 1. Login to WebSparks backend admin panel 2. Navigate to Projects 3. Create or select a project 4. Copy your API key and project ID ### Use in SDK ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'EBvk5C...............', // From backend projectId: 'websparks-....-...-fui893j' // From backend }); ``` ### API Key Validation The SDK automatically validates your API key on initialization: ```javascript // Valid key βœ“ API Key is valid // Invalid key βœ— API Key is invalid Message: Invalid or inactive API key ``` ### Security - βœ… API keys are validated on every initialization - βœ… Invalid keys prevent all tracking - βœ… Keys are sent securely via HTTPS - ⚠️ Don't commit API keys to public repositories ```javascript // Use environment variables const analytics = new WebSparksAnalytics({ apiKey: process.env.WEBSPARKS_API_KEY, projectId: process.env.WEBSPARKS_PROJECT_ID }); ``` --- ## Development ### Install Dependencies ```bash npm install ``` ### Build the SDK ```bash npm run build ``` ### Run Tests ```bash npm test ``` ### Start Dev Server ```bash npm run dev ``` --- ## Troubleshooting ### Session End Not Firing **Problem:** `session_end` event not being tracked **Solutions:** 1. Ensure `trackSessionEnd: true` in config 2. Enable `debug: true` to see console logs 3. Check browser console for errors 4. Test by actually closing tab (not just switching tabs) ```javascript const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackSessionEnd: true, // Make sure this is true debug: true // See what's happening }); ``` ### Events Not Being Tracked **Problem:** Events not showing in backend **Solutions:** 1. Check API key is valid 2. Check network tab for failed requests 3. Enable debug mode 4. Verify project ID is correct ### Location Not Working **Problem:** GPS location not being collected **Solutions:** 1. Set `trackLocation: true` in config 2. User must grant permission 3. HTTPS required (not HTTP) 4. Check browser console for permission errors ```javascript // Correct setup const analytics = new WebSparksAnalytics({ apiKey: 'your-key', projectId: 'your-project', trackLocation: true // Enable location }); // Or request manually analytics.requestLocation() .then(location => console.log('Got location:', location)) .catch(err => console.log('Permission denied:', err)); ``` --- ## Support - 🌐 **Website:** [https://websparks.ai](https://websparks.ai) - πŸ“š **Documentation:** [https://docs.websparks.ai](https://docs.websparks.ai) - πŸ“§ **Email:** support@websparks.ai - πŸ’¬ **Discord:** [Join our community](https://discord.gg/websparks) --- ## License MIT License - See LICENSE file for details --- ## Changelog ### Version 1.4.0 (2025-10-11) - ✨ **Anonymous vs Identified User Tracking** - Automatic tracking of anonymous and identified users - ✨ **Fingerprint-Based Distinct IDs** - Anonymous users get distinct_id based on device fingerprint - ✨ **Custom Distinct IDs** - Support for custom distinct_id from backend via `identify()` method - ✨ **User Transition Tracking** - Track when users transition from anonymous to identified - ✨ **User Type Classification** - All events include `user_type`, `is_anonymous`, `is_identified` - ✨ **Previous Distinct ID** - Identify events include `previous_distinct_id` for linking - πŸ“ Added comprehensive "Anonymous vs Identified Users" section to README - πŸ”§ Enhanced `identify()` method to accept `distinctId` parameter - πŸ”§ Updated `getUserIdentificationData()` to use custom distinct IDs ### Version 1.2.0 (2025-10-10) - ✨ Added dedicated `session()` method for session tracking - ✨ New `event_type: 'session'` for session events (separate from `'track'`) - ✨ Session events now use dedicated event type instead of track - ✨ Improved session tracking architecture - πŸ“ Updated README with `session()` method documentation - πŸ”§ Refactored all session tracking to use `session()` internally ### Version 1.1.0 (2025-10-09) - ✨ Enhanced session end tracking with multiple event listeners - ✨ Added `sessionEnd()` alias for `endSession()` - ✨ Improved mobile browser support (iOS Safari) - ✨ Added `endReason` to session_end events - ✨ Better duplicate prevention for session_end - πŸ› Fixed session_end not firing on tab switch - πŸ› Fixed pagehide event for back/forward cache - πŸ“ Comprehensive README documentation ### Version 1.0.0 (2025-10-01) - πŸŽ‰ Initial release - ✨ Event tracking (track, identify, page) - ✨ Browser fingerprinting - ✨ IP detection (WebRTC + external services) - ✨ Geolocation (GPS + IP-based) - ✨ Session management with localStorage - ✨ API key validation - ✨ Debug mode with comprehensive logging --- ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. --- **Made with ❀️ by WebSparks Team**