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:
- Per-event override — a
__emitkit_channelvalue in the event properties (highest priority). - Category mapping — the event’s category matched against
categoryChannelMap. - Default channel — the
channelNameoption (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
apiKeystring
Your EmitKit API key. Starts with 'emitkit_'.
stringchannelName?string
Default channel when no override or category mapping applies.
stringgeneralcategoryChannelMap?Record<string, string>
Map event categories to specific channels.
Record<string, string>notify?boolean
Send a notification for each event.
booleantruedisplayAs?'message' | 'notification'
How events appear in EmitKit.
'message' | 'notification'notificationdebug?boolean
Log debug output for the provider.
booleanfalseenabled?boolean
Enable or disable the provider.
booleantrueBest practices
- Route by category with
categoryChannelMapand reserve__emitkit_channelfor 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.
