@slnka/web
v1.0.0-beta.17
Published
SLNKA Web SDK — Client-side analytics, deep linking, and attribution (CNDP compliant)
Downloads
29
Maintainers
Readme
@slnka/web
Lightweight client-side event tracking SDK for SLNK.
- Zero production dependencies - everything hand-rolled
- < 15 KB gzip - smaller than Mixpanel (36 KB), Amplitude (37 KB), Segment (25 KB)
- GDPR + CNDP compliant by default - no tracking without explicit consent
- Offline resilient - localStorage queue for failed sends
- TypeScript first - full type exports, tree-shakeable ESM
Installation
npm / yarn / pnpm
npm install @slnka/web
# or
yarn add @slnka/web
# or
pnpm add @slnka/webNo authentication or registry config needed — @slnka/web is published on the public npm registry.
CDN (script tag)
<script src="https://cdn.slnka.ma/sdk/slnka.umd.js"></script>
<script>
slnka.configure('lsk_live_your_api_key', {
serverUrl: 'https://api.slnka.ma',
workspaceId: 'ws_abc123',
});
</script>Quick Start
import slnka from '@slnka/web';
// 1. Configure
slnka.configure('lsk_live_your_api_key', {
serverUrl: 'https://api.slnka.ma',
workspaceId: 'ws_abc123',
});
// 2. Grant consent (required by default — privacy-first mode)
slnka.optIn();
// 3. Track events
slnka.track('button_click', { buttonId: 'cta-hero' });
slnka.page();
slnka.identify('user_123', { plan: 'pro' });API Reference
slnka.configure(apiKey, config)
Configures the SDK. Must be called before any other method.
slnka.configure('lsk_live_your_api_key', {
serverUrl: 'https://your-instance.slnka.ma', // Required
workspaceId: 'ws_abc123',
flushInterval: 5000,
flushSize: 10,
persistence: 'cookie',
respectDnt: true,
respectGpc: true,
requireConsent: true,
queueBeforeConsent: true,
debug: false,
cookieExpiry: 365,
sessionTimeout: 30,
});The apiKey can optionally embed the workspace ID: 'lsk_live_abc123:ws_def456'.
slnka.track(eventName, properties?)
Tracks a custom event.
slnka.track('purchase_completed', {
product: 'Pro Plan',
amount: 49.99,
currency: 'MAD',
});Each event is automatically enriched with:
eventId(UUIDv4)anonymousIduserId(if identified)sessionIdtimestamp(ISO 8601 UTC)context(page URL, referrer, user agent, screen, locale, timezone)
slnka.page(properties?)
Tracks a page view ($page_view event). Page URL, path, title, and referrer are auto-collected.
slnka.page({ section: 'pricing' });slnka.identify(userId, traits?)
Links the current anonymous ID to a known user. Sends a $identify event.
slnka.identify('user_123', {
email: '[email protected]',
plan: 'professional',
company: 'Acme Corp',
});slnka.reset()
Generates a new anonymous ID, clears the user ID, and starts a fresh session. Use on logout.
slnka.reset();slnka.flush()
Manually flushes all queued events. Returns a Promise.
await slnka.flush();slnka.getAnonymousId()
Returns the current anonymous ID.
slnka.getUserId()
Returns the current user ID (or null if not identified).
slnka.setDebug(enabled)
Enables or disables debug logging to the browser console.
slnka.setDebug(true); // See all SDK activity in consoleConsent Management
The SDK is GDPR + CNDP compliant by default: no cookies are written and no events are sent until the user explicitly grants consent.
slnka.optIn(category?)
Grants consent. Without a category argument, grants all categories.
// Grant all categories
slnka.optIn();
// Grant a specific category
slnka.optIn('analytics');When analytics consent is granted, any events tracked before consent (the "pre-consent queue") are automatically flushed.
slnka.optOut(category?)
Revokes consent. Purges the event queue and deletes all SDK cookies/storage.
slnka.optOut();slnka.getConsentState()
Returns the current consent state for all categories.
const state = slnka.getConsentState();
// { analytics: 'granted', marketing: 'pending', functional: 'granted' }Consent Categories
| Category | Purpose |
|----------|---------|
| analytics | Event tracking, page views, user behavior |
| marketing | Campaign attribution, cross-site tracking |
| functional | Feature flags, A/B testing, personalization |
Consent States
| State | Behavior |
|-------|----------|
| pending | Events queued in memory (not sent, no cookies) |
| granted | Events sent, cookies written |
| denied | Events dropped, cookies/storage purged |
Browser Privacy Signals
The SDK respects:
- Do Not Track (DNT):
navigator.doNotTrack === '1'- consent auto-denied - Global Privacy Control (GPC):
navigator.globalPrivacyControl === true- consent auto-denied
Disable with respectDnt: false and/or respectGpc: false.
Privacy Compliance (GDPR + CNDP)
SLNK is designed for compliance with EU GDPR (Regulation 2016/679) and Morocco's CNDP Law 09-08 (Commission Nationale de contrôle de la protection des Données à caractère Personnel). The same technical mechanisms satisfy both frameworks:
- No tracking without consent -
requireConsent: trueis the default. - No cookies before consent - Anonymous ID is held in memory until
optIn(). - Pre-consent queue - Events tracked before consent are buffered in memory (not localStorage) and flushed only after
optIn(). - Full data purge on opt-out -
optOut()deletes all cookies, localStorage entries, and queued events. - DNT and GPC respected - Browser-level privacy signals are honored.
- No raw IP storage - IP hashing happens server-side (SHA-256 + daily salt).
- First-party cookies only -
SameSite=Lax,Secure, on your domain.
Cookie Banner Integration
// Configure SDK (no cookies yet)
slnka.configure('lsk_live_your_api_key', {
serverUrl: 'https://api.slnka.ma',
workspaceId: 'ws_abc123',
});
// Events are tracked but queued in memory
slnka.page();
slnka.track('page_scroll', { depth: 50 });
// User clicks "Accept" on your cookie banner
document.getElementById('accept-cookies').addEventListener('click', () => {
slnka.optIn(); // Flushes all queued events, writes cookies
});
// User clicks "Reject"
document.getElementById('reject-cookies').addEventListener('click', () => {
slnka.optOut(); // Purges everything
});Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| serverUrl | string | Required | Analytics API base URL (e.g., 'https://api.slnka.ma') |
| workspaceId | string | '' | Workspace ID (can embed in apiKey) |
| flushInterval | number | 5000 | Auto-flush interval in ms |
| flushSize | number | 10 | Max buffer size before auto-flush |
| persistence | 'cookie' \| 'localStorage' \| 'memory' | 'cookie' | Where to persist anonymous ID |
| respectDnt | boolean | true | Respect Do Not Track header |
| respectGpc | boolean | true | Respect Global Privacy Control |
| requireConsent | boolean | true | Require explicit consent |
| queueBeforeConsent | boolean | true | Queue events before consent |
| debug | boolean | false | Console debug logging |
| cookieDomain | string | auto-detected | Cookie domain |
| cookieExpiry | number | 365 | Cookie expiry in days |
| sessionTimeout | number | 30 | Session timeout in minutes |
Event Payload
Every event sent to the backend has this shape:
{
"eventName": "button_click",
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"anonymousId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"userId": "user_123",
"properties": {
"buttonId": "cta-hero"
},
"context": {
"page": {
"url": "https://example.com/pricing",
"path": "/pricing",
"title": "Pricing - Example",
"referrer": "https://google.com"
},
"browser": {
"userAgent": "Mozilla/5.0 ...",
"language": "fr-MA"
},
"screen": {
"width": 1920,
"height": 1080
},
"locale": "fr-MA",
"timezone": "Africa/Casablanca"
},
"timestamp": "2026-03-15T14:30:00.000Z",
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Events are batched and sent to POST /api/v1/sdk/events/batch.
Advanced Usage
Multiple Instances
import { SlnkaClient } from '@slnka/web';
const tracker1 = new SlnkaClient();
tracker1.configure('lsk_live_project_a', {
serverUrl: 'https://api.slnka.ma',
workspaceId: 'ws_a',
});
const tracker2 = new SlnkaClient();
tracker2.configure('lsk_live_project_b', {
serverUrl: 'https://api.slnka.ma',
workspaceId: 'ws_b',
});Server-Side Rendering (SSR)
The SDK gracefully handles SSR environments where window, document, and navigator are unavailable. Context fields will be empty strings and storage falls back to in-memory.
Offline Support
When network requests fail, events are automatically persisted to localStorage (key: __slnka_queue). On the next page load, persisted events are restored and retried.
Storage Keys
| Key | Storage | Purpose |
|-----|---------|---------|
| __slnka_anon | cookie / localStorage / memory | Anonymous user ID |
| __slnka_user | cookie / localStorage / memory | Identified user ID |
| __slnka_consent | localStorage | Consent state |
| __slnka_session | sessionStorage | Session ID |
| __slnka_session_activity | sessionStorage | Last activity timestamp |
| __slnka_queue | localStorage | Persisted event queue (offline) |
Browser Support
- Chrome 80+
- Firefox 80+
- Safari 14+
- Edge 80+
- Mobile Safari (iOS 14+)
- Chrome Android 80+
The SDK uses fetch, crypto.getRandomValues, sendBeacon, and Intl.DateTimeFormat, all widely supported in modern browsers.
