@lobehub/analytics
v1.6.0
Published
A modern, type-safe analytics library for tracking user events across multiple providers, built by LobeHub
Keywords
Readme
A modern, type-safe analytics library for tracking user events across multiple providers, built by LobeHub
Changelog · Report Bug · Request Feature

TOC
- ✨ Features
- 📦 Installation
- ⚠️ Client-side vs Server-side Usage
- Import Structure
- 🚀 Quick Start
- 📖 API Reference
- 🛠️ Development
- Examples
- 🤝 Contributing
✨ Features
- 🎯 Type-safe - Full TypeScript support with predefined events
- 🔌 Multi-provider - Built-in PostHog support, extensible for other providers
- 🌐 Global Instance Management - Singleton pattern and named global instances
- 📊 SPM Auto-Prefixing - Automatic Source Page Medium tracking with business prefixes
- ⚛️ React integration - Enhanced Provider with auto-registration and hooks
- 🎛️ Easy configuration - Simple setup with business context
- 🪶 Lightweight - Minimal dependencies and optimized bundle size
- 🔧 Developer-friendly - Comprehensive error handling and debugging
- 🧪 Test-friendly - Built-in reset and cleanup functions
📦 Installation
To install @lobehub/analytics, run the following command:
npm install @lobehub/analytics
# Additional installation for server-side usage
npm install posthog-node # Server-side onlyThis library includes PostHog analytics provider out of the box. For React integration:
npm install react # if not already installed⚠️ Client-side vs Server-side Usage
🌐 Client-side Usage (Browser Environment)
import { createAnalytics } from '@lobehub/analytics';
const analytics = createAnalytics({
business: 'my-app',
providers: {
posthog: { enabled: true, key: 'client_key' },
},
});🖥️ Server-side Usage (Node.js Environment)
import { createServerAnalytics } from '@lobehub/analytics/server';
const analytics = createServerAnalytics({
business: 'my-app',
providers: {
// ✅ Client-side PostHog (browser compatible)
posthog: {
enabled: true,
key: 'phc_xxxxx',
api_host: 'https://app.posthog.com',
},
// ✅ Server-side PostHog (Node.js only)
posthogNode: {
enabled: true,
key: 'server_key',
host: 'https://app.posthog.com',
},
},
});🔥 Separation Solution: Clear entry point separation ensures
posthogNodeis completely excluded from client-side builds!
Import Structure
The library provides separate entry points for client-side, server-side, and React integration:
// Client-side analytics (browser safe)
import { AnalyticsManager, createAnalytics } from '@lobehub/analytics';
// Global instance management
import {
createSingletonAnalytics,
getGlobalAnalytics,
getSingletonAnalytics,
} from '@lobehub/analytics';
// React hooks (separate import)
import {
AnalyticsProvider,
useAnalytics,
useAnalyticsStrict,
useEventTracking,
} from '@lobehub/analytics/react';
// Server-side analytics (includes posthog-node)
import { PostHogNodeAnalyticsProvider, createServerAnalytics } from '@lobehub/analytics/server';🚀 Quick Start
Basic Usage
import { createAnalytics } from '@lobehub/analytics';
// Configure analytics with business context
const analytics = createAnalytics({
business: 'my-app', // Required: business name for SPM prefixing
debug: process.env.NODE_ENV === 'development',
providers: {
posthog: {
enabled: !!process.env.POSTHOG_KEY,
key: process.env.POSTHOG_KEY!,
host: process.env.POSTHOG_HOST, // optional
},
},
});
// Initialize
await analytics.initialize();
// Track events with automatic SPM prefixing
await analytics.trackEvent('user_signup', {
method: 'email',
source: 'landing_page',
spm: 'homepage.cta', // Will become: 'my-app.homepage.cta'
});
// Identify users
await analytics.identify('user_123', {
email: '[email protected]',
plan: 'pro',
});Global Instance Management
Singleton Pattern (Recommended for simple apps):
import { createSingletonAnalytics, getSingletonAnalytics } from '@lobehub/analytics';
// Create singleton (usually in app initialization)
const analytics = createSingletonAnalytics({
business: 'my-app',
providers: {
posthog: {
enabled: true,
key: process.env.POSTHOG_KEY!,
},
},
});
await analytics.initialize();
// Access from anywhere in your application
export function trackUserAction() {
const analytics = getSingletonAnalytics();
analytics.trackEvent('button_click', {
button_name: 'signup',
page: 'home',
});
}Named Global Instances (For complex apps):
import { getGlobalAnalytics, setGlobalAnalytics } from '@lobehub/analytics';
// Register multiple instances
setGlobalAnalytics(mainAnalytics, 'main');
setGlobalAnalytics(adminAnalytics, 'admin');
// Use specific instances
getGlobalAnalytics('main').trackEvent('user_action', {});
getGlobalAnalytics('admin').trackEvent('admin_action', {});React Integration
Enhanced AnalyticsProvider with auto-registration:
import React from 'react';
import { createAnalytics } from '@lobehub/analytics';
import {
AnalyticsProvider,
useAnalytics,
useAnalyticsStrict
} from '@lobehub/analytics/react';
// Create analytics instance
const analytics = createAnalytics({
business: 'my-app',
providers: {
posthog: {
enabled: true,
key: process.env.REACT_APP_POSTHOG_KEY!,
},
},
});
// Provider with auto-registration
function App() {
return (
<AnalyticsProvider
client={analytics}
autoInitialize={true} // Auto-initialize on mount
registerGlobal={true} // Auto-register as global instance
globalName="main" // Optional: custom global name
>
<MyComponent />
</AnalyticsProvider>
);
}
// Use in components
function MyComponent() {
const { analytics, isReady, isInitializing, error } = useAnalytics();
// Safe usage with state checking
if (isInitializing) return <div>Loading analytics...</div>;
if (error) return <div>Analytics error: {error.message}</div>;
if (!isReady) return <div>Analytics not ready</div>;
const handleClick = () => {
analytics?.trackEvent('button_click', {
button_name: 'cta',
page: 'home',
});
};
return <button onClick={handleClick}>Track Event</button>;
}
// Strict mode (throws if not initialized)
function StrictComponent() {
const analytics = useAnalyticsStrict(); // Throws if not ready
const handleClick = () => {
analytics.trackEvent('button_click', { button_name: 'strict-button' });
};
return <button onClick={handleClick}>Strict Track</button>;
}Access analytics outside React components:
import { getGlobalAnalytics } from '@lobehub/analytics/react';
// In service functions, API handlers, etc.
export async function apiCall() {
try {
const response = await fetch('/api/data');
// Track success
const analytics = getGlobalAnalytics('main');
analytics.trackEvent('api_call', {
endpoint: '/api/data',
success: true,
});
return response.json();
} catch (error) {
// Track error
const analytics = getGlobalAnalytics('main');
analytics.trackEvent('api_call', {
endpoint: '/api/data',
success: false,
error: error.message,
});
throw error;
}
}SPM (Source Page Medium) Auto-Prefixing
The library automatically handles SPM prefixing with your business name:
const analytics = createAnalytics({
business: 'my-app', // This will prefix all SPM values
// ... other config
});
// These events will have SPM auto-prefixed:
analytics.trackEvent('button_click', {
button_name: 'signup',
spm: 'homepage.hero', // Becomes: 'my-app.homepage.hero'
});
analytics.trackEvent('page_view', {
page: '/dashboard',
spm: 'dashboard.main', // Becomes: 'my-app.dashboard.main'
});
// If no SPM provided, uses business name as default
analytics.trackEvent('user_login', {
method: 'email',
// spm will be: 'my-app'
});📖 API Reference
Core Functions
createAnalytics(config: AnalyticsConfig): AnalyticsManager
Creates a configured analytics manager.
AnalyticsManager
Main class for managing analytics providers.
Methods:
initialize(): Promise<void>- Initialize all providerstrack(event: AnalyticsEvent): Promise<void>- Track custom eventtrackEvent<K>(eventName: K, properties): Promise<void>- Track predefined eventidentify(userId: string, properties?): Promise<void>- Identify usertrackPageView(page: string, properties?): Promise<void>- Track page viewreset(): Promise<void>- Reset user identitysetGlobalContext(context: EventContext): this- Set global contextgetStatus(): { initialized: boolean; providersCount: number }- Get status
Global Instance Management
Singleton Pattern
// Create singleton
createSingletonAnalytics(config: AnalyticsConfig): AnalyticsManager
// Get singleton
getSingletonAnalytics(): AnalyticsManager
getSingletonAnalyticsOptional(): AnalyticsManager | null
// Check singleton
hasSingletonAnalytics(): boolean
resetSingletonAnalytics(): void // For testingNamed Global Instances
// Register/unregister
setGlobalAnalytics(instance: AnalyticsManager, name?: string): void
removeGlobalAnalytics(name?: string): boolean
clearGlobalAnalytics(): void
// Access
getGlobalAnalytics(name?: string): AnalyticsManager
getGlobalAnalyticsOptional(name?: string): AnalyticsManager | null
// Utilities
hasGlobalAnalytics(name?: string): boolean
getGlobalAnalyticsNames(): string[]React Hooks & Provider
AnalyticsProvider
<AnalyticsProvider
client={AnalyticsManager}
autoInitialize?: boolean // Default: true
registerGlobal?: boolean // Default: true
globalName?: string // Default: '__default__'
>
{children}
</AnalyticsProvider>React Hooks
// Safe access with state
useAnalytics(): {
analytics: AnalyticsManager | null;
isReady: boolean;
isInitialized: boolean;
isInitializing: boolean;
error: Error | null;
}
// Strict access (throws if not ready)
useAnalyticsStrict(): AnalyticsManager
// State only
useAnalyticsState(): {
isReady: boolean;
isInitialized: boolean;
isInitializing: boolean;
error: Error | null;
}
// Optional access
useAnalyticsOptional(): AnalyticsManager | null
// Legacy hook (for backward compatibility)
useEventTracking(manager: AnalyticsManager): {
trackButtonClick: (buttonName: string, properties?: any) => void;
// ... other convenience methods
}Types
AnalyticsConfig
interface AnalyticsConfig {
business: string; // Required: business name for SPM prefixing
debug?: boolean;
providers: {
posthog?: PostHogProviderAnalyticsConfig;
umami?: UmamiProviderAnalyticsConfig;
ga?: GoogleProviderAnalyticsConfig;
};
}PostHogProviderAnalyticsConfig
interface PostHogProviderAnalyticsConfig {
enabled: boolean;
key: string;
host?: string;
debug?: boolean;
// ... other PostHog config options
}PredefinedEvents
interface PredefinedEvents {
// UI interactions
button_click: {
button_name: string;
page?: string;
section?: string;
spm?: string;
[key: string]: any;
};
// User actions
user_signup: {
method: 'email' | 'oauth' | 'phone';
source?: string;
spm?: string;
[key: string]: any;
};
user_login: {
method: 'email' | 'oauth' | 'phone';
spm?: string;
[key: string]: any;
};
// Chat interactions
chat_message_sent: {
message_length: number;
model?: string;
conversation_id?: string;
spm?: string;
[key: string]: any;
};
// Page tracking
page_view: {
page: string;
referrer?: string;
spm?: string;
[key: string]: any;
};
// Form interactions
form_submit: {
form_name: string;
success: boolean;
spm?: string;
[key: string]: any;
};
}🛠️ Development
# Clone the repository
git clone https://github.com/lobehub/@lobehub/analytics.git
cd @lobehub/analytics
# Install dependencies
npm install
# Start development
npm run dev
# Build the library
npm run build
# Run tests
npm test
# Run examples
npm run exampleProject Structure
@lobehub/analytics/
├── src/
│ ├── base.ts # Base analytics provider
│ ├── manager.ts # Analytics manager
│ ├── config.ts # Configuration factory
│ ├── global.ts # Global instance management
│ ├── types.ts # TypeScript definitions
│ ├── providers/ # Analytics providers
│ │ └── posthog.ts # PostHog implementation
│ ├── react/ # React integration
│ │ ├── provider.tsx # Enhanced Provider component
│ │ └── hooks.ts # Legacy hooks
│ └── index.ts # Main exports
├── examples/ # Usage examples
└── dist/ # Built files (generated)Examples
See the examples/ directory for comprehensive usage examples:
examples/library-usage.ts- Basic library usage and design principlesexamples/enhanced-react-usage.tsx- Advanced React integrationexamples/singleton-enhanced-usage.ts- Singleton pattern examplesexamples/global-usage.ts- Global instance managementexamples/business-spm-example.ts- SPM prefixing demonstrationexamples/usage-summary.md- Complete feature overview
🤝 Contributing
Contributions of all types are more than welcome, if you are interested in contributing code, feel free to check out our GitHub Issues to get stuck in to show us what you're made of.
