alphana-sdk 1.6.5 → 1.8.0
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 +239 -187
- package/dist/alphana-sdk.global.js +4 -4
- package/dist/index.d.mts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +23 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +24 -3
- package/dist/react/index.d.ts +24 -3
- package/dist/react/index.js +24 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +4 -4
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -2
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,176 @@ 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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
206
|
+
Publish the bundle with MinIO (see [CDN upload](#cdn-upload) below). The WordPress plugin and other non-bundler sites load this file.
|
|
207
|
+
|
|
208
|
+
## Configuration
|
|
209
|
+
|
|
210
|
+
All options are passed to `new UserTracker(config)` or `<UserTrackerProvider config={…} />`.
|
|
211
|
+
|
|
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
|
+
| `compressPayloads` | `boolean` | `true` | Gzip-compress large ingest bodies when the browser supports it |
|
|
227
|
+
| `compressionThresholdBytes` | `number` | `1024` | Minimum JSON size (bytes) before gzip is attempted |
|
|
228
|
+
| `collectEndpoint` | `string` | — | Override unified ingest URL (default: `{apiBase}/collect` from `endpoint`) |
|
|
229
|
+
| `heatmapPages` | `string[]` | — | Only capture heatmap data on these paths (from dashboard “Heatmap Pages”) |
|
|
230
|
+
| `onEvent` | `(event) => void` | — | Synchronous callback for every emitted event |
|
|
231
|
+
|
|
232
|
+
Example with heatmap path allowlist and custom sampling:
|
|
167
233
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| `batchSize` | `number` | `20` | Queue size before an automatic flush. |
|
|
182
|
-
| `flushInterval` | `number` (ms) | `5000` | Timer-based flush when the queue is non-empty. |
|
|
183
|
-
| `onEvent` | `(event: TrackerEvent) => void` | — | Synchronous callback for every emitted event. |
|
|
184
|
-
|
|
185
|
-
TypeScript marks `appId` / `secretKey` as optional on `TrackerConfig`, but you should always pass them when using the hosted Alphana API.
|
|
186
|
-
|
|
187
|
-
---
|
|
234
|
+
```ts
|
|
235
|
+
const tracker = new UserTracker({
|
|
236
|
+
appId: "YOUR_APP_ID",
|
|
237
|
+
secretKey: "YOUR_SECRET_KEY",
|
|
238
|
+
heatmapPages: ["/", "/pricing", "/dashboard"],
|
|
239
|
+
mouseSampleRate: 0.2,
|
|
240
|
+
onEvent: (event) => {
|
|
241
|
+
if (event.type === "rageclik") {
|
|
242
|
+
console.debug("Rage click", event.data);
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
```
|
|
188
247
|
|
|
189
|
-
## API
|
|
248
|
+
## Core API (`UserTracker`)
|
|
190
249
|
|
|
191
|
-
###
|
|
250
|
+
### Lifecycle
|
|
192
251
|
|
|
193
252
|
```ts
|
|
194
|
-
import { UserTracker } from "alphana-sdk";
|
|
253
|
+
import { UserTracker, DEFAULT_ENDPOINT } from "alphana-sdk";
|
|
195
254
|
|
|
196
|
-
const tracker = new UserTracker({ appId: "
|
|
197
|
-
|
|
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
|
-
});
|
|
255
|
+
const tracker = new UserTracker({ appId: "…", secretKey: "…" });
|
|
209
256
|
|
|
210
|
-
tracker.
|
|
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
|
|
257
|
+
tracker.init(); // attach listeners; safe on server (no-op)
|
|
258
|
+
tracker.destroy(); // remove listeners, flush queue via sendBeacon
|
|
233
259
|
```
|
|
234
260
|
|
|
235
|
-
|
|
261
|
+
`DEFAULT_ENDPOINT` is exported if you need the cloud default URL in your own config layer.
|
|
236
262
|
|
|
237
|
-
|
|
263
|
+
### Manual page views
|
|
238
264
|
|
|
239
|
-
|
|
265
|
+
```ts
|
|
266
|
+
tracker.trackPageView("/products?id=1");
|
|
267
|
+
```
|
|
240
268
|
|
|
241
|
-
|
|
269
|
+
Dispatches a `pageview` event and the custom DOM event `tracker:navigate` (used internally by time and heatmap plugins).
|
|
242
270
|
|
|
243
|
-
|
|
271
|
+
### Session data (in-memory)
|
|
244
272
|
|
|
245
|
-
|
|
273
|
+
```ts
|
|
274
|
+
tracker.getSession(); // full snapshot: id, visitorId, pageViews, timeSpent, heatmap, location
|
|
275
|
+
tracker.getPageViews(); // PageView[]
|
|
276
|
+
tracker.getTimeSpent(); // Record<path, milliseconds>
|
|
277
|
+
tracker.getHeatmapData("/"); // HeatmapPoint[] for one path
|
|
278
|
+
tracker.getHeatmapData(); // Record<path, HeatmapPoint[]>
|
|
279
|
+
```
|
|
246
280
|
|
|
247
|
-
|
|
281
|
+
### Subscribing to events
|
|
248
282
|
|
|
249
283
|
```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_...",
|
|
284
|
+
const unsub = tracker.subscribe((event) => {
|
|
285
|
+
console.log(event.type, event.data);
|
|
257
286
|
});
|
|
258
|
-
|
|
259
|
-
capture.init();
|
|
260
|
-
capture.capture("error", "Something failed", { stack: err.stack });
|
|
261
|
-
capture.destroy();
|
|
287
|
+
unsub();
|
|
262
288
|
```
|
|
263
289
|
|
|
264
|
-
###
|
|
290
|
+
### Feature flags
|
|
265
291
|
|
|
266
|
-
|
|
292
|
+
Requires `secretKey`. Flags are fetched on `init()` and after each `identify()` call.
|
|
267
293
|
|
|
268
294
|
```ts
|
|
269
|
-
|
|
295
|
+
tracker.identify({ email: "user@example.com", plan: "enterprise" });
|
|
270
296
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
canvas.height = 720;
|
|
297
|
+
tracker.getFlags(); // { "flag-key": true, ... }
|
|
298
|
+
tracker.isFeatureEnabled("flag-key"); // boolean
|
|
274
299
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
maxOpacity: 0.85,
|
|
278
|
-
minOpacity: 0,
|
|
300
|
+
const unsub = tracker.onFlagsChange((flags) => {
|
|
301
|
+
console.log("Flags updated", flags);
|
|
279
302
|
});
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### `DEFAULT_ENDPOINT`
|
|
303
|
+
unsub();
|
|
283
304
|
|
|
284
|
-
|
|
285
|
-
import { DEFAULT_ENDPOINT } from "alphana-sdk";
|
|
286
|
-
// "https://api.alphana.ir/api/events"
|
|
305
|
+
await tracker.fetchFlags(); // manual refresh
|
|
287
306
|
```
|
|
288
307
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
## React hooks
|
|
308
|
+
### Error logging (manual)
|
|
292
309
|
|
|
293
|
-
|
|
310
|
+
When `trackLogs` is enabled, `tracker.logCapture` is available after `init()`:
|
|
294
311
|
|
|
295
|
-
|
|
312
|
+
```ts
|
|
313
|
+
try {
|
|
314
|
+
riskyOperation();
|
|
315
|
+
} catch (err) {
|
|
316
|
+
tracker.logCapture?.capture("error", "riskyOperation failed", {
|
|
317
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
318
|
+
meta: { feature: "checkout" },
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
```
|
|
296
322
|
|
|
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. |
|
|
323
|
+
## React API (`alphana-sdk/react`)
|
|
310
324
|
|
|
311
|
-
|
|
312
|
-
|
|
325
|
+
| Export | Description |
|
|
326
|
+
| ----------------------------------- | ----------------------------------------------------------------------------- |
|
|
327
|
+
| `UserTrackerProvider` | Creates one `UserTracker`, calls `init()` on mount, `destroy()` on unmount |
|
|
328
|
+
| `useTracker()` | Returns the tracker instance, or `null` outside a provider |
|
|
329
|
+
| `usePageView(path?)` | Records a page view when `path` changes (use with `usePathname()` in Next.js) |
|
|
330
|
+
| `usePageViews()` | Live list of session page views |
|
|
331
|
+
| `useTimeSpent()` | Live `Record<path, ms>` |
|
|
332
|
+
| `useHeatmapData(path?, refreshMs?)` | Live heatmap points for a path (debounced updates, default 500ms) |
|
|
333
|
+
| `useFeatureFlags()` | Live flag map; re-renders on `onFlagsChange` |
|
|
334
|
+
| `useFeatureFlagEnabled(key)` | Boolean for a single flag |
|
|
313
335
|
|
|
314
|
-
|
|
315
|
-
const tracker = useTracker();
|
|
316
|
-
const timeByPath = useTimeSpent();
|
|
317
|
-
const points = useHeatmapData();
|
|
336
|
+
`UserTrackerProvider` captures `config` only on the first render; changing props later does not reconfigure the tracker.
|
|
318
337
|
|
|
319
|
-
|
|
338
|
+
## Event types
|
|
320
339
|
|
|
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
|
-
```
|
|
340
|
+
Events flow through `onEvent`, `subscribe()`, the in-memory session, and the remote batch queue.
|
|
332
341
|
|
|
333
|
-
|
|
342
|
+
| `type` | Description |
|
|
343
|
+
| ----------- | -------------------------------------------------------------------------------- |
|
|
344
|
+
| `pageview` | Path, title, timestamp, referrer |
|
|
345
|
+
| `timespent` | Milliseconds spent on a path before leaving |
|
|
346
|
+
| `heatmap` | Mouse move, click, or scroll point (`xPct`, `yPct`, optional `target` on clicks) |
|
|
347
|
+
| `rageclik` | Rapid repeated clicks in one area |
|
|
348
|
+
| `uturn` | Left a page within ~5s (bounce signal) |
|
|
334
349
|
|
|
335
|
-
|
|
350
|
+
TypeScript definitions:
|
|
336
351
|
|
|
337
352
|
```ts
|
|
338
353
|
import type {
|
|
@@ -346,25 +361,62 @@ import type {
|
|
|
346
361
|
SessionData,
|
|
347
362
|
GeoLocation,
|
|
348
363
|
HeatmapRenderOptions,
|
|
349
|
-
RageClick,
|
|
350
|
-
UTurn,
|
|
351
|
-
RevenueEvent,
|
|
352
|
-
RevenueEventPayload,
|
|
353
|
-
RevenueEventStatus,
|
|
354
|
-
RevenueLineItem,
|
|
355
364
|
LogLevel,
|
|
356
365
|
LogEntry,
|
|
357
366
|
} from "alphana-sdk";
|
|
358
367
|
```
|
|
359
368
|
|
|
360
|
-
|
|
369
|
+
## Heatmap rendering
|
|
370
|
+
|
|
371
|
+
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.
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
import { renderHeatmap } from "alphana-sdk";
|
|
375
|
+
|
|
376
|
+
const canvas = document.getElementById("heatmap") as HTMLCanvasElement;
|
|
377
|
+
const points = tracker.getHeatmapData("/");
|
|
378
|
+
|
|
379
|
+
renderHeatmap(canvas, points, {
|
|
380
|
+
radius: 25,
|
|
381
|
+
maxOpacity: 0.85,
|
|
382
|
+
minOpacity: 0,
|
|
383
|
+
});
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Network behavior
|
|
387
|
+
|
|
388
|
+
| Traffic | Endpoint | When |
|
|
389
|
+
| ------------- | --------------------------------------- | ----------------------------------------------------------- |
|
|
390
|
+
| Collect (SDK ≥ 1.8) | `POST {apiBase}/collect` | Event batches, heartbeats, and logs (multiplexed envelope) |
|
|
391
|
+
| Event batch | `POST {endpoint}/batch` | Legacy SDK < 1.8 — still supported on the backend |
|
|
392
|
+
| Heartbeat | `POST {endpoint}/heartbeat` | Legacy SDK < 1.8 |
|
|
393
|
+
| Logs | `POST {apiBase}/logs/ingest` | Legacy SDK < 1.8 |
|
|
394
|
+
| Feature flags | `POST {apiBase}/feature-flags/evaluate` | On init and after `identify()` |
|
|
395
|
+
|
|
396
|
+
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.
|
|
361
397
|
|
|
362
|
-
|
|
398
|
+
Visitor country/city is resolved asynchronously from IP and attached to batch payloads when available.
|
|
363
399
|
|
|
364
|
-
|
|
400
|
+
## Package exports
|
|
365
401
|
|
|
366
|
-
|
|
402
|
+
```ts
|
|
403
|
+
// Core (framework-agnostic)
|
|
404
|
+
import {
|
|
405
|
+
UserTracker,
|
|
406
|
+
DEFAULT_ENDPOINT,
|
|
407
|
+
LogCapture,
|
|
408
|
+
renderHeatmap,
|
|
409
|
+
} from "alphana-sdk";
|
|
367
410
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
411
|
+
// React (optional)
|
|
412
|
+
import {
|
|
413
|
+
UserTrackerProvider,
|
|
414
|
+
useTracker,
|
|
415
|
+
usePageView,
|
|
416
|
+
useHeatmapData,
|
|
417
|
+
usePageViews,
|
|
418
|
+
useTimeSpent,
|
|
419
|
+
useFeatureFlags,
|
|
420
|
+
useFeatureFlagEnabled,
|
|
421
|
+
} from "alphana-sdk/react";
|
|
422
|
+
```
|