Track Custom Events
Kitbase lets you track custom events with rich metadata to understand what your users are doing, monitor business metrics, and trigger real-time notifications. Events are sent asynchronously to the Kitbase API and processed in the background.
All events are sent via POST /sdk/v1/logs with API key authentication (X-API-Key header) and return 202 Accepted for async processing.
Basic Usage
import { init } from '@kitbase/analytics';
const kitbase = init({ sdkKey: 'YOUR_SDK_KEY' });
await kitbase.track({
channel: 'payments',
event: 'Purchase Completed',
tags: {
amount: 99.99,
currency: 'USD',
plan: 'premium'
}
});Track Options
The track method accepts a TrackOptions object with the following fields:
interface TrackOptions {
channel: string; // Required: event category (e.g., 'payments', 'users', 'errors')
event: string; // Required: event name (e.g., 'Purchase Completed')
user_id?: string; // Optional: explicit user identifier
icon?: string; // Optional: emoji icon for dashboard
notify?: boolean; // Optional: trigger real-time notification
description?: string; // Optional: human-readable event description
tags?: Record<string, unknown>; // Optional: metadata (string, number, boolean values)
}| Parameter | Type | Required | Description |
|---|---|---|---|
channel | string | Yes | Category for the event (e.g., "payments", "users") |
event | string | Yes | Name of the event (e.g., "Purchase Completed") |
user_id | string | No | Explicit user identifier |
icon | string | No | Emoji icon displayed in the dashboard |
notify | boolean | No | Trigger a real-time notification |
description | string | No | Human-readable event description |
tags | object | No | Key-value metadata (string, number, boolean) |
Response
A successful call returns a TrackResponse with the event's unique identifier and timestamp:
interface TrackResponse {
id: string; // Unique event ID (UUID)
event: string; // Event name
timestamp: string; // ISO 8601 timestamp
}Channels
Channels organize your events into logical categories. Use consistent channel names across your application to keep your dashboard clean and filterable.
| Channel | Use Case |
|---|---|
payments | Purchases, refunds, subscription changes |
users | Signups, logins, profile updates |
errors | Application errors, failed requests |
notifications | Alerts, messages, delivery status |
api | API calls, webhooks, integrations |
system | Infrastructure events, deployments |
You are not limited to these defaults. Custom channels are fully supported -- use whatever names make sense for your domain.
Channel Naming
Use lowercase, plural nouns for channel names (e.g., payments, errors, users). This keeps your events organized and easy to filter in the dashboard.
Tags
Tags are key-value metadata attached to events. They allow you to store additional context that you can filter and analyze later.
Supported Types
| Type | Example |
|---|---|
string | "premium" |
number | 99.99 |
boolean | true |
Example
tags: {
plan_name: 'premium', // string
amount: 99.99, // number
is_upgrade: true, // boolean
}Tag Naming
Use snake_case for tag names:
plan_name,user_type,error_code- Not:
PlanName,planName,ERROR-CODE
Server-Side Tag Enrichment
The Kitbase backend automatically enriches every event with additional context derived from the request. These enriched fields are prefixed with __ and stored as dedicated columns, available as first-class filter dimensions in the dashboard.
Browser and Device
| Tag | Description |
|---|---|
__browser | Browser name (Chrome, Firefox, Safari) |
__browser_version | Browser version |
__os | Operating system (Windows, macOS, iOS) |
__os_version | OS version |
__device | Device type (desktop, mobile, tablet) |
__brand | Device brand (Apple, Samsung, Google) |
__model | Device model (iPhone 15, Pixel 8) |
Geolocation
| Tag | Description |
|---|---|
__country | Country (derived from IP) |
__region | Region or state |
__city | City |
Page and Attribution
| Tag | Description |
|---|---|
__path | Page path |
__referrer | Referrer URL |
__utm_source | UTM source parameter |
__utm_medium | UTM medium parameter |
__utm_campaign | UTM campaign parameter |
__utm_term | UTM term parameter |
__utm_content | UTM content parameter |
Query Filters
These enriched fields are available as filter dimensions in the dashboard. Filter events by browser, country, device, UTM parameters, and more directly from the events list.
Notifications
When notify: true is set, the event triggers a real-time notification in the Kitbase dashboard. Combine with icon and description to make notifications informative at a glance.
await kitbase.track({
channel: 'payments',
event: 'Large Purchase',
icon: '💰',
notify: true,
description: 'A customer just made a $500+ purchase',
tags: { amount: 549.99 }
});Good candidates for notifications:
- New signups and subscriptions
- Failed payments and billing issues
- Critical application errors
- Security events (login from new device)
- Large or unusual transactions
Revenue Tracking
Track revenue with the dedicated trackRevenue method. Revenue events are automatically sent to the __analytics channel.
await kitbase.trackRevenue({
amount: 99.99,
currency: 'USD',
orderId: 'order_123',
productId: 'prod_premium',
tags: { plan: 'premium' }
});This provides structured revenue data in the dashboard, separate from general custom events, so you can track MRR, ARPU, and other financial metrics out of the box.
Timed Events
Measure how long user flows take by starting a timer and letting the SDK automatically attach the duration when the event is tracked.
// Start timing
kitbase.timeEvent('Checkout Flow');
// ... user completes checkout ...
// Track with automatic $duration tag (in milliseconds)
await kitbase.track({
channel: 'conversions',
event: 'Checkout Flow',
tags: { items: 3 }
});
// The $duration tag is automatically added to the eventMethods
| Method | Description |
|---|---|
timeEvent(eventName) | Start timing an event |
cancelTimeEvent(eventName) | Cancel a timed event without tracking |
getTimedEvents() | Get list of event names currently being timed |
getEventDuration(eventName) | Get current elapsed duration in milliseconds |
Example
// Check active timers
const activeTimers = kitbase.getTimedEvents();
// => ['Checkout Flow', 'Video Watched']
// Get duration without tracking
const duration = kitbase.getEventDuration('Checkout Flow');
// => 45000 (ms)
// Cancel a timer
kitbase.cancelTimeEvent('Video Watched');Super Properties
Super properties are automatically included with every event you track. They are useful for attaching persistent context like app version, environment, or user segment.
// Register properties (overwrites existing)
kitbase.register({ app_version: '2.1.0', environment: 'production' });
// Register only if not already set
kitbase.registerOnce({ first_visit_source: 'google' });
// Remove a specific super property
kitbase.unregister('first_visit_source');
// Get all registered super properties
kitbase.getSuperProperties();
// Clear all super properties
kitbase.clearSuperProperties();Methods
| Method | Description |
|---|---|
register(properties) | Set properties (overwrites existing) |
registerOnce(properties) | Set properties only if not already set |
unregister(key) | Remove a specific property |
getSuperProperties() | Get all registered properties |
clearSuperProperties() | Remove all super properties |
In-Memory Storage
Super properties are stored in memory and reset on page reload. For persistent properties, store them externally (e.g., localStorage) and call register() on initialization.
Data Attribute Events
Track events declaratively from HTML without writing JavaScript. The SDK automatically binds event listeners based on data-kb-* attributes.
Click Tracking
<button
data-kb-track-click="Add to Cart"
data-kb-click-channel="ecommerce"
>
Add to Cart
</button>When the button is clicked, an event named "Add to Cart" is tracked on the "ecommerce" channel.
Visibility Tracking
<section
data-kb-track-visibility="Pricing Section Viewed"
data-kb-visibility-channel="marketing"
data-kb-visibility-threshold="0.75"
>
<!-- content -->
</section>When 75% of the section becomes visible in the viewport, an event named "Pricing Section Viewed" is tracked on the "marketing" channel.
Error Handling
The SDK provides typed error classes so you can handle specific failure modes precisely.
import {
AuthenticationError,
ValidationError,
TimeoutError,
ApiError,
KitbaseError
} from '@kitbase/analytics';
try {
await kitbase.track({ channel: 'payments', event: 'Purchase' });
} catch (error) {
if (error instanceof AuthenticationError) {
// 401: Invalid or missing API key
} else if (error instanceof ValidationError) {
// 400/422: Missing or invalid fields - check error.field
} else if (error instanceof TimeoutError) {
// Request timed out (default: 30s)
} else if (error instanceof ApiError) {
// Other API error - check error.statusCode and error.response
} else if (error instanceof KitbaseError) {
// Generic SDK error
}
}| Error | HTTP Status | Description |
|---|---|---|
AuthenticationError | 401 | Invalid or missing API key |
ValidationError | 400/422 | Missing or invalid required fields |
TimeoutError | -- | Request exceeded 30s timeout |
ApiError | 4xx/5xx | API returned an error response |
For detailed error handling patterns including retry logic and best practices, see Error Handling.
REST API
You can send events directly to the Kitbase REST API without the SDK. This is useful for server-side integrations or languages without an official SDK.
Single Event
curl -X POST https://api.kitbase.dev/sdk/v1/logs \
-H "X-API-Key: YOUR_SDK_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": "Purchase Completed",
"properties": {
"channel": "payments",
"tags": { "amount": 99.99 }
}
}'Response (202 Accepted):
{
"id": "evt_abc123",
"event": "Purchase Completed",
"timestamp": "2026-02-13T12:00:00.000Z"
}Batch Events
Send multiple events in a single request for better performance:
POST /sdk/v1/logs/batchRequest body:
{
"events": [
{
"event": "Page Viewed",
"properties": { "channel": "analytics", "tags": { "path": "/pricing" } }
},
{
"event": "CTA Clicked",
"properties": { "channel": "conversions", "tags": { "button": "signup" } }
}
]
}Response (202 Accepted):
{
"accepted": 2,
"total": 2
}The batch endpoint accepts an array of events and returns the count of accepted events vs. total submitted.