Skip to content

Browser SDK

The core entry of @syntarie/tracking exposes everything you need for pageview, custom events, identification, consent, and identity reads. The auto-capture features (Web Vitals, errors, clicks, scroll depth, engaged time) live under their own subpaths.

import { init } from '@syntarie/tracking';
init({
siteId: 'site_marketing',
host: 'https://collect.example.com',
// optional:
sessionTimeout: 30 * 60 * 1000,
respectDnt: true,
mode: 'cookied',
defaultConsent: 'unknown',
sampling: { mousemove: 0.1 },
});
FieldTypeDefaultNotes
siteIdstringrequiredIssued by your Leatsmap deployment. Throws on empty.
hoststringrequiredCollector origin (scheme + host). Throws on empty.
sessionTimeoutnumber30 * 60 * 1000ms. Negative / non-finite values clamp silently.
respectDntbooleantrueWhen true, a DNT-blocked init never installs listeners.
mode'cookied' | 'cookieless''cookied'Cookieless uses a daily-rotating fingerprint.
defaultConsent'unknown' | 'granted''unknown'Pass 'granted' if you obtained consent before bootstrap.
samplingRecord<string, number>{}Per-event-type rates in [0, 1].

Calling init more than once is a no-op for the second call onward.

import { track } from '@syntarie/tracking';
track('checkout_completed', {
order_id: 'ord_42',
total_cents: 4900,
currency: 'USD',
});

name becomes the wire type discriminator. props is sanitized (string clamp, function / symbol drop) before queuing. Empty name is dropped silently. Calls before init are dropped.

For type-safe track() calls narrowed to your tracking plan, see TypeScript codegen.

import { identify } from '@syntarie/tracking';
identify('user_42', { plan: 'pro' });

Binds the current anon_id to a known user_id. If a different user_id was previously stored, Leatsmap emits a merge event before the new identify so cross-device timelines stay consistent. Empty / non-string userId produces a console.warn and is otherwise a no-op (the SDK never throws from public surfaces inside the host page).

init() records the first pageview automatically and listens for SPA navigation (pushState / replaceState / popstate). You do not need to call pageview() manually in 99 % of apps. If your router uses a non-history mechanism, call captureContext(url) followed by your custom emit.

import { grantConsent, revokeConsent, getConsentState } from '@syntarie/tracking';
grantConsent(); // optional: pass a token attached as X-Consent on every request
revokeConsent(); // purges the in-memory queue immediately
getConsentState(); // 'unknown' | 'granted' | 'revoked'

While consent is 'unknown' (the default), events queue in memory but no network request goes out. grantConsent() drains the queued events. revokeConsent() empties the queue and makes every subsequent send a no-op for the rest of the page lifetime.

See Consent gating for the server-side enforcement.

import { getUserId, getAnonId, getSessionId } from '@syntarie/tracking';
getUserId(); // string | null — null if identify() never ran
getAnonId(); // string — UUID in cookied mode, daily fingerprint in cookieless mode
getSessionId(); // string — mints a new session id if the inactivity window has lapsed

getSessionId() extends lastActiveTs as a side effect.

import { captureContext, getCurrentContext } from '@syntarie/tracking';
captureContext('https://example.com/pricing');
// returns: { utm, referrer, viewport, screen, language, timezone, ua }
getCurrentContext(); // EventContext | null

captureContext is called automatically on every pageview; you only need to call it manually if you are wiring your own custom navigation hook.

import type {
InitOptions,
TrackingEvent,
ConsentState,
} from '@syntarie/tracking';

TrackingEvent is exported only for type narrowing in adjacent modules (e.g. the errors and engaged-time subpath signatures). Customers do not construct TrackingEvent instances directly.

The SDK exports send, getConfig, and getQueueForTests from the core entry for use by the opt-in subpaths. They are not part of the contract — do not import them in production code. Test seams (__resetForTests, __resetConsentForTests, __resetIdentifyForTests, etc.) are private.