alphana-sdk 1.5.5 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +231 -183
- package/dist/alphana-sdk.global.js +4 -4
- package/dist/index.d.mts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +17 -4
- package/dist/react/index.d.ts +17 -4
- package/dist/react/index.js +4 -4
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +4 -4
- package/dist/react/index.mjs.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
1
|
# alphana-sdk
|
|
2
2
|
|
|
3
|
-
[
|
|
3
|
+
Client-side analytics SDK for the [Alphana](https://alphana.ir) platform. Collects navigation, time-on-page, heatmap interactions, console errors, and feature-flag evaluations, then batches and sends them to your Alphana backend.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**NPM:** `[alphana-sdk](https://www.npmjs.com/package/alphana-sdk)` · **Version:** 0.5.x · **License:** MIT
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Features
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
9
|
+
- **SPA navigation** — Monitors `history.pushState`, `replaceState`, and `popstate` for automatic page views and U-turn detection (quick bounces).
|
|
10
|
+
- **Time on page** — Cumulative dwell time per path, updated on tab hide and navigation.
|
|
11
|
+
- **Heatmaps** — Sampled mouse moves, clicks, scrolls, and rage-click bursts; coordinates stored as page percentages for resolution-independent replay.
|
|
12
|
+
- **Session identity** — Per-tab session ID plus a persistent `visitorId` in `localStorage`.
|
|
13
|
+
- **Batched ingest** — Events queue locally and flush on batch size, interval, or page unload (`sendBeacon`).
|
|
14
|
+
- **Heartbeats** — Keep-alive pings every 30s; deactivate signal when the tab is hidden.
|
|
15
|
+
- **Error logging** — Patches `console.info/warn/error`, `window.onerror`, and unhandled rejections (optional).
|
|
16
|
+
- **Feature flags** — Evaluate flags server-side with `identify()` targeting (requires `secretKey`).
|
|
17
|
+
- **React bindings** — Optional subpath `alphana-sdk/react` with provider and hooks (React 17+).
|
|
18
|
+
- **Tree-shakeable** — `sideEffects: false`; React is an optional peer dependency.
|
|
19
|
+
- **SSR-safe** — `init()` is a no-op when `window` is undefined.
|
|
11
20
|
|
|
12
21
|
## Installation
|
|
13
22
|
|
|
14
23
|
```bash
|
|
15
24
|
npm install alphana-sdk
|
|
25
|
+
# or
|
|
16
26
|
pnpm add alphana-sdk
|
|
17
|
-
|
|
27
|
+
# or
|
|
18
28
|
bun add alphana-sdk
|
|
19
29
|
```
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
For React integration, install React 17+ in your app (peer dependency):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install react react-dom
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Credentials
|
|
38
|
+
|
|
39
|
+
Create an app in the Alphana dashboard and copy:
|
|
40
|
+
|
|
41
|
+
| Value | Config key | Usage |
|
|
42
|
+
| ---------- | ----------- | -------------------------------- |
|
|
43
|
+
| App ID | `appId` | Sent in every request body |
|
|
44
|
+
| Secret key | `secretKey` | `Authorization: Bearer …` header |
|
|
45
|
+
|
|
46
|
+
Default API endpoint (cloud):
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
https://api.alphana.ir/api/events
|
|
50
|
+
```
|
|
22
51
|
|
|
23
52
|
## Quick start
|
|
24
53
|
|
|
@@ -35,8 +64,8 @@ createRoot(document.getElementById("root")!).render(
|
|
|
35
64
|
<StrictMode>
|
|
36
65
|
<UserTrackerProvider
|
|
37
66
|
config={{
|
|
38
|
-
appId:
|
|
39
|
-
secretKey:
|
|
67
|
+
appId: "YOUR_APP_ID",
|
|
68
|
+
secretKey: "YOUR_SECRET_KEY",
|
|
40
69
|
}}
|
|
41
70
|
>
|
|
42
71
|
<App />
|
|
@@ -45,15 +74,25 @@ createRoot(document.getElementById("root")!).render(
|
|
|
45
74
|
);
|
|
46
75
|
```
|
|
47
76
|
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
77
|
+
```tsx
|
|
78
|
+
// Any child component
|
|
79
|
+
import { useTracker, useFeatureFlagEnabled } from "alphana-sdk/react";
|
|
80
|
+
|
|
81
|
+
export function MyComponent() {
|
|
82
|
+
const tracker = useTracker();
|
|
83
|
+
const showBeta = useFeatureFlagEnabled("new-checkout");
|
|
84
|
+
|
|
85
|
+
function handleSignup() {
|
|
86
|
+
tracker?.identify({ email: "user@example.com", plan: "pro" });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return showBeta ? <BetaCheckout /> : <Checkout />;
|
|
90
|
+
}
|
|
52
91
|
```
|
|
53
92
|
|
|
54
93
|
### Next.js App Router
|
|
55
94
|
|
|
56
|
-
|
|
95
|
+
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.
|
|
57
96
|
|
|
58
97
|
```tsx
|
|
59
98
|
// app/providers.tsx
|
|
@@ -75,6 +114,19 @@ export function Providers({ children }: { children: ReactNode }) {
|
|
|
75
114
|
}
|
|
76
115
|
```
|
|
77
116
|
|
|
117
|
+
```tsx
|
|
118
|
+
// app/navigation-tracker.tsx
|
|
119
|
+
"use client";
|
|
120
|
+
|
|
121
|
+
import { usePathname } from "next/navigation";
|
|
122
|
+
import { usePageView } from "alphana-sdk/react";
|
|
123
|
+
|
|
124
|
+
export function NavigationTracker() {
|
|
125
|
+
usePageView(usePathname());
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
78
130
|
```tsx
|
|
79
131
|
// app/layout.tsx
|
|
80
132
|
import { Providers } from "./providers";
|
|
@@ -116,7 +168,7 @@ NEXT_PUBLIC_TRACKER_APP_ID=your_app_id
|
|
|
116
168
|
NEXT_PUBLIC_TRACKER_SECRET=your_secret_key
|
|
117
169
|
```
|
|
118
170
|
|
|
119
|
-
### Vanilla
|
|
171
|
+
### Vanilla TypeScript / JavaScript
|
|
120
172
|
|
|
121
173
|
```ts
|
|
122
174
|
import { UserTracker } from "alphana-sdk";
|
|
@@ -126,213 +178,173 @@ const tracker = new UserTracker({
|
|
|
126
178
|
secretKey: "YOUR_SECRET_KEY",
|
|
127
179
|
});
|
|
128
180
|
|
|
129
|
-
tracker.init();
|
|
181
|
+
tracker.init();
|
|
130
182
|
|
|
131
|
-
|
|
183
|
+
// Optional: tear down on logout or SPA teardown
|
|
184
|
+
// tracker.destroy();
|
|
132
185
|
```
|
|
133
186
|
|
|
134
|
-
|
|
187
|
+
## CDN / script tag (IIFE)
|
|
135
188
|
|
|
136
|
-
|
|
137
|
-
as a GTM Custom HTML tag:
|
|
189
|
+
The build also emits a self-contained browser bundle:
|
|
138
190
|
|
|
139
|
-
```html
|
|
140
|
-
<script
|
|
141
|
-
async
|
|
142
|
-
src="https://storage.alphana.ir/cdn/alphana-sdk/latest/alphana-sdk.js"
|
|
143
|
-
data-app-id="YOUR_APP_ID"
|
|
144
|
-
data-secret-key="YOUR_SECRET_KEY"
|
|
145
|
-
></script>
|
|
146
191
|
```
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
dist/alphana-sdk.global.js → window.AlphanaSDK
|
|
193
|
+
```
|
|
149
194
|
|
|
150
195
|
```html
|
|
151
|
-
<script
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
196
|
+
<script src="https://your-cdn.example/cdn/alphana-sdk/latest/alphana-sdk.js"></script>
|
|
197
|
+
<script>
|
|
198
|
+
const tracker = new AlphanaSDK.UserTracker({
|
|
199
|
+
appId: "YOUR_APP_ID",
|
|
200
|
+
secretKey: "YOUR_SECRET_KEY",
|
|
201
|
+
});
|
|
202
|
+
tracker.init();
|
|
203
|
+
</script>
|
|
159
204
|
```
|
|
160
205
|
|
|
161
|
-
|
|
162
|
-
for example `window.alphana("identify", { email: "user@example.com" })`.
|
|
206
|
+
Publish the bundle with MinIO (see [CDN upload](#cdn-upload) below). The WordPress plugin and other non-bundler sites load this file.
|
|
163
207
|
|
|
164
|
-
|
|
208
|
+
## Configuration
|
|
165
209
|
|
|
166
|
-
|
|
210
|
+
All options are passed to `new UserTracker(config)` or `<UserTrackerProvider config={…} />`.
|
|
167
211
|
|
|
168
|
-
| Option | Type
|
|
169
|
-
| ------------------ |
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `sessionId` | `string`
|
|
174
|
-
| `trackNavigation` | `boolean`
|
|
175
|
-
| `trackTime` | `boolean`
|
|
176
|
-
| `trackHeatmap` | `boolean`
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `onEvent` | `(event
|
|
212
|
+
| Option | Type | Default | Description |
|
|
213
|
+
| ------------------ | ----------------- | ----------------------------------- | ------------------------------------------------------------------------- |
|
|
214
|
+
| `endpoint` | `string` | `https://api.alphana.ir/api/events` | Events API base URL |
|
|
215
|
+
| `appId` | `string` | — | App identifier from the dashboard |
|
|
216
|
+
| `secretKey` | `string` | — | Bearer token for authenticated requests |
|
|
217
|
+
| `sessionId` | `string` | auto (`crypto.randomUUID`) | Override session ID |
|
|
218
|
+
| `trackNavigation` | `boolean` | `true` | SPA route / pageview tracking |
|
|
219
|
+
| `trackTime` | `boolean` | `true` | Time-on-page per path |
|
|
220
|
+
| `trackHeatmap` | `boolean` | `true` | Mouse, click, scroll sampling |
|
|
221
|
+
| `trackLogs` | `boolean` | `true` | Console and uncaught error capture |
|
|
222
|
+
| `mouseSampleRate` | `number` | `0.3` | Fraction of move/scroll events to record (0–1) |
|
|
223
|
+
| `maxHeatmapPoints` | `number` | `2000` | Max in-memory points per page |
|
|
224
|
+
| `batchSize` | `number` | `20` | Auto-flush when queue reaches this size |
|
|
225
|
+
| `flushInterval` | `number` | `5000` | Auto-flush interval in ms |
|
|
226
|
+
| `heatmapPages` | `string[]` | — | Only capture heatmap data on these paths (from dashboard “Heatmap Pages”) |
|
|
227
|
+
| `onEvent` | `(event) => void` | — | Synchronous callback for every emitted event |
|
|
184
228
|
|
|
185
|
-
|
|
229
|
+
Example with heatmap path allowlist and custom sampling:
|
|
186
230
|
|
|
187
|
-
|
|
231
|
+
```ts
|
|
232
|
+
const tracker = new UserTracker({
|
|
233
|
+
appId: "YOUR_APP_ID",
|
|
234
|
+
secretKey: "YOUR_SECRET_KEY",
|
|
235
|
+
heatmapPages: ["/", "/pricing", "/dashboard"],
|
|
236
|
+
mouseSampleRate: 0.2,
|
|
237
|
+
onEvent: (event) => {
|
|
238
|
+
if (event.type === "rageclik") {
|
|
239
|
+
console.debug("Rage click", event.data);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
```
|
|
188
244
|
|
|
189
|
-
## API
|
|
245
|
+
## Core API (`UserTracker`)
|
|
190
246
|
|
|
191
|
-
###
|
|
247
|
+
### Lifecycle
|
|
192
248
|
|
|
193
249
|
```ts
|
|
194
|
-
import { UserTracker } from "alphana-sdk";
|
|
250
|
+
import { UserTracker, DEFAULT_ENDPOINT } from "alphana-sdk";
|
|
195
251
|
|
|
196
|
-
const tracker = new UserTracker({ appId: "
|
|
252
|
+
const tracker = new UserTracker({ appId: "…", secretKey: "…" });
|
|
197
253
|
|
|
198
|
-
tracker.init();
|
|
199
|
-
tracker.destroy();
|
|
200
|
-
|
|
201
|
-
tracker.trackPageView(path?: string);
|
|
202
|
-
tracker.trackRevenue({
|
|
203
|
-
eventName: "purchase",
|
|
204
|
-
amount: 4900,
|
|
205
|
-
currency: "USD",
|
|
206
|
-
transactionId: "ord_123",
|
|
207
|
-
productId: "starter-plan",
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
tracker.flush(); // POST queued events to `/batch` (fire-and-forget)
|
|
211
|
-
|
|
212
|
-
tracker.getSession(); // read-only SessionData
|
|
213
|
-
tracker.getPageViews();
|
|
214
|
-
tracker.getTimeSpent(); // Record<path, milliseconds>
|
|
215
|
-
tracker.getHeatmapData(path: string): HeatmapPoint[];
|
|
216
|
-
tracker.getHeatmapData(): Record<string, HeatmapPoint[]>;
|
|
217
|
-
|
|
218
|
-
tracker.subscribe(fn); // returns unsubscribe
|
|
219
|
-
|
|
220
|
-
// Feature flags (requires `secretKey` + valid `endpoint`)
|
|
221
|
-
tracker.identify({ email: "u@example.com", plan: "pro" });
|
|
222
|
-
tracker.getFlags();
|
|
223
|
-
tracker.isFeatureEnabled("my-flag");
|
|
224
|
-
tracker.onFlagsChange((flags) => { /* ... */ }); // unsubscribe fn
|
|
225
|
-
void tracker.fetchFlags();
|
|
226
|
-
|
|
227
|
-
// A/B tests (requires `secretKey` + valid `endpoint`)
|
|
228
|
-
tracker.getAbVariants();
|
|
229
|
-
tracker.getAbVariant("checkout-cta-test");
|
|
230
|
-
tracker.isAbVariant("checkout-cta-test", "variant-b");
|
|
231
|
-
tracker.onAbTestsChange((variants) => { /* ... */ });
|
|
232
|
-
void tracker.fetchAbTests(["checkout-cta-test"]); // optional keys filter
|
|
254
|
+
tracker.init(); // attach listeners; safe on server (no-op)
|
|
255
|
+
tracker.destroy(); // remove listeners, flush queue via sendBeacon
|
|
233
256
|
```
|
|
234
257
|
|
|
235
|
-
|
|
258
|
+
`DEFAULT_ENDPOINT` is exported if you need the cloud default URL in your own config layer.
|
|
236
259
|
|
|
237
|
-
|
|
260
|
+
### Manual page views
|
|
238
261
|
|
|
239
|
-
|
|
262
|
+
```ts
|
|
263
|
+
tracker.trackPageView("/products?id=1");
|
|
264
|
+
```
|
|
240
265
|
|
|
241
|
-
|
|
266
|
+
Dispatches a `pageview` event and the custom DOM event `tracker:navigate` (used internally by time and heatmap plugins).
|
|
242
267
|
|
|
243
|
-
|
|
268
|
+
### Session data (in-memory)
|
|
244
269
|
|
|
245
|
-
|
|
270
|
+
```ts
|
|
271
|
+
tracker.getSession(); // full snapshot: id, visitorId, pageViews, timeSpent, heatmap, location
|
|
272
|
+
tracker.getPageViews(); // PageView[]
|
|
273
|
+
tracker.getTimeSpent(); // Record<path, milliseconds>
|
|
274
|
+
tracker.getHeatmapData("/"); // HeatmapPoint[] for one path
|
|
275
|
+
tracker.getHeatmapData(); // Record<path, HeatmapPoint[]>
|
|
276
|
+
```
|
|
246
277
|
|
|
247
|
-
|
|
278
|
+
### Subscribing to events
|
|
248
279
|
|
|
249
280
|
```ts
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const capture = new LogCapture({
|
|
253
|
-
endpoint: "https://api.alphana.ir/api/events",
|
|
254
|
-
sessionId: "ses_abc123",
|
|
255
|
-
appId: "YOUR_APP_ID",
|
|
256
|
-
secretKey: "sk_...",
|
|
281
|
+
const unsub = tracker.subscribe((event) => {
|
|
282
|
+
console.log(event.type, event.data);
|
|
257
283
|
});
|
|
258
|
-
|
|
259
|
-
capture.init();
|
|
260
|
-
capture.capture("error", "Something failed", { stack: err.stack });
|
|
261
|
-
capture.destroy();
|
|
284
|
+
unsub();
|
|
262
285
|
```
|
|
263
286
|
|
|
264
|
-
###
|
|
287
|
+
### Feature flags
|
|
265
288
|
|
|
266
|
-
|
|
289
|
+
Requires `secretKey`. Flags are fetched on `init()` and after each `identify()` call.
|
|
267
290
|
|
|
268
291
|
```ts
|
|
269
|
-
|
|
292
|
+
tracker.identify({ email: "user@example.com", plan: "enterprise" });
|
|
270
293
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
canvas.height = 720;
|
|
294
|
+
tracker.getFlags(); // { "flag-key": true, ... }
|
|
295
|
+
tracker.isFeatureEnabled("flag-key"); // boolean
|
|
274
296
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
maxOpacity: 0.85,
|
|
278
|
-
minOpacity: 0,
|
|
297
|
+
const unsub = tracker.onFlagsChange((flags) => {
|
|
298
|
+
console.log("Flags updated", flags);
|
|
279
299
|
});
|
|
280
|
-
|
|
300
|
+
unsub();
|
|
281
301
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
```ts
|
|
285
|
-
import { DEFAULT_ENDPOINT } from "alphana-sdk";
|
|
286
|
-
// "https://api.alphana.ir/api/events"
|
|
302
|
+
await tracker.fetchFlags(); // manual refresh
|
|
287
303
|
```
|
|
288
304
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
## React hooks
|
|
305
|
+
### Error logging (manual)
|
|
292
306
|
|
|
293
|
-
|
|
307
|
+
When `trackLogs` is enabled, `tracker.logCapture` is available after `init()`:
|
|
294
308
|
|
|
295
|
-
|
|
309
|
+
```ts
|
|
310
|
+
try {
|
|
311
|
+
riskyOperation();
|
|
312
|
+
} catch (err) {
|
|
313
|
+
tracker.logCapture?.capture("error", "riskyOperation failed", {
|
|
314
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
315
|
+
meta: { feature: "checkout" },
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
```
|
|
296
319
|
|
|
297
|
-
|
|
298
|
-
| ----------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------ |
|
|
299
|
-
| `useTracker()` | `UserTracker \| null` | Tracker from context. |
|
|
300
|
-
| `usePageView(path?)` | `void` | When `path` is defined, calls `trackPageView(path)` on change. No-op if `path` is omitted. |
|
|
301
|
-
| `useHeatmapData(path?, refreshMs?)` | `HeatmapPoint[]` | Live points for a path; optional debounced refresh (default 500 ms). |
|
|
302
|
-
| `usePageViews()` | `PageView[]` | Page views in the current session. |
|
|
303
|
-
| `useTrackRevenue()` | `(payload: RevenueEventPayload) => void` | Stable hook for recording purchases/subscriptions/refunds through the current tracker. |
|
|
304
|
-
| `useTimeSpent()` | `Record<string, number>` | Cumulative **milliseconds** per path. |
|
|
305
|
-
| `useFeatureFlags()` | `Record<string, boolean>` | Evaluated flags; updates after `identify()`. |
|
|
306
|
-
| `useFeatureFlagEnabled(key)` | `boolean` | Whether `key` is enabled. |
|
|
307
|
-
| `useAbTests()` | `Record<string, string \| null>` | Assigned variant per experiment key. |
|
|
308
|
-
| `useAbVariant(experimentKey)` | `string \| null` | Variant key for one experiment. |
|
|
309
|
-
| `useIsAbVariant(experiment, variant)` | `boolean` | Whether visitor is in that variant. |
|
|
320
|
+
## React API (`alphana-sdk/react`)
|
|
310
321
|
|
|
311
|
-
|
|
312
|
-
|
|
322
|
+
| Export | Description |
|
|
323
|
+
| ----------------------------------- | ----------------------------------------------------------------------------- |
|
|
324
|
+
| `UserTrackerProvider` | Creates one `UserTracker`, calls `init()` on mount, `destroy()` on unmount |
|
|
325
|
+
| `useTracker()` | Returns the tracker instance, or `null` outside a provider |
|
|
326
|
+
| `usePageView(path?)` | Records a page view when `path` changes (use with `usePathname()` in Next.js) |
|
|
327
|
+
| `usePageViews()` | Live list of session page views |
|
|
328
|
+
| `useTimeSpent()` | Live `Record<path, ms>` |
|
|
329
|
+
| `useHeatmapData(path?, refreshMs?)` | Live heatmap points for a path (debounced updates, default 500ms) |
|
|
330
|
+
| `useFeatureFlags()` | Live flag map; re-renders on `onFlagsChange` |
|
|
331
|
+
| `useFeatureFlagEnabled(key)` | Boolean for a single flag |
|
|
313
332
|
|
|
314
|
-
|
|
315
|
-
const tracker = useTracker();
|
|
316
|
-
const timeByPath = useTimeSpent();
|
|
317
|
-
const points = useHeatmapData();
|
|
333
|
+
`UserTrackerProvider` captures `config` only on the first render; changing props later does not reconfigure the tracker.
|
|
318
334
|
|
|
319
|
-
|
|
335
|
+
## Event types
|
|
320
336
|
|
|
321
|
-
|
|
322
|
-
<div>
|
|
323
|
-
<p>Paths tracked: {Object.keys(timeByPath).length}</p>
|
|
324
|
-
<p>Heatmap points (this page): {points.length}</p>
|
|
325
|
-
<button type="button" onClick={() => tracker.flush()}>
|
|
326
|
-
Flush now
|
|
327
|
-
</button>
|
|
328
|
-
</div>
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
```
|
|
337
|
+
Events flow through `onEvent`, `subscribe()`, the in-memory session, and the remote batch queue.
|
|
332
338
|
|
|
333
|
-
|
|
339
|
+
| `type` | Description |
|
|
340
|
+
| ----------- | -------------------------------------------------------------------------------- |
|
|
341
|
+
| `pageview` | Path, title, timestamp, referrer |
|
|
342
|
+
| `timespent` | Milliseconds spent on a path before leaving |
|
|
343
|
+
| `heatmap` | Mouse move, click, or scroll point (`xPct`, `yPct`, optional `target` on clicks) |
|
|
344
|
+
| `rageclik` | Rapid repeated clicks in one area |
|
|
345
|
+
| `uturn` | Left a page within ~5s (bounce signal) |
|
|
334
346
|
|
|
335
|
-
|
|
347
|
+
TypeScript definitions:
|
|
336
348
|
|
|
337
349
|
```ts
|
|
338
350
|
import type {
|
|
@@ -346,25 +358,61 @@ import type {
|
|
|
346
358
|
SessionData,
|
|
347
359
|
GeoLocation,
|
|
348
360
|
HeatmapRenderOptions,
|
|
349
|
-
RageClick,
|
|
350
|
-
UTurn,
|
|
351
|
-
RevenueEvent,
|
|
352
|
-
RevenueEventPayload,
|
|
353
|
-
RevenueEventStatus,
|
|
354
|
-
RevenueLineItem,
|
|
355
361
|
LogLevel,
|
|
356
362
|
LogEntry,
|
|
357
363
|
} from "alphana-sdk";
|
|
358
364
|
```
|
|
359
365
|
|
|
360
|
-
|
|
366
|
+
## Heatmap rendering
|
|
361
367
|
|
|
362
|
-
|
|
368
|
+
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.
|
|
363
369
|
|
|
364
|
-
|
|
370
|
+
```ts
|
|
371
|
+
import { renderHeatmap } from "alphana-sdk";
|
|
365
372
|
|
|
366
|
-
|
|
373
|
+
const canvas = document.getElementById("heatmap") as HTMLCanvasElement;
|
|
374
|
+
const points = tracker.getHeatmapData("/");
|
|
367
375
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
376
|
+
renderHeatmap(canvas, points, {
|
|
377
|
+
radius: 25,
|
|
378
|
+
maxOpacity: 0.85,
|
|
379
|
+
minOpacity: 0,
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Network behavior
|
|
384
|
+
|
|
385
|
+
| Traffic | Endpoint | When |
|
|
386
|
+
| ------------- | --------------------------------------- | ----------------------------------------------------------- |
|
|
387
|
+
| Event batch | `POST {endpoint}/batch` | Queue size ≥ `batchSize`, every `flushInterval`, or unload |
|
|
388
|
+
| Heartbeat | `POST {endpoint}/heartbeat` | Every 30s while tab visible; `active: false` on hide/unload |
|
|
389
|
+
| Logs | `POST {apiBase}/logs/ingest` | Each captured log line / error |
|
|
390
|
+
| Feature flags | `POST {apiBase}/feature-flags/evaluate` | On init and after `identify()` |
|
|
391
|
+
|
|
392
|
+
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.
|
|
393
|
+
|
|
394
|
+
Visitor country/city is resolved asynchronously from IP and attached to batch payloads when available.
|
|
395
|
+
|
|
396
|
+
## Package exports
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
// Core (framework-agnostic)
|
|
400
|
+
import {
|
|
401
|
+
UserTracker,
|
|
402
|
+
DEFAULT_ENDPOINT,
|
|
403
|
+
LogCapture,
|
|
404
|
+
renderHeatmap,
|
|
405
|
+
} from "alphana-sdk";
|
|
406
|
+
|
|
407
|
+
// React (optional)
|
|
408
|
+
import {
|
|
409
|
+
UserTrackerProvider,
|
|
410
|
+
useTracker,
|
|
411
|
+
usePageView,
|
|
412
|
+
useHeatmapData,
|
|
413
|
+
usePageViews,
|
|
414
|
+
useTimeSpent,
|
|
415
|
+
useFeatureFlags,
|
|
416
|
+
useFeatureFlagEnabled,
|
|
417
|
+
} from "alphana-sdk/react";
|
|
418
|
+
```
|