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

v1.6.5

Published

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

Readme

alphana-sdk

npm

Client-side analytics SDK for React, Next.js, Vite, and vanilla JS/TS. Tracks SPA navigation, time-on-page, heatmaps (with optional path allowlists), console and runtime errors, session heartbeats, feature flags (with user targeting), behavioral signals such as rage clicks and quick U-turns, first/last-touch UTM attribution, revenue events, and a one-time client_context snapshot per session (device category, OS, browser, language, viewport, time zone, SDK version) for catalog parity with the dashboard — without third-party scripts.

Note: client_context does not record DOM for full visual replay; that still requires a dedicated capture pipeline (e.g. rrweb) if you add it later.

  • Package: alphana-sdk on npm
  • Exports: alphana-sdk (core) and alphana-sdk/react (provider + hooks)

Installation

npm install alphana-sdk
pnpm add alphana-sdk
yarn add alphana-sdk
bun add alphana-sdk

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: import.meta.env.VITE_TRACKER_APP_ID,
        secretKey: import.meta.env.VITE_TRACKER_SECRET,
      }}
    >
      <App />
    </UserTrackerProvider>
  </StrictMode>,
);
# .env.local
VITE_TRACKER_APP_ID=your_app_id
VITE_TRACKER_SECRET=your_secret_key

Next.js App Router

Wrap the provider in a Client Component, then use usePageView with usePathname() so App Router navigations are recorded (History API hooks alone do not always fire).

// 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/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 JS / TypeScript

import { UserTracker } from "alphana-sdk";

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

tracker.init(); // safe no-op during SSR (`window` undefined)

tracker.destroy(); // teardown, timers, best-effort final send

Script tag / Google Tag Manager

Use the CDN build when you cannot install npm packages. Add this to <head> or as a GTM Custom HTML tag:

<script
  async
  src="https://storage.alphana.ir/cdn/alphana-sdk/latest/alphana-sdk.js"
  data-app-id="YOUR_APP_ID"
  data-secret-key="YOUR_SECRET_KEY"
></script>

Optional config can also be added as data-* attributes on the same script:

<script
  async
  src="https://storage.alphana.ir/cdn/alphana-sdk/latest/alphana-sdk.js"
  data-app-id="YOUR_APP_ID"
  data-secret-key="YOUR_SECRET_KEY"
  data-track-heatmap="true"
  data-session-replay="false"
></script>

After the script loads, manual calls are available through window.alphana, for example window.alphana("identify", { email: "[email protected]" }).


Configuration reference

| Option | Type | Default | Description | | ------------------ | ------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | appId | string | — | Required for Alphana Cloud. App ID from the dashboard; included in batch payloads. | | secretKey | string | — | Required for Alphana Cloud (and for feature flags). Sent as Authorization: Bearer … on API calls. | | endpoint | string | https://api.alphana.ir/api/events | Events base URL for Alphana Cloud. Batching uses {endpoint}/batch, heartbeats {endpoint}/heartbeat, logs derived under the same API prefix. | | sessionId | string | auto UUID | Optional fixed session id. | | trackNavigation | boolean | true | Intercept pushState / replaceState / popstate for SPA routes; also emits U-turn detection. | | trackTime | boolean | true | Cumulative time per path. | | trackHeatmap | boolean | true | Mouse move, click, scroll sampling; rage-click bursts. | | heatmapPages | string[] | — | Optional client allowlist: heatmap capture is limited to these paths (values are normalized like dashboard rows). If omitted, the SDK may still record moves; the backend only persists heatmap points when the app has ≥1 registered heatmap page and the path matches. | | trackLogs | boolean | true | Patches console.info/warn/error, window.onerror, unhandledrejection; sends to /logs/ingest. | | mouseSampleRate | number (0–1) | 0.3 | Fraction of move/scroll events kept. | | maxHeatmapPoints | number | 2000 | Max in-memory heatmap points per path in the session snapshot. | | batchSize | number | 20 | Queue size before an automatic flush. | | flushInterval | number (ms) | 5000 | Timer-based flush when the queue is non-empty. | | onEvent | (event: TrackerEvent) => void | — | Synchronous callback for every emitted event. |

TypeScript marks appId / secretKey as optional on TrackerConfig, but you should always pass them when using the hosted Alphana API.


API

UserTracker

import { UserTracker } from "alphana-sdk";

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

tracker.init();
tracker.destroy();

tracker.trackPageView(path?: string);
tracker.trackRevenue({
  eventName: "purchase",
  amount: 4900,
  currency: "USD",
  transactionId: "ord_123",
  productId: "starter-plan",
});

tracker.flush(); // POST queued events to `/batch` (fire-and-forget)

tracker.getSession(); // read-only SessionData
tracker.getPageViews();
tracker.getTimeSpent(); // Record<path, milliseconds>
tracker.getHeatmapData(path: string): HeatmapPoint[];
tracker.getHeatmapData(): Record<string, HeatmapPoint[]>;

tracker.subscribe(fn); // returns unsubscribe

// Feature flags (requires `secretKey` + valid `endpoint`)
tracker.identify({ email: "[email protected]", plan: "pro" });
tracker.getFlags();
tracker.isFeatureEnabled("my-flag");
tracker.onFlagsChange((flags) => { /* ... */ }); // unsubscribe fn
void tracker.fetchFlags();

// A/B tests (requires `secretKey` + valid `endpoint`)
tracker.getAbVariants();
tracker.getAbVariant("checkout-cta-test");
tracker.isAbVariant("checkout-cta-test", "variant-b");
tracker.onAbTestsChange((variants) => { /* ... */ });
void tracker.fetchAbTests(["checkout-cta-test"]); // optional keys filter

Attribution: Pageviews automatically read utm_source, utm_medium, utm_campaign, utm_term, utm_content, plus click IDs (gclid, fbclid, ttclid, msclkid) from the current URL. The SDK persists first-touch and last-touch context in localStorage and attaches it to pageview and revenue events.

Revenue: trackRevenue(payload) records purchases, subscriptions, renewals, upgrades, refunds, or custom monetary events. Include a stable transactionId for idempotent backend upserts.

Heartbeat: Every 30s while the tab is visible, a POST is sent to {endpoint}/heartbeat with session and visitor ids.

Deactivate: On tab hide / pagehide, a beacon marks the session inactive and flushes queued analytics via sendBeacon when possible.

Batching: Analytics events are POSTed as JSON to {endpoint}/batch with visitorId, optional location, and an events array.

LogCapture

Used internally when trackLogs: true. Sends structured entries to {apiBase}/logs/ingest (API base is derived by stripping the last path segment from your endpoint, e.g. …/api/events…/api).

import { LogCapture } from "alphana-sdk";

const capture = new LogCapture({
  endpoint: "https://api.alphana.ir/api/events",
  sessionId: "ses_abc123",
  appId: "YOUR_APP_ID",
  secretKey: "sk_...",
});

capture.init();
capture.capture("error", "Something failed", { stack: err.stack });
capture.destroy();

renderHeatmap

Draws HeatmapPoint[] on a <canvas> (blue → red).

import { renderHeatmap } from "alphana-sdk";

const canvas = document.getElementById("heatmap") as HTMLCanvasElement;
canvas.width = 1280;
canvas.height = 720;

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

DEFAULT_ENDPOINT

import { DEFAULT_ENDPOINT } from "alphana-sdk";
// "https://api.alphana.ir/api/events"

React hooks

All hooks are exported from alphana-sdk/react.

useTracker() returns UserTracker | null (null outside a provider).

| Hook | Returns | Description | | ----------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------ | | useTracker() | UserTracker \| null | Tracker from context. | | usePageView(path?) | void | When path is defined, calls trackPageView(path) on change. No-op if path is omitted. | | useHeatmapData(path?, refreshMs?) | HeatmapPoint[] | Live points for a path; optional debounced refresh (default 500 ms). | | usePageViews() | PageView[] | Page views in the current session. | | useTrackRevenue() | (payload: RevenueEventPayload) => void | Stable hook for recording purchases/subscriptions/refunds through the current tracker. | | useTimeSpent() | Record<string, number> | Cumulative milliseconds per path. | | useFeatureFlags() | Record<string, boolean> | Evaluated flags; updates after identify(). | | useFeatureFlagEnabled(key) | boolean | Whether key is enabled. | | useAbTests() | Record<string, string \| null> | Assigned variant per experiment key. | | useAbVariant(experimentKey) | string \| null | Variant key for one experiment. | | useIsAbVariant(experiment, variant) | boolean | Whether visitor is in that variant. |

import { useTracker, useTimeSpent, useHeatmapData } from "alphana-sdk/react";

export function DebugPanel() {
  const tracker = useTracker();
  const timeByPath = useTimeSpent();
  const points = useHeatmapData();

  if (!tracker) return null;

  return (
    <div>
      <p>Paths tracked: {Object.keys(timeByPath).length}</p>
      <p>Heatmap points (this page): {points.length}</p>
      <button type="button" onClick={() => tracker.flush()}>
        Flush now
      </button>
    </div>
  );
}

TypeScript types

import type {
  TrackerConfig,
  TrackerEvent,
  UtmParams,
  AttributionContext,
  PageView,
  TimeSpent,
  HeatmapPoint,
  SessionData,
  GeoLocation,
  HeatmapRenderOptions,
  RageClick,
  UTurn,
  RevenueEvent,
  RevenueEventPayload,
  RevenueEventStatus,
  RevenueLineItem,
  LogLevel,
  LogEntry,
} from "alphana-sdk";

WordPress

For WordPress sites, use the Alphana Tracker plugin (ZIP):

Download: https://storage.alphana.ir/cdn/alphana-tracker.zip

  1. In WordPress admin: Plugins → Add New → Upload Plugin and choose the ZIP, or unzip into wp-content/plugins/alphana-tracker/.
  2. Activate Alphana Tracker.
  3. Open Settings → Alphana Tracker, enter App ID and Secret Key from the Alphana dashboard, enable tracking, and save.