npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@slnka/web

v1.0.0-beta.17

Published

SLNKA Web SDK — Client-side analytics, deep linking, and attribution (CNDP compliant)

Downloads

29

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/web

No 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)
  • anonymousId
  • userId (if identified)
  • sessionId
  • timestamp (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 console

Consent 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:

  1. No tracking without consent - requireConsent: true is the default.
  2. No cookies before consent - Anonymous ID is held in memory until optIn().
  3. Pre-consent queue - Events tracked before consent are buffered in memory (not localStorage) and flushed only after optIn().
  4. Full data purge on opt-out - optOut() deletes all cookies, localStorage entries, and queued events.
  5. DNT and GPC respected - Browser-level privacy signals are honored.
  6. No raw IP storage - IP hashing happens server-side (SHA-256 + daily salt).
  7. 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.