@capcons/analytics
v0.1.5
Published
Isomorphic Capcons analytics SDK for event tracking
Maintainers
Readme
@capcons/analytics
Isomorphic analytics SDK for Capcons storefronts, GoKwik checkout, server events, and ClickHouse-backed dashboards.
Principles
appIdis the Capcons circle ID.- Stable
snake_caseevent names; dynamic values never enter event names. - Flat, bounded event properties for predictable ClickHouse paths.
- Money uses
<field>_amountplus an explicit currency field. - Identity, session, page, device, and consent use the event envelope.
- Raw email, phone, address, password, cookie, and token fields are removed.
- Order APIs remain financial truth; SDK events describe behavior and funnels.
Install
bun add @capcons/analyticsBrowser setup
import { initBrowserAnalytics } from "@capcons/analytics/browser";
const trackEvent = initBrowserAnalytics({
appId: circleId,
autoTrack: { pageViews: true, clicks: false },
consent: { analytics: true },
});Browser entry creates stable anonymous/session IDs, captures page/device/UTM context, queues events in local storage, flushes every five seconds, and flushes on pagehide.
Call setIdentity after login:
import { getBrowserAnalytics } from "@capcons/analytics/browser";
getBrowserAnalytics()?.setIdentity({ user_id: user.id });Never pass raw email or phone as identity. Hash externally when needed, then use email_hash or phone_hash.
Flat properties
Callers may pass real application objects. SDK normalizes them before delivery:
trackEvent("cart_updated", {
cart: { cartId: "cart_1", totalAmount: 4999, currency: "INR" },
campaign: { utmSource: "meta", utmCampaign: "summer" },
});Delivered data:
{
"cart_cart_id": "cart_1",
"cart_total_amount": 4999,
"cart_currency": "INR",
"campaign_utm_source": "meta",
"campaign_utm_campaign": "summer"
}Limits default to four levels, 100 properties, 2,048 characters per string, and 100 array values. Configure through normalization only when collector schema supports larger payloads.
Typed commerce events
import { createEcommerceAnalytics } from "@capcons/analytics/ecommerce";
const commerce = createEcommerceAnalytics(trackEvent);
commerce.productAddedToCart({
product: {
product_id: "product_1",
title: "Trail Boot",
category: ["men", "boots"],
},
variant: {
variant_id: "variant_1",
sku: "BOOT-9",
size: "9",
color: "brown",
price: { amount: 4999, currency: "INR" },
},
cart_line: { quantity: 1 },
cart: {
cart_id: "cart_1",
total: { amount: 4999, currency: "INR" },
},
});Commerce helper produces stable keys such as product_id, variant_id, variant_sku, cart_total_amount, and cart_total_currency. Purchase item objects become aligned arrays such as item_product_ids, item_variant_ids, item_price_amounts, and item_quantities.
GoKwik integration
SDK contains every GoKwik event name currently observed in Teddyboy and maps them to canonical Capcons events.
import {
createGoKwikAnalytics,
GOKWIK_EVENTS,
} from "@capcons/analytics/gokwik";
const gokwikAnalytics = createGoKwikAnalytics(trackEvent);
for (const eventName of Object.values(GOKWIK_EVENTS)) {
window.gokwikSdk.on(eventName, (payload: unknown) => {
gokwikAnalytics.track(eventName, payload);
});
}kwikpass-sso may arrive as a DOM event instead of an SDK event. Pass it to the same adapter. Token data is removed.
GoKwik mapping covers checkout readiness/failure/close, login and OTP, address steps, coupon, gift card, wallet, payment method/failure/completion, order creation/completion, and KwikPass page views. Raw provider name remains in provider_event; dashboards query canonical event_type.
Server setup
import { createAnalyticsEventClient } from "@capcons/analytics/node";
import { createEcommerceAnalytics } from "@capcons/analytics/ecommerce";
const client = createAnalyticsEventClient({ appId: circleId });
const commerce = createEcommerceAnalytics(client.track);
commerce.orderDelivered({
order: { order_id: "order_1", total: { amount: 4999, currency: "INR" } },
});
await client.shutdown();Use server events for order fulfilment, shipping, delivery, return, and refund lifecycle. Browser cannot know these outcomes reliably.
Delivery
Default transport sends one event payload per request because current Capcons endpoint accepts a single event.
initBrowserAnalytics({
appId: circleId,
transportMode: "single",
});Enable batch only after collector accepts { "events": [...] }:
initBrowserAnalytics({
appId: circleId,
transportMode: "batch",
batchSize: 20,
});Collector should perform idempotent inserts using event_id, batch ClickHouse writes, enable asynchronous inserts with acknowledgements, and keep raw events append-only.
Consent
When consent.analytics is explicitly false, event is rejected, pending browser queue is cleared, and nothing is delivered. Undefined consent remains application-controlled for backward compatibility.
Commands
bun run typecheck
bun run build
bun run test
bun run pack:drySee docs/USAGE.md for complete event contract and collector guidance.
