@thanhdevapp/ngx-analytics-tracking
v0.1.2
Published
Analytics-level tracking SDK for Angular 20+. Event batching, offline queue, auto screen tracking, user properties, and more.
Maintainers
Readme
🎯 NgX Analytics Tracking
Production-ready analytics tracking SDK for Angular 20+. Event tracking with offline queue, auto screen tracking, user properties, and more.
✨ Features
- ✅ Event Batching - Automatic batching (50 events / 10 seconds)
- ✅ Offline Queue - IndexedDB-based offline storage with retry
- ✅ Auto Screen Tracking - Automatic Angular Router integration
- ✅ Interaction Tracking - Native gesture tracking (swipes, taps, drags, long-press)
- ✅ Lifecycle Events - first_open, session_start, app_update, user_engagement
- ✅ User Properties - Persistent user attributes
- ✅ Click Tracking - Directive-based declarative tracking
- ✅ Event Validation - Best-practice rules (max 40 char names, 25 params)
- ✅ Gzip Compression - 10x payload reduction
- ✅ Privacy Controls - GDPR-compliant opt-out/opt-in
- ✅ Debug Mode - Console output for development
- ✅ Zero Performance Impact - Runs outside Angular zone
- ✅ Unified Input Support - Works with mouse, touch, and pen (Pointer Events API)
📦 Installation
npm install @thanhdevapp/ngx-analytics-trackingPeer Dependencies
npm install @angular/common@^21 @angular/core@^21 @angular/router@^21 rxjs@^7🚀 Quick Start
1. Configure Provider
// app.config.ts
import { provideTracking } from '@thanhdevapp/ngx-analytics-tracking';
import { ApplicationConfig } from '@angular/core';
import { environment } from './environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideTracking({
appId: 'my-app',
endpoint: environment.trackingEndpoint,
debugMode: !environment.production,
batchSize: 50,
batchInterval: 10000,
compressionEnabled: true,
offlineQueueEnabled: true
})
]
};2. Track Events in Components
import { Component, inject } from '@angular/core';
import { TrackingService } from '@thanhdevapp/ngx-analytics-tracking';
@Component({
selector: 'app-product-detail',
template: `
<button (click)="addToCart()">Add to Cart</button>
`
})
export class ProductDetailComponent {
private tracking = inject(TrackingService);
ngOnInit() {
this.tracking.trackEvent('view_product', {
product_id: '123',
product_name: 'Sample Product',
price: 29.99
});
}
addToCart() {
this.tracking.trackEvent('add_to_cart', {
product_id: '123',
quantity: 1,
value: 29.99
});
}
}3. Declarative Click Tracking
<button
mbTrackClick="buy_now_button"
[trackParams]="{ product_id: product.id, price: product.price }">
Buy Now
</button>📖 API Reference
TrackingService
trackEvent(eventName: string, params?: Record<string, any>): void
Track custom events.
tracking.trackEvent('purchase', {
transaction_id: 'ORDER_123',
value: 99.99,
currency: 'USD'
});setUserId(userId: string): void
Set authenticated user ID.
tracking.setUserId('user_12345');setUserProperties(properties: Record<string, any>): void
Set persistent user attributes.
tracking.setUserProperties({
subscription_tier: 'premium',
signup_date: '2025-01-01',
vip_status: true
});optOut(): void / optIn(): void
GDPR-compliant privacy controls.
tracking.optOut(); // Disable tracking
tracking.optIn(); // Re-enable tracking🔧 Configuration Options
interface TrackingConfig {
appId: string; // Required: Application identifier
endpoint?: string; // API endpoint for batch upload
debugMode?: boolean; // Enable console logging (default: false)
batchSize?: number; // Max events per batch (default: 50)
batchInterval?: number; // Flush interval in ms (default: 10000)
compressionEnabled?: boolean; // Gzip compression (default: true)
offlineQueueEnabled?: boolean; // IndexedDB queue (default: true)
sessionTimeout?: number; // Session timeout in ms (default: 1800000)
}🎨 Advanced Usage
Interaction Tracking (Swipes, Taps, Gestures)
Track user interactions automatically using native Pointer Events API (supports mouse + touch + pen):
// Enable in config (auto-start)
provideTracking({
appId: 'my-app',
interactionTracking: {
enabled: true,
trackTaps: true, // Track tap/click events
trackSwipes: true, // Track swipe gestures
trackDrags: false, // Track drag gestures
trackLongPress: false, // Track long-press
swipeThreshold: 50, // Min 50px to detect swipe
samplingRate: 1.0, // Track 100% of interactions
}
});
// Or enable dynamically
const tracking = inject(TrackingService);
tracking.enableInteractionTracking({
trackSwipes: true,
trackTaps: true,
});
// Disable when needed
tracking.disableInteractionTracking();Events tracked:
interaction_tap- Tap/click with input type (mouse/touch/pen)gesture_swipe- Swipe with direction (left/right/up/down), velocity, distanceinteraction_drag- Drag with distance and durationinteraction_longpress- Long-press with coordinates
Browser Support:
- Chrome 55+, Safari 13+, Firefox 59+
- iOS WebView 13+, Android WebView 7+
- Automatic fallback for older browsers
Custom Lifecycle Events
import { LifecycleTrackerService } from '@thanhdevapp/ngx-analytics-tracking';
// Service automatically tracks:
// - first_open (first app launch)
// - session_start (30min timeout)
// - app_update (version change)
// - app_background / app_foreground (visibility API)
// - user_engagement (every 60s while active)Manual Screen Tracking
import { ScreenTrackerService } from '@thanhdevapp/ngx-analytics-tracking';
const screenTracker = inject(ScreenTrackerService);
screenTracker.trackScreen({
screen_name: '/custom-page',
screen_class: 'CustomPageComponent',
previous_screen: '/home'
});Error Tracking Interceptor
// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { errorTrackingInterceptor } from '@thanhdevapp/ngx-analytics-tracking';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([errorTrackingInterceptor])
)
]
};🧪 Testing
The SDK runs outside Angular's zone to avoid performance impact. For testing:
import { TestBed } from '@angular/core/testing';
import { TrackingService } from '@thanhdevapp/ngx-analytics-tracking';
describe('MyComponent', () => {
let tracking: jasmine.SpyObj<TrackingService>;
beforeEach(() => {
tracking = jasmine.createSpyObj('TrackingService', ['trackEvent']);
TestBed.configureTestingModule({
providers: [
{ provide: TrackingService, useValue: tracking }
]
});
});
it('should track event', () => {
component.addToCart();
expect(tracking.trackEvent).toHaveBeenCalledWith('add_to_cart', jasmine.any(Object));
});
});📊 Event Validation Rules
Follows analytics best practices:
- Event Names: Max 40 chars, alphanumeric + underscore, must start with letter
- Parameters: Max 25 params per event
- Parameter Values: Max 100 chars per string value
- User Properties: Max 25 user-scoped dimensions
🔒 Privacy & GDPR Compliance
// Opt-out (disable tracking)
tracking.optOut();
// Check status
if (tracking.isOptedOut()) {
console.log('Tracking disabled');
}
// Re-enable
tracking.optIn();Storage:
- Opt-out status saved in
localStorage(key:tracking_opted_out) - Events persisted in IndexedDB (database:
TrackingSDK)
🏗️ Architecture
@thanhdevapp/ngx-analytics-tracking
├── Core (Framework-agnostic)
│ ├── EventQueue (batching)
│ ├── StorageService (IndexedDB)
│ ├── CompressionService (gzip)
│ ├── NetworkManager (online/offline detection)
│ └── BatchUploader (HTTP + retry)
└── Angular (Angular-specific)
├── TrackingService (main facade)
├── ScreenTracker (Router integration)
├── LifecycleTracker (auto events)
├── TrackClickDirective (declarative tracking)
└── errorTrackingInterceptor (HTTP error capture)📈 Performance
- Bundle Size: ~45KB (gzipped)
- Runtime Impact: Zero (runs outside Angular zone)
- Network Optimization: Gzip compression (10x reduction)
- Offline Support: IndexedDB queue with retry
🤝 Contributing
Contributions welcome! Please open an issue or PR.
📄 License
MIT © thanhdevapp
🔗 Links
💬 Support
For issues and questions, please use GitHub Issues.
