@timbuk22/kuro-tracker
v0.3.0
Published
User Interaction Events tracking library for Kuro Service
Maintainers
Readme
Kuro Tracker
A lightweight, performant, and privacy-conscious user interaction tracking library designed for the Kuro Service ecosystem. Built with TypeScript and optimized for React applications.
Features
- 🚀 Fire-and-forget API - Non-blocking event tracking
- 📦 Smart batching - Automatically batches events (50 event threshold, 1000 event buffer)
- 🔄 Retry logic - Exponential backoff for failed requests
- 💾 Offline support - LocalStorage persistence for offline scenarios
- ⚛️ React integration - Custom hooks and HOCs for easy integration
- 📊 Type-safe - Full TypeScript support
- 🎯 Lightweight - ~15KB gzipped
- 🔒 Privacy-focused - No PII tracking, consent management built-in
Installation
npm install kuro-tracker
# or
yarn add kuro-tracker
# or
pnpm add kuro-trackerQuick Start
Basic Usage
import KuroTracker from 'kuro-tracker';
// or
import { initialize, trackEvent, updateAuthToken } from 'kuro-tracker';
// Initialize the tracker (do this once in your app)
KuroTracker.initialize({
apiUrl: 'https://api.your-domain.com',
walletId: '0x1234...abcd', // Required: user's wallet address
authToken: 'your-auth-token', // Required: authentication token
source: 'your-app-name',
eventVersion: '1.0.0',
});
// Track an event using the eventType string format
// Format: context.action.target (e.g., 'button.click.submit')
KuroTracker.trackEvent('game.click.join', {
gameId: '123',
roomId: '456',
});
// Or using the exported function
trackEvent('wallet.connect.metamask', {
chainId: 1,
});React Integration Example
import { useEffect } from 'react';
import KuroTracker from 'kuro-tracker';
function GameLobby({ walletId, authToken }) {
// Initialize tracker on mount
useEffect(() => {
if (walletId && authToken) {
KuroTracker.initialize({
apiUrl: 'https://api.your-domain.com',
walletId,
authToken,
source: 'multiplayer-dapp',
eventVersion: '1.0.0',
});
}
}, [walletId, authToken]);
const handleJoinGame = (gameId: string) => {
// Track the event
KuroTracker.trackEvent('game.click.join', { gameId });
// ... your game logic
};
return (
<button onClick={() => handleJoinGame('game-123')}>
Join Game
</button>
);
}API Reference
Initialization
KuroTracker.initialize(config: TrackerConfig)
// or
initialize(config: TrackerConfig)TrackerConfig
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| apiUrl | string | ✅ | - | API endpoint URL |
| walletId | string | ✅ | - | User's wallet address |
| authToken | string | ✅ | - | Authentication token for API |
| source | string | ✅ | - | Source application name |
| eventVersion | string | ✅ | - | Event schema version |
| consentVersion | string | ❌ | - | Version of consent obtained |
| bufferSize | number | ❌ | 1000 | Maximum events in buffer |
| flushThreshold | number | ❌ | 50 | Auto-flush threshold |
| flushInterval | number | ❌ | 10000 | Auto-flush interval (ms) |
| enableOfflineSupport | boolean | ❌ | true | Enable localStorage persistence |
| enableDebugLogging | boolean | ❌ | false | Enable debug logs |
| onError | (error: Error) => void | ❌ | - | Error callback |
| notifications | NotificationConfig | ❌ | - | Notification settings |
Tracking Events
KuroTracker.trackEvent(eventType: string, metadata?: object, consent?: boolean)
// or
trackEvent(eventType: string, metadata?: object, consent?: boolean)Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| eventType | string | ✅ | - | Event type in format: context.action.target |
| metadata | object | ❌ | {} | Additional event data |
| consent | boolean | ❌ | true | User consent status |
Event Type Format
Events follow the pattern: context.action.target
Examples:
button.click.submitpage.view.dashboardgame.start.multiplayerwallet.connect.metamaskform.submit.registration
Authentication Management
// Update auth token when it expires or changes
KuroTracker.updateAuthToken(newAuthToken: string)
// or
updateAuthToken(newAuthToken: string)
// Check if authenticated
const isAuth = KuroTracker.isAuthenticated()Manual Flush
// Fire-and-forget flush (non-blocking)
KuroTracker.flush()
// or
flush()
// With callback for result (still non-blocking)
KuroTracker.flushWithCallback((result) => {
console.log('Flush completed:', result);
})
// or
flushWithCallback((result) => {
console.log('Flush completed:', result);
})The callback receives a FlushResult object:
interface FlushResult {
success: boolean;
eventsProcessed: number;
eventsFailed: number;
error?: Error;
}Note: The flush methods are fire-and-forget and won't block UI interactions. Events are flushed in the background without requiring await.
Cleanup
// Destroy the tracker and clean up resources
KuroTracker.destroy()
// or
destroy()Using with React Context
// KuroTrackerContext.tsx
import React, { createContext, useContext, useEffect } from 'react';
import KuroTracker from 'kuro-tracker';
interface KuroTrackerContextType {
trackEvent: (eventType: string, metadata?: object) => void;
updateAuthToken: (token: string) => void;
}
const KuroTrackerContext = createContext<KuroTrackerContextType | null>(null);
export function KuroTrackerProvider({ children, config }) {
useEffect(() => {
KuroTracker.initialize(config);
}, []);
const value = {
trackEvent: KuroTracker.trackEvent,
updateAuthToken: KuroTracker.updateAuthToken,
};
return (
<KuroTrackerContext.Provider value={value}>
{children}
</KuroTrackerContext.Provider>
);
}
export function useKuroTracker() {
const context = useContext(KuroTrackerContext);
if (!context) {
throw new Error('useKuroTracker must be used within KuroTrackerProvider');
}
return context;
}
// Usage in components
function MyComponent() {
const { trackEvent } = useKuroTracker();
const handleClick = () => {
trackEvent('button.click.action', { component: 'MyComponent' });
};
return <button onClick={handleClick}>Click me</button>;
}Event Schema
Events are automatically enriched with:
walletId- From the provided wallet ID in configtimestamp- ISO 8601 timestampsessionId- Unique session identifierviewport- Current viewport dimensionsmetadata.userAgent- Browser user agentmetadata.referrer- Document referrersource- Application source from configeventVersion- Event schema versioneventContext,eventAction,eventTarget- Parsed from the event type string
Event Type Parsing
The library automatically parses your event type string:
// Input
trackEvent('game.click.join')
// Parsed result
{
eventContext: 'game',
eventAction: 'click',
eventTarget: 'join',
eventType: 'game.click.join'
}Advanced Configuration
Notification Configuration
KuroTracker.initialize({
// ... other config
notifications: {
enableNotifications: true,
notificationLevel: 'warning', // 'info' | 'warning' | 'error' | 'critical'
notificationBatchSize: 10,
notificationBatchInterval: 5000,
// Discord webhook support (future feature)
// discordWebhookUrl: 'https://discord.com/api/webhooks/...',
// discordUsername: 'KuroTracker Bot',
// discordAvatarUrl: 'https://example.com/avatar.png',
},
});Custom Error Handling
KuroTracker.initialize({
// ... other config
onError: (error) => {
console.error('Tracking error:', error);
// Send to your error monitoring service
Sentry.captureException(error);
},
});Conditional Tracking
const shouldTrack = getUserConsent();
// Consent parameter is optional and defaults to true
KuroTracker.trackEvent(
'game.click.play',
{ gameMode: 'multiplayer' },
shouldTrack // Pass consent as third parameter
);Authentication Token Management
// Initial setup with auth token
KuroTracker.initialize({
apiUrl: 'https://api.example.com',
walletId: userWallet,
authToken: initialAuthToken,
source: 'my-app',
eventVersion: '1.0.0',
});
// Later, when token expires or refreshes
const refreshToken = async () => {
const newToken = await fetchNewAuthToken();
KuroTracker.updateAuthToken(newToken);
};
// Check authentication status
if (!KuroTracker.isAuthenticated()) {
await refreshToken();
}TypeScript Support
The library is fully typed. Import types as needed:
import type {
TrackerConfig,
UserInteractionEvent,
FlushResult,
NotificationConfig,
ParsedEvent
} from 'kuro-tracker';
// The main class is also available as default export
import KuroTracker from 'kuro-tracker';
// Or use named exports
import {
initialize,
trackEvent,
flush,
destroy,
updateAuthToken
} from 'kuro-tracker';Performance Considerations
- Events are queued in memory and sent in batches
- Automatic cleanup on page unload
- Minimal impact on UI thread
- Efficient retry mechanism with exponential backoff
- LocalStorage used only when enabled
Privacy & Compliance
- No automatic PII collection
- Consent flag required for all events
- Wallet addresses should be anonymized when possible
- Complies with GDPR requirements when properly configured
Browser Support
- Chrome/Edge: Last 2 versions
- Firefox: Last 2 versions
- Safari: Last 2 versions
- Requires ES2018+ support
Contributing
See the main repository's contributing guidelines.
License
MIT © Kuro Team
