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

@kixo.io/web

v0.1.33

Published

Kixo Web Analytics SDK — lightweight, privacy-first analytics for web applications

Readme

TypeScript npm Formats License

Kixo Web SDK

Lightweight, privacy-first analytics SDK for web applications. Part of the Kixo platform.

The SDK auto-captures page views, clicks, scroll depth, errors, sessions, performance vitals (LCP / INP / FCP / CLS / TTFB), Web Push permission state, third-party SDK usage, heatmaps, and project-controlled session replay — with rrweb lazy-loaded only when pixel replay is enabled.

Same wire format as the iOS / Android SDKs, identical StandardProperty keys (37 cases across 8 packs), identical lifecycle states. Cross-platform funnels Just Work.


Install

npm

npm install @kixo.io/web
import Kixo from '@kixo.io/web';

Kixo.init({ projectId: 'kx_proj_...', apiKey: 'kx_key_...' });

Script tag (CDN)

<script type="module">
  import Kixo from 'https://cdn.kixo.io/kixo.min.js';
  Kixo.init({ projectId: 'kx_proj_…', apiKey: 'kx_key_…' });
</script>

The script auto-detects ?id=…&key=… query params from its own <script type="module" src=…> URL, so an explicit Kixo.init({…}) call is optional when you set the params on the URL itself.

The npm package and CDN embed are two supported distributions of the same release. Pin the immutable CDN URL when you need a fixed browser version, for example https://cdn.kixo.io/kixo-VERSION.min.js.


Configuration

Kixo.init({
  projectId: 'kx_proj_…',
  apiKey:    'kx_key_…',
  environment: 'production', // or 'development'; staging is not provisioned

  // ── Auto-trackers ─────────────────────────────────────────
  autoTrack: {
    pageViews:      true,
    clicks:         true,
    scrollDepth:    true,
    sessions:       true,
    forms:          true,
    network:        true,    // opt-in; default false because URL paths may contain PII
    errors:         true,
    performance:    true,    // LCP / INP / FCP / CLS / TTFB / DOM-load
    rageClicks:     true,
    deadClicks:     true,
    engagementTime: true,
    context:        true,
    refreshLoop:    true,
    lifecycle:      true,
    resourceErrors: true,
    perfBudget:     true,
    attribution:    true,
    push:           true,    // Notification permission monitoring (privacy-neutral)
  },

  heatmap: {
    enabled: true,
    clicks:  true,
    moves:   true,
    scroll:  true,
  },

});

Session replay is configured per project in Kixo Dashboard, not in the embed code. The SDK applies enabled, sampling, masking, and duration from remote config on init and on periodic refresh.


Data ownership

Kixo does not maintain end-user consent or opt-out state. Your application decides which data to send and which automatic trackers to enable. Kixo applies the project policy returned by the control plane and the collection settings configured in your project.


API

Track events

Kixo.track('purchase_completed', {
  product_id: 'SKU-123',
  amount: 49.99,
  currency: 'USD',
});

Page views

Kixo.page('Product Detail', { category: 'shoes' });

Identify

import Kixo, { StandardProperty } from 'https://cdn.kixo.io/kixo.min.js';

// Reserved standard properties carry `$`-prefix (Mixpanel convention)
// so they namespace away from your custom traits.
Kixo.identify('user_123', {
  $email:  '[email protected]',     // identity
  $name:   'Jane Doe',              // identity
  $plan:   'pro',                   // saas pack
  $lifetime_orders: 12,             // ecommerce pack
  signup_source: 'twitter_ad',      // custom trait
});

// Typed standard properties (37 cases mirror iOS / Android)
Kixo.setUserProperty(StandardProperty.Email,          '[email protected]');
Kixo.setUserProperty(StandardProperty.Country,        'US');
Kixo.setUserProperty(StandardProperty.Plan,           'pro');
Kixo.setUserProperty(StandardProperty.LifetimeOrders, 12);

// Or string-keyed for custom traits (autocomplete still surfaces the 37):
Kixo.setUserProperty('signup_source', 'twitter_ad');

// Boolean flags — tag a user for segmentation & campaigns
Kixo.setUserProperty('subscribe', true);   // queryable as "subscribe = true"
Kixo.setUserProperty('vip', true);
Kixo.setUserProperty('beta_tester', false);

// Bulk
Kixo.setUserProperties({
  $email: '[email protected]',
  $plan:  'pro',
  subscribe: true,
  custom_trait: 'value',
});

Boolean / string / numeric properties all power segments + campaigns + chat ("send a welcome email to users where subscribe is true"). Persisted in localStorage; cleared on Kixo.reset().

37 typed StandardProperty cases across 8 packs (identity / geo / lifecycle + 5 verticals). The dashboard auto-detects which packs your project actively uses and adapts the audience-explorer columns to match. Byte-for-byte mirrored across iOS / Android.

| Pack | Cases | |---|---| | identity (universal) | Email, Phone, Name, FirstName, LastName, AvatarUrl | | geo (universal) | Country, City, Region, Timezone, Language, Locale | | lifecycle (universal) | Created, LastSeen | | saas (vertical) | Plan, SubscriptionStatus, TrialEnds, Mrr, SubscriptionStarted | | ecommerce (vertical) | LifetimeOrders, LifetimeRevenue, Aov, LastPurchase, FirstPurchase, CartAbandonedCount | | media (vertical) | ContentTier, SubscribedCategories, WatchTimeTotal, LastPlayed | | marketplace (vertical) | SellerTier, BuyerTier, ListingsCount, ReviewsCount, Verified | | loyalty (vertical) | LoyaltyPoints, VipLevel, ReferralCount |

Don't see your pattern? Use bare keys (no $-prefix) for custom traits — they surface in the Custom Traits panel of the audience explorer without polluting the first-class profile columns.

Group / B2B

Kixo.group('team_456', { company: 'Acme Inc', plan: 'enterprise' });

Super-properties (decorate every event)

Kixo.setSuperProperty('app_variant', 'B');
Kixo.setSuperProperties({ app_variant: 'B', build_flavor: 'beta' });
Kixo.unsetSuperProperty('app_variant');
Kixo.clearSuperProperties();

Web Push (FCM)

// 1. Prompt for permission (must be inside a user-gesture handler)
const result = await Kixo.requestPushPermission();
// → 'granted' | 'denied' | 'default'

// 2. Obtain the current FCM Web registration token with Firebase's
//    getToken(...) API, then register it with Kixo on every app start.
Kixo.setPushToken(fcmRegistrationToken); // provider defaults to 'firebase'

// 3. When manually integrating delivery callbacks, log funnel events:
Kixo.logPushReceived({ campaign_id: '…' });
Kixo.logPushOpened({ campaign_id: '…', action_id: '…' });
Kixo.logPushDismissed({ campaign_id: '…' });

Kixo's web sender uses FCM HTTP v1. Raw PushSubscription endpoint URLs are not supported: setPushToken rejects them (and non-firebase providers) with a console.warn and returns false instead of creating an undeliverable token — it never throws into your registration handler. Use Firebase Web SDK deleteToken(...) when removing an FCM token.

push_permission events fire automatically as the user grants / denies / resets — no manual wiring.

Manual goal markers (May 2026)

Two surfaces declare conversion goals — both fire the same event_type='goal' payload, both validated against the strict [a-z0-9_-]{3,64} whitelist (server-template-injection-safe).

HTML attribute — best for inline declarations on existing buttons / forms:

<button data-kixo-goal="checkout_complete"
        data-kixo-goal-value="49.99"
        data-kixo-goal-currency="USD">Pay</button>

<form data-kixo-goal="signup" data-kixo-goal-trigger="submit">…</form>

<section data-kixo-goal="onboarding"
         data-kixo-goal-step="2"
         data-kixo-goal-trigger="view">
  <!-- IntersectionObserver fires after ≥50% visible for ≥500ms -->
</section>

Sub-attributes: -trigger (click / submit / view — default click), -step (1-32 funnel step), -value, -currency (ISO 4217), -once (session / page / never — default session), -props (JSON object string ≤ 2 KB).

JS API — best for server-confirmed events without a clickable element:

Kixo.markGoal('checkout_complete', {
  value: 49.99,
  currency: 'USD',
  step: 3,
  properties: { plan: 'pro' },  // PII-filtered automatically
});

Manual marks are ground truth — they beat AI auto-detected goal candidates on the same scope. The auto-goals analyzer (in the dashboard) skips proposing goals the host already declared manually.

Auto-tracked behavior signals (May 2026)

Beyond clicks + page views, the SDK now emits 4 new event types that drive auto-goals AI + behavior-trail replay:

| event_type | event_name(s) | When | |---|---|---| | modal | modal_opened / modal_closed | DOM mutation creates/removes a dialog (native <dialog>, role=dialog + aria-modal, fixed-position overlays) | | page_semantic | page_semantic | Once per page-view — captures path, H1/H2/H3, top-3 CTAs by visual prominence, form field signature, OpenGraph type, JSON-LD @type | | interaction | long_press / swipe_* / double_tap / pinch_* / drag / scroll_end | Pointer/touch/scroll thresholds — cross-platform parity with iOS | | goal | <your_goal_name> | data-kixo-goal HTML attribute or Kixo.markGoal() JS call |

All event payloads pass through PII filter (regex + Luhn for cards, Unicode-aware for emails) before reaching the wire.

Feature flags & experiments

const variant = Kixo.getVariant('checkout_experiment', ['control', 'variant_a']);
const showNewUI = Kixo.getFeatureFlag('new_checkout_ui');
await Kixo.refreshFlags();

Operational

await Kixo.flush();           // force-drain the buffer
const diag = Kixo.diagnostics();  // lifecycle + release + queue + replay
Kixo.reset();                  // logout — new anonymousId, full clear

Auto-tracking

| Event type | Description | |---|---| | page_view | SPA navigation + initial page load | | click | All clicks with selector / text / coords (text PII-filtered) | | scroll_depth | 25 / 50 / 75 / 100 % milestones | | session_start | New session with idle-timeout detection | | session_end | Session closed after idle rotation or explicit SDK teardown; browsers may omit it on tab close | | form_submit | Submission (values excluded for privacy) | | network_request | XHR/fetch with timing + auto-classified _kixo_classification | | error | Unhandled exceptions + promise rejections | | performance | LCP, FCP, FID, INP, CLS, TTFB, DOM-load | | rage_click | 3+ clicks on the same element within 1s | | dead_click | Click that produces no DOM change | | engagement_tick | Visible-active-time per 15s | | frustration_refresh_loop | 3+ reloads in 2 minutes | | bfcache_restore, pwa_installed, online, offline | Lifecycle | | resource_error | Failed image / script / CSS / font loads | | push_permission | Notification permission state changes | | push_received / push_open / push_dismissed | Delivery events (from SW) |


Web Vitals (CrUX-standard payload)

Every performance event ships the standard { id, value, rating, delta, navigation_type } shape that downstream RUM dashboards expect:

{
  "name": "lcp",
  "value": 1843,
  "id": "v3-lcp-9f8b3c4d2e1a",
  "rating": "good",
  "navigation_type": "navigate",
  "url": "https://shop.example.com/cart",
  "path": "/cart"
}

Rating thresholds match Google's official Core Web Vitals (web.dev/vitals). INP gets its own visibility-change report capturing the worst interaction across the page lifetime; CLS reports incrementally with delta since the last sample.


Privacy filtering (PII)

Every string in event properties (and breadcrumb data) passes through the central PII filter before reaching the wire format. Detected and redacted:

  • Email addresses
  • Phone numbers (E.164, parens, dotted)
  • Credit cards — Luhn-validated (only real card numbers, not random 16-digit IDs)
  • US SSN (3-2-4 digit format)
  • IBAN, JWT tokens, API keys (32+ char alphanumeric runs), social handles (@username)

Long copy (>256 chars) head-scans only — editorial article text isn't treated as a PII surface to keep false-positives down.

This filter is identical to the iOS SDK's (PIIFilter.swift), so cross-platform replay surfaces redact the same things on both sides.

The kixo-private HTML attribute (<input data-kixo-mask>) excludes specific elements from snapshot capture entirely.


SDK / vendor classification

Network events get auto-stamped with _kixo_classification for the top 50 web vendors (Google Analytics, Stripe, Auth0, Sentry, Mixpanel, Hotjar, Intercom, etc.). The full 1100-entry catalog applies server-side for the long tail.

Stamp shape:

"_kixo_classification": {
  "sdk_name":     "Stripe",
  "sdk_vendor":   "Stripe",
  "sdk_category": "payments"
}

Categories: analytics · payments · auth · crash-reporting · session-replay · ab-testing · support · cdn · email · maps · storage · realtime · cms · ads.


Heatmaps

When heatmap.enabled is true, the SDK records click positions, mouse movements, and scroll depth, then uploads DOM snapshots for server-side heatmap rendering. Snapshots dedupe via a fingerprint endpoint so re-visits to the same page don't re-upload.


Session replay

When Session replay is enabled for the project in Kixo Dashboard, the SDK records DOM mutations and user interactions for full session playback without an application-code opt-in. The dashboard player renders the rrweb stream in a static iframe. Interaction taxonomy (long_press, swipe, double_tap, pinch, drag, scroll_end) is captured separately as analytics events.


Diagnostics

const d = Kixo.diagnostics();
// d.lifecycle                   — initialising / running / recovering / pausedByServer
// d.releaseId                   — server-bound release, or null before init resolves
// d.pauseReason                 — stable server reason when paused
// d.queue.bufferedEventCount, …, retryTier
// d.replay.serverEnabled
// d.replay.sampleRatePercent
// d.replay.captureOnCellularApplied // always false on Web

Inspect from devtools: copy(Kixo.__diag).


Testing

npm test           # full Vitest suite
npm run test:watch # interactive
npm run test:coverage

The current 0.1.8 gate is 39 files / 430 tests and also runs TypeScript, clean Rollup build, Service Worker syntax, package dry-run checks, and the leased/monotonic CDN publication contract. Use the command output as the source of truth for test counts.


Performance

  • Code-split ESM entry; exact compressed size is measured from each clean build
  • rrweb is the only runtime dependency and stays in the lazy replay chunk
  • sideEffects: false — fully tree-shakeable
  • requestIdleCallback-deferred flush, never blocks main thread
  • sendBeacon on pagehide for reliable last-mile delivery
  • Replay recorder is lazy-loaded via dynamic import() — projects whose remote policy keeps replay disabled never download it

Build outputs

| Format | File | Use case | |---|---|---| | CDN ESM | dist/kixo.min.js | Public script-module entry | | ESM | dist/esm/index.js | npm bundlers and modern runtimes | | CJS | dist/kixo.cjs.js | npm CommonJS consumers | | Types | dist/esm/index.d.ts | npm TypeScript consumers |


Compatibility

| | Modern | Legacy | |---|---|---| | Browsers | Chrome 90+, Firefox 90+, Safari 15+, Edge 90+ | Chrome 80, Safari 14 (degraded — INP unavailable) | | Frameworks | React, Vue, Svelte, Angular, Solid, raw HTML | All | | Build tools | Vite, esbuild, webpack 5+, rollup, Parcel 2 | webpack 4 (use ESM entry) |


Development

npm install
npm run build       # clean Rollup build → CDN ESM + ESM/CJS QA artifacts
npm run dev         # rollup -w
npm run typecheck   # tsc --noEmit
npm test            # vitest

License

MIT