websparks-analytics-sdk
v1.5.0
Published
JavaScript SDK for WebSparks analytics tracking with geolocation, fingerprinting, and session management
Downloads
25
Maintainers
Readme
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
npm install websparks-analytics-sdkQuick Start
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: '[email protected]'
});
// Track page views
analytics.page('Home Page', {
section: 'landing'
});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: '[email protected]'
};
analytics.identify(123, userProps);
// Track page views
analytics.page('Home Page', { section: 'landing' });Table of Contents
- Initialization
- Configuration Options
- API Methods
- Anonymous vs Identified Users
- Session Management
- Data Collected
- Examples
- TypeScript Support
- Browser Support
- Privacy
Initialization
Basic Initialization
JavaScript:
import WebSparksAnalytics from 'websparks-analytics-sdk';
const analytics = new WebSparksAnalytics({
apiKey: 'your-api-key-here',
projectId: 'your-project-id-here'
});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:
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:
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?
- API Key Validation - Validates your API key with the backend
- Session Creation/Restoration - Creates new session or restores existing from localStorage
- Fingerprint Generation - Generates browser fingerprint automatically
- IP Detection - Detects client IP address (both local and public)
- Location Detection - Requests GPS location if
trackLocation: true - ✨ 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_startis tracked
- If session exists in localStorage (page refresh), session is restored without new
- Session End Listener - Sets up automatic
session_endtracking 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)
import WebSparksAnalytics from 'websparks-analytics-sdk';
const analytics = new WebSparksAnalytics({
apiKey: 'prod-api-key',
projectId: 'prod-project-id'
});Development Setup (Full Debugging)
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
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 eventeventData(object, optional): Event properties/data
Returns: Promise<void>
Examples:
// 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 occurredsessionId: Current session IDuserId: User ID (if identified)fingerprint: Browser fingerprintlocation: 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 identifieruserProperties(object, optional): User properties to storedistinctId(string, optional): Custom distinct ID from your backend
Returns: Promise<void>
Examples:
// Basic identification
analytics.identify(123);
// With user properties
analytics.identify(456, {
name: 'Jane Smith',
email: '[email protected]',
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: '[email protected]',
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,
userIdpersists 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 todocument.title)pageProperties(object, optional): Page-specific properties
Returns: Promise<void>
Examples:
// 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 URLpath: URL pathnametimestamp: ISO timestampsessionId: Current session IDuserId: User ID (if identified)
4. reset()
Clear current user identification and start a new session.
Parameters: None
Returns: void
Examples:
// 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 eventWhat 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:
// 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 millisecondssessionDurationMinutes: Duration in minutes (rounded)sessionDurationSeconds: Duration in seconds (rounded)sessionId: The session being endedtimestamp: 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:
// 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:
// 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 newsession('start')
8. requestLocation()
Manually request user's GPS location.
Parameters: None
Returns: Promise<LocationData>
LocationData Type:
interface LocationData {
latitude: number;
longitude: number;
accuracy: number; // in meters
}Examples:
// 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: falsein 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_idautomatically - Format:
anon-{fingerprint-hash}-{timestamp} - Based on device/browser characteristics
- Persists across sessions via localStorage
Identified Users (After signup/login):
- Can use custom
distinct_idfrom your backend - Or keep the fingerprint-based one
- User transitions tracked with
previous_distinct_id
User Journey Example
// 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: '[email protected]',
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)
// On signup/login, provide your own distinct_id
analytics.identify(12345, {
email: '[email protected]',
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
// Don't provide distinctId - keeps the fingerprint-based one
analytics.identify(12345, {
email: '[email protected]',
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:
{
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:
{
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
// 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 startsBenefits
✅ 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 localStorageSession 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_sessionStored data:
{
sessionId: "1704123456789-abc123def",
startTime: 1704123456789,
userId: 30 // if identified
}Session Start
✨ Automatic Tracking (Recommended):
// 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):
// Only for custom session management flows
analytics.session('start', {
custom_property: 'value'
});Session End
Automatic Tracking (Default):
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:
// 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:
beforeunloadevent - Fires when tab/browser closingpagehideevent - More reliable on mobile (iOS Safari)freezeevent - Safari iOS when page is frozen
Implementation:
// 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 eventSession ID
Every session has a unique ID:
// Format: timestamp-randomstring
// Example: "1704123456789-xyz789abc"Accessing Session ID:
// Session ID is private, but included in all events
analytics.track('my_event', {
// Custom properties
});
// → Event payload includes: sessionId automaticallySession Duration
Session duration is calculated on session_end:
analytics.endSession();
// Sends:
{
sessionDuration: 300000, // 300,000ms = 5 minutes
sessionDurationMinutes: 5, // 5 minutes
sessionDurationSeconds: 300 // 300 seconds
}Session Examples
Example 1: Normal Session Flow
// 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
// 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" continuesExample 3: User Login Mid-Session
// 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
// 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
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
{
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
{
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)
{
location: {
latitude: 23.8103,
longitude: 90.4125,
accuracy: 50 // meters
}
}4. Network Data
{
clientIp: '103.45.67.89' // Public IP address
}5. Page Data (for page views)
{
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: trueand user grants permission
Examples
E-Commerce Tracking
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
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
const analytics = new WebSparksAnalytics({
apiKey: 'saas-key',
projectId: 'saas-project'
});
// User signup
analytics.identify(789, {
email: '[email protected]',
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
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
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
// 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
import WebSparksAnalytics, {
AnalyticsConfig,
EventData,
UserProperties,
FingerprintData,
LocationData
} from 'websparks-analytics-sdk';Type Definitions
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
// 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: '[email protected]',
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
sendBeaconunavailable → Falls back to synchronous XHR - If
localStorageunavailable → Session won't persist across refreshes - If
Geolocationunavailable → Location features disabled
Debug Mode
Enable Debug Mode
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: trueDebug 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
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: trueand user consents) - ✅ Page views and custom events
- ✅ Session data
User Consent
// 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
const analytics = new WebSparksAnalytics({
apiKey: 'your-key',
projectId: 'your-project',
trackLocation: false // Never request GPS permission
});Privacy Best Practices
- ✅ Have a clear privacy policy
- ✅ Get user consent where required (GDPR, CCPA)
- ✅ Set
trackLocation: falseunless GPS is needed - ✅ Don't send PII in event properties
- ✅ Anonymize user data when possible
API Key Setup
Get Your API Key
- Login to WebSparks backend admin panel
- Navigate to Projects
- Create or select a project
- Copy your API key and project ID
Use in SDK
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:
// Valid key
✓ API Key is valid
// Invalid key
✗ API Key is invalid
Message: Invalid or inactive API keySecurity
- ✅ 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
// Use environment variables
const analytics = new WebSparksAnalytics({
apiKey: process.env.WEBSPARKS_API_KEY,
projectId: process.env.WEBSPARKS_PROJECT_ID
});Development
Install Dependencies
npm installBuild the SDK
npm run buildRun Tests
npm testStart Dev Server
npm run devTroubleshooting
Session End Not Firing
Problem: session_end event not being tracked
Solutions:
- Ensure
trackSessionEnd: truein config - Enable
debug: trueto see console logs - Check browser console for errors
- Test by actually closing tab (not just switching tabs)
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:
- Check API key is valid
- Check network tab for failed requests
- Enable debug mode
- Verify project ID is correct
Location Not Working
Problem: GPS location not being collected
Solutions:
- Set
trackLocation: truein config - User must grant permission
- HTTPS required (not HTTP)
- Check browser console for permission errors
// 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
- 📚 Documentation: https://docs.websparks.ai
- 📧 Email: [email protected]
- 💬 Discord: Join our community
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_idfor linking - 📝 Added comprehensive "Anonymous vs Identified Users" section to README
- 🔧 Enhanced
identify()method to acceptdistinctIdparameter - 🔧 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 forendSession() - ✨ Improved mobile browser support (iOS Safari)
- ✨ Added
endReasonto 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
