@cognivo/analytics
Opt-in, zero-dependency telemetry for Cognivo components. Captures 243 known cg-*, ai-*, and bias-* custom events, sanitizes the payload, and routes to one of four pluggable sinks. Does nothing until enableAnalytics() is called.
Installation
pnpm add @cognivo/analytics Quick start
import { enableAnalytics, consoleSink } from '@cognivo/analytics';
const dispose = enableAnalytics({ sink: consoleSink });
// …later, when the app unmounts:
dispose(); Every Cognivo custom event bubbling to window is now logged. No listeners are attached and no data is captured until you call enableAnalytics.
API Reference
| Export | Description |
|---|---|
enableAnalytics(config) | Start capture. Returns a disposer that removes every listener. |
disableAnalytics() | Tear down capture. Idempotent. |
extendEventRegistry(events) | Add consumer-defined event names to the runtime registry. |
getSessionId() | Stable anonymous session id for the page lifetime. |
sanitizeDetail(detail) | Privacy filter — truncates long strings, caps nesting depth at 2, drops functions and symbols. |
KNOWN_EVENTS | Readonly registry of all 243 Cognivo event names. |
createMatcher(patterns) | Glob matcher for tag / event filtering ('bias-*', 'ai-thinking-*'). |
consoleSink, fetchSink, batchSink, localStorageSink | Built-in sinks. See Configuration below. |
The AnalyticsEvent shape
interface AnalyticsEvent {
timestamp: string; // ISO-8601 UTC
component: string; // e.g. 'cg-button'
event: string; // e.g. 'cg-button-click'
detail: Record<string, unknown>; // sanitized shallow payload
page: string; // pathname, or full href if includeUrlQuery
sessionId: string; // anonymous, stable per page load
} Configuration
enableAnalytics({
sink: consoleSink,
trackComponents: ['cg-button', 'bias-*'], // default: ['cg-*','ai-*','bias-*']
trackEvents: ['cg-button-click'], // default: all registered
sampleRate: 0.25, // default: 1
includeUrlQuery: false, // default: false
anonymizeDetail: true, // default: true
}); Built-in sinks
consoleSink — dev logging
import { enableAnalytics, consoleSink } from '@cognivo/analytics';
enableAnalytics({ sink: consoleSink }); fetchSink — fire-and-forget POST
import { enableAnalytics, fetchSink } from '@cognivo/analytics';
enableAnalytics({ sink: fetchSink('/api/events') }); batchSink — buffered, flushes on pagehide
import { enableAnalytics, batchSink } from '@cognivo/analytics';
enableAnalytics({
sink: batchSink('/api/events', { batchSize: 20, flushMs: 5000 }),
});
// Uses navigator.sendBeacon when the page unloads. localStorageSink — persist locally
import { enableAnalytics, localStorageSink } from '@cognivo/analytics';
enableAnalytics({ sink: localStorageSink('cognivo:events') });
// Trimmed to the last 500 events. Use cases
Funnel events from a pricing page
enableAnalytics({
sink: fetchSink('/api/events'),
trackComponents: ['cg-button', 'bias-anchoring', 'bias-scarcity'],
}); Custom sink — route to your own collector
import { enableAnalytics, type AnalyticsEvent } from '@cognivo/analytics';
function mySink(ev: AnalyticsEvent) {
window.myCollector?.push({ t: ev.timestamp, e: ev.event, p: ev.page });
}
enableAnalytics({ sink: mySink }); Extend the event registry
import { enableAnalytics, extendEventRegistry, consoleSink } from '@cognivo/analytics';
extendEventRegistry(['cg-mycustom-ready', 'cg-mycustom-error']);
enableAnalytics({ sink: consoleSink }); Caveats
- Opt-in, always. Importing the package has no side effects — capture only starts after
enableAnalytics(). - Privacy defaults. Only the pathname is captured (not query or hash). Strings over 40 chars are truncated. Nested objects are dropped beyond depth 2. Functions, symbols, and
bigintvalues are dropped. - No PII inference. There is no fingerprinting, IP capture, or cookie — just a random session id per page load.
- Sink errors are swallowed. A throwing sink is warned once to the console and never interrupts capture.
- Single active capture. Calling
enableAnalytics()twice replaces the previous configuration.