Skip to content
trakoo
Esc
navigateopen⌘Jpreview
On this page

EmitKit

Server-only event notifications and activity feeds with channel routing and rich metadata.

EmitKit sends events to named channels with rich metadata, so your team can watch activity feeds and get notified when something important happens.

When to use it

  • Real-time activity feeds and internal dashboards for team visibility.
  • Notifications for high-signal events like signups, payments, or errors.
  • Event logging with user context, routed into channels by topic.

EmitKit is not a product-analytics dashboard. Pair it with a provider like PostHog or Pirsch when you need charts and funnels.

Installation

pnpm install @emitkit/js

Client-side usage

EmitKit is server-only — its SDK has no browser package. To capture browser events, use the Proxy to forward them to your server, then send them to EmitKit from there. See Browser events via proxy below.

Server-side usage

import { createServerAnalytics } from 'trakoo/server';
import { EmitKitServerProvider } from 'trakoo/providers/server';

export const serverAnalytics = createServerAnalytics({
  providers: [
    new EmitKitServerProvider({
      apiKey: process.env.EMITKIT_API_KEY!, // starts with 'emitkit_'
      channelName: 'general'
    })
  ]
});

Track events with properties and optional user context. EmitKit accepts multiple identifiers per user, so later events can reference a user by id, email, or username.

await serverAnalytics.track('purchase_completed', {
  orderId: 'order-123',
  amount: 99.99,
  currency: 'USD'
}, {
  userId: 'user-456',
  user: {
    email: 'user@example.com',
    traits: { plan: 'pro' }
  }
});

Channel routing

Channels group events into separate streams, similar to Slack channels. The provider resolves the channel for each event in this order:

  1. Per-event override — a __emitkit_channel value in the event properties (highest priority).
  2. Category mapping — the event’s category matched against categoryChannelMap.
  3. Default channel — the channelName option (falls back to 'general').

Map categories to channels so events route automatically:

new EmitKitServerProvider({
  apiKey: process.env.EMITKIT_API_KEY!,
  channelName: 'general', // fallback for unmapped categories
  categoryChannelMap: {
    user: 'user-activity',
    error: 'alerts',
    conversion: 'revenue'
  }
});

// Category 'user' → 'user-activity'
await serverAnalytics.track('user_signed_up', { plan: 'pro' });

Override the channel for a single event by adding __emitkit_channel. trakoo strips this key before sending, so it never appears in the event metadata.

await serverAnalytics.track('large_payment', {
  amount: 50000,
  __emitkit_channel: 'critical-payments'
});

Titles and icons

EmitKit turns event names into readable titles (user_signed_up becomes “User Signed Up”) and assigns an icon based on the event category, so feeds stay legible without extra configuration.

Browser events via proxy

Send browser events through your own API, then forward them to EmitKit on the server.

import { createClientAnalytics } from 'trakoo/client';
import { ProxyProvider } from 'trakoo/providers/client';

export const analytics = createClientAnalytics({
  providers: [new ProxyProvider({ endpoint: '/api/analytics' })]
});

analytics.track('button_clicked', { buttonId: 'signup' });
import { createServerAnalytics } from 'trakoo/server';
import {
  EmitKitServerProvider,
  ingestProxyEvents
} from 'trakoo/providers/server';

const serverAnalytics = createServerAnalytics({
  providers: [
    new EmitKitServerProvider({
      apiKey: process.env.EMITKIT_API_KEY!,
      channelName: 'user-activity'
    })
  ]
});

export async function POST(request: Request) {
  await ingestProxyEvents(request, serverAnalytics);
  return new Response('OK');
}

Configuration

PropType
apiKeystring

Your EmitKit API key. Starts with 'emitkit_'.

Typestring
channelName?string

Default channel when no override or category mapping applies.

Typestring
Defaultgeneral
categoryChannelMap?Record<string, string>

Map event categories to specific channels.

TypeRecord<string, string>
notify?boolean

Send a notification for each event.

Typeboolean
Defaulttrue
displayAs?'message' | 'notification'

How events appear in EmitKit.

Type'message' | 'notification'
Defaultnotification
debug?boolean

Log debug output for the provider.

Typeboolean
Defaultfalse
enabled?boolean

Enable or disable the provider.

Typeboolean
Defaulttrue

Best practices

  • Route by category with categoryChannelMap and reserve __emitkit_channel for the few events that need a dedicated channel.
  • Name channels by domain — payments, user-signups, team-alerts — so feeds stay scannable.
  • Include email and username in user traits so events resolve to the same person across identifiers.
  • Run EmitKit alongside an analytics provider: EmitKit for feeds and notifications, PostHog or Pirsch for dashboards. See routing to control which events reach each provider.

Resources

Was this page helpful?