EmitKit Provider
Event notifications and activity feeds with rich metadata
EmitKit is a notification and event tracking service that allows you to send events to channels with rich metadata, user identification, and flexible display options.
Installation
# Server-side only:
pnpm install @emitkit/jsImportant Notes
EmitKit is server-side only. The EmitKit SDK does not provide a client-side package. For client-side event tracking, use the Proxy Provider to forward events from the browser to your server, where they can be sent to EmitKit.
Server-Side Usage
Basic Configuration
import { createServerAnalytics } from '@stacksee/analytics/server';
import { EmitKitServerProvider } from '@stacksee/analytics/providers/server';
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!, // starts with 'emitkit_'
channelName: 'general', // default channel (default: 'general')
notify: true, // send notifications (default: true)
displayAs: 'notification' // 'message' | 'notification'
})
]
});
serverAnalytics.initialize();Tracking Events
// Track a custom event
await serverAnalytics.track('purchase_completed', {
orderId: 'order-123',
amount: 99.99,
currency: 'USD'
}, {
userId: 'user-456',
user: {
email: 'user@example.com',
traits: {
plan: 'pro',
company: 'Acme Corp'
}
}
});User Identification
EmitKit supports powerful user aliasing, allowing you to reference users by multiple identifiers:
// Identify user with aliases
serverAnalytics.identify('user-123', {
email: 'john@example.com',
name: 'John Doe',
username: 'johndoe',
plan: 'pro'
});
// Now you can track events using any of these identifiers
await serverAnalytics.track('feature_used', {
feature: 'export'
}, {
userId: 'john@example.com' // Email works as alias!
});Client-to-Server with Proxy
Since EmitKit is server-only, use the proxy pattern for client-side events:
Client Setup
import { createClientAnalytics } from '@stacksee/analytics/client';
import { ProxyProvider } from '@stacksee/analytics/providers/client';
const analytics = createClientAnalytics({
providers: [
new ProxyProvider({
endpoint: '/api/analytics'
})
]
});
await analytics.initialize();
// Events are queued and sent to your API endpoint
analytics.track('button_clicked', { buttonId: 'signup' });Server API Endpoint
// app/api/analytics/route.ts (Next.js example)
import { createServerAnalytics } from '@stacksee/analytics/server';
import { EmitKitServerProvider } from '@stacksee/analytics/providers/server';
import { ingestProxyEvents } from '@stacksee/analytics/providers/server';
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'user-activity'
})
]
});
serverAnalytics.initialize();
export async function POST(request: Request) {
await ingestProxyEvents(request, serverAnalytics);
return new Response('OK');
}Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | required | Your EmitKit API key (starts with emitkit_) |
channelName | string | 'general' | Default channel for events |
categoryChannelMap | Record<string, string> | undefined | Map event categories to specific channels |
notify | boolean | true | Send notifications for events |
displayAs | 'message' | 'notification' | 'notification' | Display style for events |
debug | boolean | false | Enable debug logging |
enabled | boolean | true | Enable/disable the provider |
Channel Routing
EmitKit's power comes from its channel system, similar to Slack channels, where you can organize events into different streams. The provider supports flexible channel routing to automatically send events to the right channels.
Channel Resolution Priority
Events are routed to channels based on this priority order:
- Event property override (highest priority) - Use
__emitkit_channelin event properties - Category mapping - Map event categories to channels via
categoryChannelMap - Default channel (fallback) - Use the
channelNameconfig option (default:'general')
Default Channel
Set a global default channel for all events:
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'app-events' // All events go here by default
})
]
});Category-Based Channel Mapping
Automatically route events to specific channels based on their category:
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'general', // Fallback channel
categoryChannelMap: {
'user': 'user-activity', // All user events → user-activity
'engagement': 'product-usage', // All engagement → product-usage
'error': 'alerts', // All errors → alerts
'conversion': 'revenue', // All conversions → revenue
'navigation': 'page-views' // All navigation → page-views
}
})
]
});
// This event automatically goes to 'user-activity' channel
await serverAnalytics.track('user_signed_up', {
plan: 'pro'
});
// This event automatically goes to 'alerts' channel
await serverAnalytics.track('api_error', {
endpoint: '/api/users',
statusCode: 500
});Predefined Categories:
user- User lifecycle events (signup, login, etc.)engagement- Feature usage and interactionserror- Errors and exceptionsconversion- Conversion and revenue eventsnavigation- Page views and navigationperformance- Performance metrics
You can also use custom categories for your specific needs.
Per-Event Channel Override
Override the channel for specific critical events:
// Send critical payment to a dedicated channel
await serverAnalytics.track('payment_processed', {
amount: 10000,
currency: 'USD',
__emitkit_channel: 'critical-payments' // Override to critical channel
});
// Send error alert to team notification channel
await serverAnalytics.track('service_down', {
service: 'api',
__emitkit_channel: 'team-alerts'
});The __emitkit_channel property is automatically stripped from the metadata sent to EmitKit - it's only used for internal routing.
Complete Example
Combining all three routing methods:
const serverAnalytics = createServerAnalytics({
providers: [
new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'general', // Fallback for unmapped categories
categoryChannelMap: {
'user': 'user-activity',
'error': 'alerts',
'conversion': 'revenue'
}
})
]
});
// Goes to 'user-activity' (category mapping)
await serverAnalytics.track('user_signed_up', { plan: 'pro' });
// Goes to 'alerts' (category mapping)
await serverAnalytics.track('api_error', { endpoint: '/users' });
// Goes to 'critical-payments' (event override)
await serverAnalytics.track('large_payment', {
amount: 50000,
__emitkit_channel: 'critical-payments'
});
// Goes to 'general' (no mapping, uses default)
await serverAnalytics.track('feature_flag_changed', { flag: 'beta' });Features
Auto-Formatted Event Titles
Event names are automatically formatted into readable titles:
// 'user_signed_up' → 'User Signed Up'
// 'purchase_completed' → 'Purchase Completed'
await serverAnalytics.track('user_signed_up', {
plan: 'pro'
});Category-Based Icons
Events automatically get icons based on their category:
engagement→ 👆user→ 👤navigation→ 🧭error→ ❌performance→ ⚡conversion→ 💰
Rich Metadata
All event context is included as metadata:
await serverAnalytics.track('page_viewed', {
pageName: 'Dashboard'
}, {
userId: 'user-123',
context: {
page: { path: '/dashboard', title: 'Dashboard' },
device: { userAgent: req.headers['user-agent'] },
utm: { source: 'google', medium: 'cpc' }
}
});User Aliasing
EmitKit supports multiple identifiers per user:
serverAnalytics.identify('user-123', {
email: 'john@example.com',
username: 'johndoe',
name: 'John Doe'
});
// Creates aliases for:
// - user-123 (user ID)
// - john@example.com (email)
// - johndoe (username)Typical Use Cases
EmitKit works best for:
- Activity feeds - Real-time user activity streams
- Notification systems - Alert users about important events
- Event logging - Centralized event tracking with rich metadata
- User journey tracking - Monitor user behavior with context
- Internal dashboards - Team visibility into product usage
Use with other providers:
- Combine with PostHog/Pirsch for analytics dashboards
- Combine with Bento for email marketing automation
- Use proxy pattern for unified client/server tracking
Provider Routing
Recommended setup with multiple providers:
import { createServerAnalytics } from '@stacksee/analytics/server';
import { EmitKitServerProvider } from '@stacksee/analytics/providers/server';
import { PostHogServerProvider } from '@stacksee/analytics/providers/server';
const serverAnalytics = createServerAnalytics({
providers: [
// Use PostHog for analytics and dashboards
new PostHogServerProvider({
apiKey: process.env.POSTHOG_API_KEY!
}),
// Use EmitKit for activity feeds and notifications
{
provider: new EmitKitServerProvider({
apiKey: process.env.EMITKIT_API_KEY!,
channelName: 'user-activity',
notify: true
}),
// Only send important events to EmitKit
methods: ['track', 'identify']
}
]
});Best Practices
-
Organize with channels - Use category mapping to automatically route events to appropriate channels
categoryChannelMap: { 'user': 'user-activity', 'error': 'alerts', 'conversion': 'revenue' } -
Use meaningful channel names - Name channels by domain (e.g.,
'payments','user-signups','team-alerts') -
Reserve overrides for critical events - Use
__emitkit_channelsparingly for high-priority events that need special attention -
Leverage user aliasing - Always include email and username for flexible identification
-
Include rich context - Add page, device, and UTM data for better insights
-
Combine with analytics providers - Use EmitKit for notifications and activity feeds, PostHog for analytics dashboards
-
Use the proxy pattern - Forward client events through your server to EmitKit for client-side tracking
-
Map standard categories - Start with the predefined categories (
user,engagement,error,conversion,navigation,performance) before creating custom ones