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

alphana-sdk

v2.0.7

Published

Client-side tracking SDK — navigation, time-on-page, and heatmap data collection.

Readme

alphana-sdk

Client-side analytics SDK for the Alphana platform. Collects navigation, time-on-page, heatmap interactions, console errors, and feature-flag evaluations, then batches and sends them to your Alphana backend.

NPM: [alphana-sdk](https://www.npmjs.com/package/alphana-sdk) · Version: 2.0.2 · License: MIT

Features

  • SPA navigation — Monitors history.pushState, replaceState, and popstate for automatic page views and U-turn detection (quick bounces).
  • Time on page — Cumulative dwell time per path, updated on tab hide and navigation.
  • Heatmaps — Sampled mouse moves, clicks, scrolls, and rage-click bursts; coordinates stored as page percentages for resolution-independent replay.
  • Element goals & revenue — Optional dashboard-configured click tracking by HTML element id (WordPress / no-code friendly).
  • Cookie consent — Optional dashboard widget; tracking waits for visitor acceptance when enabled.
  • Session identity — Per-tab session ID plus a persistent visitorId in localStorage (after consent when required).
  • Batched ingest — Events queue locally and flush on batch size, interval, or page unload (sendBeacon).
  • Heartbeats — Keep-alive pings every 30s; deactivate signal when the tab is hidden.
  • Error logging — Patches console.info/warn/error, window.onerror, and unhandled rejections (optional).
  • Feature flags — Evaluate flags server-side with identify() targeting (requires secretKey).
  • React bindings — Optional subpath alphana-sdk/react with provider and hooks (React 17+).
  • Tree-shakeable — sideEffects: false; React is an optional peer dependency.
  • SSR-safe — init() is a no-op when window is undefined.

Installation

npm install alphana-sdk
# or
pnpm add alphana-sdk
# or
bun add alphana-sdk

For React integration, install React 17+ in your app (peer dependency):

npm install react react-dom

Credentials

Create an app in the Alphana dashboard and copy:

| Value | Config key | Usage | | ---------- | ----------- | -------------------------------- | | App ID | appId | Sent in every request body | | Secret key | secretKey | Authorization: Bearer … header |

Default API endpoint (cloud):

https://api.alphana.ir/api/events

Quick start

React / Vite

// main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { UserTrackerProvider } from "alphana-sdk/react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <UserTrackerProvider
      config={{
        appId: "YOUR_APP_ID",
        secretKey: "YOUR_SECRET_KEY",
      }}
    >
      <App />
    </UserTrackerProvider>
  </StrictMode>,
);
// Any child component
import { useTracker, useFeatureFlagEnabled } from "alphana-sdk/react";

export function MyComponent() {
  const tracker = useTracker();
  const showBeta = useFeatureFlagEnabled("new-checkout");

  function handleSignup() {
    tracker?.identify({ email: "[email protected]", plan: "pro" });
  }

  return showBeta ? <BetaCheckout /> : <Checkout />;
}

Next.js App Router

The App Router does not trigger history.pushState the same way as classic SPAs. Wrap the app in the provider, then track pathname changes manually.

// app/providers.tsx
"use client";
import { UserTrackerProvider } from "alphana-sdk/react";
import type { ReactNode } from "react";

export function Providers({ children }: { children: ReactNode }) {
  return (
    <UserTrackerProvider
      config={{
        appId: process.env.NEXT_PUBLIC_TRACKER_APP_ID!,
        secretKey: process.env.NEXT_PUBLIC_TRACKER_SECRET!,
      }}
    >
      {children}
    </UserTrackerProvider>
  );
}
// app/navigation-tracker.tsx
"use client";

import { usePathname } from "next/navigation";
import { usePageView } from "alphana-sdk/react";

export function NavigationTracker() {
  usePageView(usePathname());
  return null;
}
// app/layout.tsx
import { Providers } from "./providers";
import { NavigationTracker } from "./navigation-tracker";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Providers>
          <NavigationTracker />
          {children}
        </Providers>
      </body>
    </html>
  );
}
// app/navigation-tracker.tsx
"use client";
import { usePathname } from "next/navigation";
import { usePageView } from "alphana-sdk/react";

export function NavigationTracker() {
  usePageView(usePathname());
  return null;
}
# .env.local
NEXT_PUBLIC_TRACKER_APP_ID=your_app_id
NEXT_PUBLIC_TRACKER_SECRET=your_secret_key

Vanilla TypeScript / JavaScript

import { UserTracker } from "alphana-sdk";

const tracker = new UserTracker({
  appId: "YOUR_APP_ID",
  secretKey: "YOUR_SECRET_KEY",
});

tracker.init();

// Optional: tear down on logout or SPA teardown
// tracker.destroy();

CDN / script tag (IIFE)

The build also emits a self-contained browser bundle:

dist/alphana-sdk.global.js  →  window.AlphanaSDK
<script src="https://your-cdn.example/cdn/alphana-sdk/latest/alphana-sdk.js"></script>
<script>
  const tracker = new AlphanaSDK.UserTracker({
    appId: "YOUR_APP_ID",
    secretKey: "YOUR_SECRET_KEY",
  });
  tracker.init();
</script>

Publish the bundle with MinIO (see CDN upload below). The WordPress plugin and other non-bundler sites load this file.

Configuration

All options are passed to new UserTracker(config) or <UserTrackerProvider config={…} />.

| Option | Type | Default | Description | | --------------------------- | ---------------------- | ----------------------------------- | -------------------------------------------------------------------------------- | | endpoint | string | https://api.alphana.ir/api/events | Events API base URL | | appId | string | — | App identifier from the dashboard | | secretKey | string | — | Bearer token for authenticated requests | | sessionId | string | auto (crypto.randomUUID) | Override session ID | | trackNavigation | boolean | true | SPA route / pageview tracking | | trackTime | boolean | true | Time-on-page per path | | trackHeatmap | boolean | true | Mouse, click, scroll sampling | | trackLogs | boolean | true | Console and uncaught error capture | | mouseSampleRate | number | 0.3 | Fraction of move/scroll events to record (0–1) | | maxHeatmapPoints | number | 2000 | Max in-memory points per page | | batchSize | number | 20 | Auto-flush when queue reaches this size | | flushInterval | number | 5000 | Auto-flush interval in ms | | compressPayloads | boolean | true | Gzip-compress large ingest bodies when the browser supports it | | compressionThresholdBytes | number | 1024 | Minimum JSON size (bytes) before gzip is attempted | | collectEndpoint | string | — | Override unified ingest URL (default: {apiBase}/collect from endpoint) | | heatmapPages | string[] | — | Only capture heatmap data on these paths (from dashboard “Heatmap Pages”) | | onEvent | (event) => void | — | Synchronous callback for every emitted event | | consentMode | "auto" \| "disabled" | auto | Honor dashboard cookie-consent widget (auto) or track immediately (disabled) |

Example with heatmap path allowlist and custom sampling:

const tracker = new UserTracker({
  appId: "YOUR_APP_ID",
  secretKey: "YOUR_SECRET_KEY",
  heatmapPages: ["/", "/pricing", "/dashboard"],
  mouseSampleRate: 0.2,
  onEvent: (event) => {
    if (event.type === "rageclik") {
      console.debug("Rage click", event.data);
    }
  },
});

Core API (UserTracker)

Lifecycle

import { UserTracker, DEFAULT_ENDPOINT } from "alphana-sdk";

const tracker = new UserTracker({ appId: "…", secretKey: "…" });

tracker.init(); // attach listeners; safe on server (no-op)
tracker.destroy(); // remove listeners, flush queue via sendBeacon

DEFAULT_ENDPOINT is exported if you need the cloud default URL in your own config layer.

Manual page views

tracker.trackPageView("/products?id=1");

Dispatches a pageview event and the custom DOM event tracker:navigate (used internally by time and heatmap plugins).

Session data (in-memory)

tracker.getSession(); // full snapshot: id, visitorId, pageViews, timeSpent, heatmap, location
tracker.getPageViews(); // PageView[]
tracker.getTimeSpent(); // Record<path, milliseconds>
tracker.getHeatmapData("/"); // HeatmapPoint[] for one path
tracker.getHeatmapData(); // Record<path, HeatmapPoint[]>

Subscribing to events

const unsub = tracker.subscribe((event) => {
  console.log(event.type, event.data);
});
unsub();

Feature flags

Requires secretKey. Flags are fetched on init() and after each identify() call.

tracker.identify({ email: "[email protected]", plan: "enterprise" });

tracker.getFlags(); // { "flag-key": true, ... }
tracker.isFeatureEnabled("flag-key"); // boolean

const unsub = tracker.onFlagsChange((flags) => {
  console.log("Flags updated", flags);
});
unsub();

await tracker.fetchFlags(); // manual refresh

Error logging (manual)

When trackLogs is enabled, tracker.logCapture is available after init():

try {
  riskyOperation();
} catch (err) {
  tracker.logCapture?.capture("error", "riskyOperation failed", {
    stack: err instanceof Error ? err.stack : undefined,
    meta: { feature: "checkout" },
  });
}

React API (alphana-sdk/react)

| Export | Description | | ----------------------------------- | ----------------------------------------------------------------------------- | | UserTrackerProvider | Creates one UserTracker, calls init() on mount, destroy() on unmount | | useTracker() | Returns the tracker instance, or null outside a provider | | usePageView(path?) | Records a page view when path changes (use with usePathname() in Next.js) | | usePageViews() | Live list of session page views | | useTimeSpent() | Live Record<path, ms> | | useHeatmapData(path?, refreshMs?) | Live heatmap points for a path (debounced updates, default 500ms) | | useFeatureFlags() | Live flag map; re-renders on onFlagsChange | | useFeatureFlagEnabled(key) | Boolean for a single flag |

UserTrackerProvider captures config only on the first render; changing props later does not reconfigure the tracker.

Event types

Events flow through onEvent, subscribe(), the in-memory session, and the remote batch queue.

| type | Description | | ----------- | -------------------------------------------------------------------------------- | | pageview | Path, title, timestamp, referrer | | timespent | Milliseconds spent on a path before leaving | | heatmap | Mouse move, click, or scroll point (xPct, yPct, optional target on clicks) | | rageclik | Rapid repeated clicks in one area | | uturn | Left a page within ~5s (bounce signal) |

TypeScript definitions:

import type {
  TrackerConfig,
  TrackerEvent,
  UtmParams,
  AttributionContext,
  PageView,
  TimeSpent,
  HeatmapPoint,
  SessionData,
  GeoLocation,
  HeatmapRenderOptions,
  LogLevel,
  LogEntry,
} from "alphana-sdk";

Heatmap rendering

Use renderHeatmap to draw collected points on a <canvas> (e.g. in a dashboard preview). Coordinates are percentages of page dimensions, so the overlay scales with canvas size.

import { renderHeatmap } from "alphana-sdk";

const canvas = document.getElementById("heatmap") as HTMLCanvasElement;
const points = tracker.getHeatmapData("/");

renderHeatmap(canvas, points, {
  radius: 25,
  maxOpacity: 0.85,
  minOpacity: 0,
});

Network behavior

| Traffic | Endpoint | When | | ------------------- | --------------------------------------- | ---------------------------------------------------------- | | Collect (SDK ≥ 1.8) | POST {apiBase}/collect | Event batches, heartbeats, and logs (multiplexed envelope) | | Event batch | POST {endpoint}/batch | Legacy SDK < 1.8 — still supported on the backend | | Heartbeat | POST {endpoint}/heartbeat | Legacy SDK < 1.8 | | Logs | POST {apiBase}/logs/ingest | Legacy SDK < 1.8 | | Feature flags | POST {apiBase}/feature-flags/evaluate | On init and after identify() |

All authenticated requests send Authorization: Bearer {secretKey}. Analytics failures are silent in production (no thrown errors to end users). Unload uses navigator.sendBeacon when available.

Visitor country/city is resolved asynchronously from IP and attached to batch payloads when available.

Package exports

// Core (framework-agnostic)
import {
  UserTracker,
  DEFAULT_ENDPOINT,
  LogCapture,
  renderHeatmap,
} from "alphana-sdk";

// React (optional)
import {
  UserTrackerProvider,
  useTracker,
  usePageView,
  useHeatmapData,
  usePageViews,
  useTimeSpent,
  useFeatureFlags,
  useFeatureFlagEnabled,
} from "alphana-sdk/react";