Skip to main content

Tracking SDK

The OmniSocial Tracking SDK is a lightweight client-side JavaScript library that captures user events and sends them to the server-side tracking pipeline. It is built as a standalone package at packages/tracking-sdk/.


Architecture​

The SDK is composed of five modules, each with a single responsibility:


Modules​

Core (core.ts)​

The core module provides the omni() function and manages the command queue.

Responsibilities:

  • Expose the global omni() function that accepts commands
  • Process queued commands from the IIFE snippet loader (omni.q)
  • Route commands to the appropriate handler: init, track, identify, consent
  • Maintain SDK state: pixel ID, API key, session ID, customer identity

Key internals:

type OmniCommand = 'init' | 'track' | 'identify' | 'consent';

interface SdkState {
pixelId: string;
apiKey: string;
sessionId: string;
identity: HashedIdentity | null;
consentGranted: boolean;
initialized: boolean;
}

On init, the core module:

  1. Stores the pixel ID and API key
  2. Generates or retrieves a session ID from cookies
  3. Captures UTM parameters and click IDs from the URL
  4. Flushes any pre-init queued commands

Hash (hash.ts)​

Handles SHA-256 hashing of personally identifiable information before it leaves the browser.

Hashed fields:

FieldInput NormalizationHashing
emailLowercase, trim whitespaceSHA-256 hex
phoneRemove spaces, dashes, parentheses; ensure + prefixSHA-256 hex
firstNameLowercase, trimSHA-256 hex
lastNameLowercase, trimSHA-256 hex

Implementation:

async function hashValue(value: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(value.trim().toLowerCase());
const buffer = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(buffer))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}

Uses the Web Crypto API (crypto.subtle) which is available in all modern browsers. No external dependencies required.

Cookies (cookies.ts)​

Manages first-party cookies for identity persistence and click ID storage.

Cookies managed:

CookieContentMax AgePurpose
_omni_idHashed visitor ID365 daysCross-session identity
_omni_sessSession ID30 minutes (sliding)Session tracking
_omni_fbclidFacebook click ID7 daysMeta CAPI attribution
_omni_gclidGoogle click ID90 daysGoogle Ads attribution
_omni_ttclidTikTok click ID7 daysTikTok attribution
_omni_utmJSON-encoded UTM paramsSessionCampaign attribution

Cookie attributes:

  • SameSite=Lax -- Allows cookies on top-level navigations but blocks cross-site subrequests
  • Secure -- Set only on HTTPS origins
  • Path=/ -- Available across all pages on the domain

Transport (transport.ts)​

Handles event delivery to the server with automatic fallback.

Delivery strategy:

  1. Primary: Beacon API -- Uses navigator.sendBeacon() for fire-and-forget delivery. Reliable even during page unload events.
  2. Fallback: XHR -- Falls back to XMLHttpRequest if Beacon is unavailable or if the payload exceeds the Beacon size limit (64 KB).
  3. Retry -- Failed XHR requests are retried up to 2 times with exponential backoff (1s, 3s).

Request format:

The shape below is out of date. The SDK actually sends POST /api/v1/tracking/ingest (or /batch) with a snake-case body: pixel_id, api_key, event_name, event_id, event_time, action_source, source_url, user_data (hashed), custom_data. Unload flushes use sendBeacon with text/plain. The default endpoint is https://api.unipulse.tech/api/v1/tracking/ingest. event_id defaults to purchase:<order_id> for a Purchase, otherwise a UUID, and track() returns it.

POST /tracking/events
Content-Type: application/json
x-api-key: {apiKey}

{
"pixelId": "px_abc123",
"eventName": "Purchase",
"eventId": "evt_unique_id",
"eventData": { "value": 49.99, "currency": "USD" },
"sourceUrl": "https://example.com/checkout/success",
"sessionId": "sess_xyz",
"identity": { "em": "a1b2c3...", "ph": "d4e5f6..." },
"utm": { "source": "facebook", "medium": "cpc", "campaign": "summer" },
"clickIds": { "fbclid": "abc123" },
"userAgent": "Mozilla/5.0...",
"timestamp": 1741392000000
}

Implements GDPR-compliant consent management.

Behavior:

StateTrackingEvent Queue
Consent not setBlockedEvents are queued in memory
omni('consent', true)ActiveQueued events are flushed, new events fire immediately
omni('consent', false)BlockedQueue is cleared, no events are sent

Integration with CMP:

The SDK does not include a consent banner. It is designed to work with any Consent Management Platform (CMP). Call omni('consent', true) from your CMP's callback when the user grants tracking consent.

// Example: integration with a generic CMP
myCMP.onConsentGranted(() => {
omni('consent', true);
});

Build Configuration​

The SDK is built using tsup (esbuild-based bundler) with three output formats:

FormatEntryOutputUse Case
IIFEsrc/iife.tsdist/omni.min.jsScript tag installation
ESMsrc/index.tsdist/index.mjsModern bundlers (Vite, webpack 5)
CJSsrc/index.tsdist/index.cjsNode.js / SSR environments

Size Budget​

TargetLimitMeasured
IIFE (gzipped)< 4 KB~3.2 KB
ESM (gzipped)< 3 KB~2.8 KB
warning

The SDK must remain dependency-free to stay under the size budget. Do not add external packages. All functionality (hashing, cookies, transport) is implemented using browser-native APIs.


API Reference​

omni('init', pixelId, options)​

Initialize the SDK. Must be called before any other command.

ParameterTypeRequiredDescription
pixelIdstringYesThe tracking pixel ID
options.apiKeystringYesThe pixel API key
options.autoPageViewbooleanNoAutomatically track PageView on init (default: true)
options.cookieDomainstringNoOverride the cookie domain (default: current domain)

omni('track', eventName, eventData?)​

Track a custom event.

ParameterTypeRequiredDescription
eventNamestringYesEvent name (e.g., Purchase, AddToCart)
eventDataobjectNoArbitrary key-value pairs

Common events:

EventRequired DataOptional Data
PageView--title, referrer
ViewContentcontent_idcontent_name, content_type
AddToCartproduct_id, value, currencyquantity, product_name
InitiateCheckoutvalue, currencyitem_count
Purchaseorder_id, value, currencyitems[], coupon
Lead--lead_type, value

omni('identify', traits)​

Identify the current user. Traits are hashed before transmission.

ParameterTypeRequiredDescription
traits.emailstringNoUser email (hashed to SHA-256)
traits.phonestringNoUser phone (hashed to SHA-256)
traits.externalIdstringNoYour internal user ID

omni('consent', granted)​

Set tracking consent.

ParameterTypeRequiredDescription
grantedbooleanYestrue to enable tracking, false to disable

Testing Locally​

To build and test the SDK during development:

cd packages/tracking-sdk
npm run build # Build all formats
npm run dev # Watch mode with hot reload
npm run size # Check bundle size against budget

To test against the local API:

omni('init', {
pixelId: 'tp_xxxxxxxxxxxxxxxx',
apiKey: 'test_key',
endpoint: 'http://localhost:3001/api/v1/tracking/ingest', // Override for local dev
});

Cross-Reference