@clickstream/sdk/core
The core tracker is a ruthlessly-scoped subset of IdentityTracker for consumers who need the smallest possible footprint. 2.01 KB gzipped minified. The bundle is served through your own first-party tracking domain — register your CNAME once and the dashboard mints the URL for you.
What's in
- First-party visitor id via
_cs_uidcookie (365-day sliding expiry,samesite=lax). - Session id via
_cs_sidcookie (30-minute idle expiry). - Pageview on init + SPA route changes (listens for
popstate, plus monkey-patcheshistory.pushState/history.replaceState). - Click auto-capture for
<button>,<a>,[role="button"], and[data-track]elements. - Custom events via
tracker.trackEvent({ name }). - Batched flush every 5 s + on
visibilitychange/pagehideviasendBeacon, withfetch+keepalivefallback. - At-most-once retry queue that re-inserts a failed batch on fetch error.
destroy()tears down every listener + clears timers.
What's out
- Identity resolution (HEM / phone / customer_id / click-id attribution).
- Session replay frames.
- Consent banner + CMP detection.
- Device fingerprinting, GPU probes, timezone capture.
- PII encryption wiring.
- 8 behavioral trackers (hover intent, clipboard, text selection, scroll regression, mouse dynamics, CTA proximity, form-field intelligence, tab visibility).
- Cross-subdomain cookie sharing.
- Universal form-fill capture.
If you need any of the above, import from @clickstream/sdk instead. The trackEvent / trackPageview signatures are drop-in compatible, so moving between tiers is a one-line import change.
Install
pnpm add @clickstream/sdk
import { IdentityTrackerCore } from '@clickstream/sdk/core';
const tracker = new IdentityTrackerCore({
apiKey: 'cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
endpoint: 'https://t.example.com',
});
tracker.init();
tracker.trackEvent({ name: 'signup_clicked' });
The endpoint option is required — point it at your first-party tracking domain. The collector rejects events sent to an unregistered hostname with 403 domain_not_allowed.
API
new IdentityTrackerCore(config)
| Option | Type | Default | Notes |
|---|---|---|---|
apiKey | string | required | Your ClickStream API key. |
endpoint | string | required in practice | Your first-party tracking domain. |
debug | boolean | false | Log flush failures to the console. |
batchSize | number | 25 | Max events per batch before auto-flush. |
flushIntervalMs | number | 5000 | Background flush cadence. |
sessionIdleMs | number | 1_800_000 | Session cookie sliding expiry. 30 min. |
Throws if apiKey is missing.
tracker.init(): void
Attaches DOM listeners, starts the flush timer, fires the initial pageview. Idempotent — calling twice is a no-op.
tracker.trackEvent({ name: string }): void
Enqueues a custom event. name is truncated to 128 characters. Safe to call before init() — events queue up and flush on the first timer tick.
tracker.trackPageview(): void
Enqueues a pageview. Called automatically on SPA route changes; call manually if you need to re-emit for a custom navigation pattern.
tracker.flush(): Promise<void>
Flushes the event queue right now. Resolves after the HTTP round-trip settles (or fails silently — failed batches re-enter the queue).
tracker.getVisitorId(): string
Returns the current _cs_uid cookie value. Stable across sessions on the same browser.
tracker.getSessionId(): string
Returns the current _cs_sid cookie value. Rotates after 30 min of inactivity.
tracker.destroy(): void
Tears down every listener + clears the flush timer. Useful in SPA frameworks that unmount a provider (React strict mode, Next.js route transitions that detach the tree). Idempotent.
What the collector sees
The core tracker POSTs batches to /v1/events on your first-party domain. Each event has this shape (matches the full event schema subset for pageview / click / custom):
{
"type": "pageview",
"visitorId": "vis_3f9a…",
"sessionId": "sess_2b1e…",
"timestamp": 1713797640000,
"page": {
"url": "https://example.com/pricing",
"path": "/pricing",
"title": "Pricing",
"referrer": "https://google.com/"
},
"device": {
"userAgent": "Mozilla/5.0 …",
"viewport": { "width": 1280, "height": 800 }
}
}
The collector validates with the same Zod schema used by the full SDK. No server-side differentiation between core and full events.
Upgrading to the full SDK
When you need identity resolution, replay, consent, or the behavioral trackers, change one line:
- import { IdentityTrackerCore } from '@clickstream/sdk/core';
+ import { IdentityTracker } from '@clickstream/sdk';
- const tracker = new IdentityTrackerCore({ apiKey, endpoint });
+ const tracker = new IdentityTracker({ apiKey, endpoint });
trackEvent / trackPageview / getVisitorId / getSessionId / destroy have the same signatures on both classes. The full SDK adds identify(), enableFollowMeTracking(), the interaction-tracker config surface, and the consent-gate API — none of which are present on core.
See also
- Install — full install matrix including core.
- Event schema — exact event shape the collector records.
- First-party tracking — required CNAME + SSL provisioning.