StackSee Analytics
Providers

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/js

Important 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

OptionTypeDefaultDescription
apiKeystringrequiredYour EmitKit API key (starts with emitkit_)
channelNamestring'general'Default channel for events
categoryChannelMapRecord<string, string>undefinedMap event categories to specific channels
notifybooleantrueSend notifications for events
displayAs'message' | 'notification''notification'Display style for events
debugbooleanfalseEnable debug logging
enabledbooleantrueEnable/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:

  1. Event property override (highest priority) - Use __emitkit_channel in event properties
  2. Category mapping - Map event categories to channels via categoryChannelMap
  3. Default channel (fallback) - Use the channelName config 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 interactions
  • error - Errors and exceptions
  • conversion - Conversion and revenue events
  • navigation - Page views and navigation
  • performance - 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

  1. Organize with channels - Use category mapping to automatically route events to appropriate channels

    categoryChannelMap: {
      'user': 'user-activity',
      'error': 'alerts',
      'conversion': 'revenue'
    }
  2. Use meaningful channel names - Name channels by domain (e.g., 'payments', 'user-signups', 'team-alerts')

  3. Reserve overrides for critical events - Use __emitkit_channel sparingly for high-priority events that need special attention

  4. Leverage user aliasing - Always include email and username for flexible identification

  5. Include rich context - Add page, device, and UTM data for better insights

  6. Combine with analytics providers - Use EmitKit for notifications and activity feeds, PostHog for analytics dashboards

  7. Use the proxy pattern - Forward client events through your server to EmitKit for client-side tracking

  8. Map standard categories - Start with the predefined categories (user, engagement, error, conversion, navigation, performance) before creating custom ones

Resources