@deriv-com/analytics 1.42.0 → 1.42.1
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 +144 -61
- package/dist/browser/analytics.bundle.global.js +5 -5
- package/dist/browser/analytics.bundle.global.js.map +1 -1
- package/dist/browser/analytics.esm.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/metafile-cjs.json +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/metafile-iife.json +1 -1
- package/dist/{posthog-ctBaPjWr.d.mts → posthog-DmVmqDsn.d.mts} +13 -0
- package/dist/{posthog-ctBaPjWr.d.ts → posthog-DmVmqDsn.d.ts} +13 -0
- package/dist/posthog-QH4OCJ4V.mjs +4 -0
- package/dist/{posthog-54CQ2T32.mjs.map → posthog-QH4OCJ4V.mjs.map} +1 -1
- package/dist/providers/posthog/index.d.mts +1 -1
- package/dist/providers/posthog/index.d.ts +1 -1
- package/dist/providers/posthog/index.js +2 -2
- package/dist/providers/posthog/index.js.map +1 -1
- package/dist/providers/posthog/index.mjs +2 -2
- package/dist/providers/posthog/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/posthog-54CQ2T32.mjs +0 -4
package/README.md
CHANGED
|
@@ -28,6 +28,10 @@ A modern, tree-shakeable analytics library for tracking user events with RudderS
|
|
|
28
28
|
- [Configuration](#configuration)
|
|
29
29
|
- [RudderStack](#rudderstack-configuration)
|
|
30
30
|
- [PostHog](#posthog-configuration)
|
|
31
|
+
- [Enforced settings](#enforced-settings)
|
|
32
|
+
- [Overridable defaults](#overridable-defaults)
|
|
33
|
+
- [Do not capture $pageview manually](#-do-not-capture-pageview-manually)
|
|
34
|
+
- [Domain allowlist](#domain-allowlist)
|
|
31
35
|
- [Core API](#core-api)
|
|
32
36
|
- [Initialization](#initialization)
|
|
33
37
|
- [Event Tracking](#event-tracking)
|
|
@@ -37,6 +41,8 @@ A modern, tree-shakeable analytics library for tracking user events with RudderS
|
|
|
37
41
|
- [Caching & Offline Support](#caching--offline-support)
|
|
38
42
|
- [Debug Mode](#debug-mode)
|
|
39
43
|
- [Advanced Usage](#advanced-usage)
|
|
44
|
+
- [PostHog Feature Flags](#posthog-feature-flags)
|
|
45
|
+
- [PostHog Integration Checklist](#posthog-integration-checklist)
|
|
40
46
|
- [API Reference](#api-reference)
|
|
41
47
|
- [Performance](#performance)
|
|
42
48
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -379,52 +385,31 @@ await Analytics.initialise({
|
|
|
379
385
|
|
|
380
386
|
### PostHog Configuration
|
|
381
387
|
|
|
382
|
-
PostHog provides
|
|
388
|
+
PostHog provides analytics, session recording, and feature flags.
|
|
389
|
+
|
|
390
|
+
#### Initialisation
|
|
391
|
+
|
|
392
|
+
`getPosthogInstance` (and `Analytics.initialise`) use a singleton — calling them more than once with the same key returns the existing instance without re-running the SDK init. Call once at app startup, not inside render loops.
|
|
383
393
|
|
|
384
394
|
```typescript
|
|
385
395
|
await Analytics.initialise({
|
|
386
396
|
rudderstackKey: 'YOUR_RUDDERSTACK_KEY',
|
|
387
397
|
posthogOptions: {
|
|
388
|
-
// Required: API key
|
|
389
398
|
apiKey: 'phc_YOUR_KEY',
|
|
390
399
|
|
|
391
|
-
// Optional:
|
|
392
|
-
// If omitted, the host is auto-selected at init time based on window.location.hostname:
|
|
393
|
-
// *.deriv.me → https://ph.deriv.me
|
|
394
|
-
// *.deriv.be → https://ph.deriv.be
|
|
395
|
-
// *.deriv.ae → https://ph.deriv.ae
|
|
396
|
-
// all others → https://ph.deriv.com (default, also used in SSR/non-browser environments)
|
|
397
|
-
// Set this explicitly if you need to override the resolved host (e.g. in tests or custom deployments).
|
|
400
|
+
// Optional: override the auto-resolved API host (see table below)
|
|
398
401
|
api_host: 'https://ph.deriv.com',
|
|
399
402
|
|
|
400
|
-
// Optional:
|
|
403
|
+
// Optional: overridable settings (see "Overridable defaults" table below)
|
|
401
404
|
config: {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
ui_host: 'https://us.posthog.com',
|
|
405
|
-
|
|
406
|
-
// Session recording
|
|
405
|
+
autocapture: false, // disable autocapture entirely
|
|
406
|
+
disable_session_recording: true, // opt out of session recording
|
|
407
407
|
session_recording: {
|
|
408
|
-
|
|
409
|
-
maskAllInputs: false,
|
|
410
|
-
minimumDurationMilliseconds: 30000, // Only save sessions longer than 30 seconds
|
|
408
|
+
sessionRecordingSampleRate: 0.5, // record 50% of sessions
|
|
411
409
|
},
|
|
412
|
-
|
|
413
|
-
// Feature capture
|
|
414
|
-
autocapture: true, // Automatically capture clicks, form submissions, etc.
|
|
415
|
-
capture_pageview: true, // Automatically capture page views
|
|
416
|
-
capture_pageleave: true, // Capture when users leave pages
|
|
417
|
-
|
|
418
|
-
// Console log recording (useful for debugging)
|
|
419
|
-
enable_recording_console_log: true,
|
|
420
|
-
|
|
421
|
-
// Disable features if needed
|
|
422
|
-
disable_session_recording: false,
|
|
423
|
-
disable_surveys: false,
|
|
424
|
-
|
|
425
|
-
// Custom event filtering
|
|
426
410
|
before_send: event => {
|
|
427
|
-
//
|
|
411
|
+
// your function runs after the built-in domain + timestamp filter
|
|
412
|
+
if (event?.properties?.sensitive_field) return null
|
|
428
413
|
return event
|
|
429
414
|
},
|
|
430
415
|
},
|
|
@@ -432,46 +417,77 @@ await Analytics.initialise({
|
|
|
432
417
|
})
|
|
433
418
|
```
|
|
434
419
|
|
|
435
|
-
|
|
420
|
+
`api_host` is auto-resolved from `window.location.hostname` if omitted:
|
|
436
421
|
|
|
437
|
-
|
|
422
|
+
| Domain pattern | Resolved host |
|
|
423
|
+
| ---------------------- | ---------------------- |
|
|
424
|
+
| `*.deriv.me` | `https://ph.deriv.me` |
|
|
425
|
+
| `*.deriv.be` | `https://ph.deriv.be` |
|
|
426
|
+
| `*.deriv.ae` | `https://ph.deriv.ae` |
|
|
427
|
+
| all others (incl. SSR) | `https://ph.deriv.com` |
|
|
438
428
|
|
|
439
|
-
####
|
|
429
|
+
#### Enforced settings
|
|
440
430
|
|
|
441
|
-
|
|
431
|
+
These are applied **after** any consumer `config` spread. Passing them in `config` has no effect:
|
|
442
432
|
|
|
443
|
-
|
|
444
|
-
|
|
433
|
+
| Setting | Value | Reason |
|
|
434
|
+
| ----------------------------------------------- | ------------------- | ------------------------------------------------------ |
|
|
435
|
+
| `person_profiles` | `'identified_only'` | Prevents anonymous profile bloat |
|
|
436
|
+
| `capture_pageview` | `'history_change'` | SPA-safe — fires on every `pushState` / `replaceState` |
|
|
437
|
+
| `capture_pageleave` | `true` | Standard session completeness |
|
|
438
|
+
| `session_recording.recordCrossOriginIframes` | `true` | Captures embedded tools |
|
|
439
|
+
| `session_recording.minimumDurationMilliseconds` | `30000` | Filters sub-30-second noise sessions |
|
|
440
|
+
| `session_recording.maskAllInputs` | `true` | Privacy — cannot be lowered by consumers |
|
|
441
|
+
|
|
442
|
+
Consumer keys inside `session_recording` are spread **before** these enforced values, so extras like `sessionRecordingSampleRate` take effect without conflicting.
|
|
443
|
+
|
|
444
|
+
#### Overridable defaults
|
|
445
445
|
|
|
446
|
-
|
|
446
|
+
| Setting | Default | Override when… |
|
|
447
|
+
| ---------------------------------- | ------------------------------------ | ------------------------------------------------------------------ |
|
|
448
|
+
| `autocapture` | `{ dom_event_allowlist: ['click'] }` | You need more event types, or want to disable autocapture entirely |
|
|
449
|
+
| `rate_limiting.events_per_second` | `10` | Legitimate user flows are hitting the burst limiter |
|
|
450
|
+
| `rate_limiting.events_burst_limit` | `100` | Legitimate user flows are hitting the burst limiter |
|
|
447
451
|
|
|
448
|
-
####
|
|
452
|
+
#### ⚠ Do not capture `$pageview` manually
|
|
453
|
+
|
|
454
|
+
`capture_pageview: 'history_change'` is enforced and fires automatically on every client-side navigation. Adding a manual `posthog.capture('$pageview')` **doubles your pageview count** and contributes to `$client_ingestion_warning` rate-limit hits.
|
|
455
|
+
|
|
456
|
+
**React Router:**
|
|
449
457
|
|
|
450
458
|
```typescript
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
// Record content from iframes
|
|
456
|
-
recordCrossOriginIframes: true,
|
|
459
|
+
// ❌ Remove this
|
|
460
|
+
useEffect(() => {
|
|
461
|
+
posthog.capture('$pageview')
|
|
462
|
+
}, [location.pathname])
|
|
457
463
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
maskInputOptions: {
|
|
461
|
-
password: true,
|
|
462
|
-
email: true,
|
|
463
|
-
},
|
|
464
|
+
// ✅ Nothing needed — capture_pageview: 'history_change' handles it
|
|
465
|
+
```
|
|
464
466
|
|
|
465
|
-
|
|
466
|
-
minimumDurationMilliseconds: 60000,
|
|
467
|
+
**Vue Router:**
|
|
467
468
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
469
|
+
```typescript
|
|
470
|
+
// ❌ Remove this
|
|
471
|
+
router.afterEach(() => {
|
|
472
|
+
posthog.capture('$pageview')
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
// ✅ Nothing needed — capture_pageview: 'history_change' handles it
|
|
473
476
|
```
|
|
474
477
|
|
|
478
|
+
#### Domain allowlist
|
|
479
|
+
|
|
480
|
+
Events are silently blocked in `before_send` unless the hostname matches:
|
|
481
|
+
|
|
482
|
+
- `deriv.com`, `deriv.be`, `deriv.me`, `deriv.team`, `deriv.ae`
|
|
483
|
+
- `localhost` and `127.0.0.1` are always allowed
|
|
484
|
+
|
|
485
|
+
This list is hardcoded and not configurable.
|
|
486
|
+
|
|
487
|
+
#### Stale cookie cleanup
|
|
488
|
+
|
|
489
|
+
On every init, leftover `ph_*_posthog` cookies from previous or rotated API keys are removed automatically. No action needed.
|
|
490
|
+
|
|
475
491
|
## Core API
|
|
476
492
|
|
|
477
493
|
### Initialization
|
|
@@ -556,6 +572,22 @@ Analytics.identifyEvent('CR123456', {
|
|
|
556
572
|
- PostHog automatically handles aliasing between anonymous and identified users
|
|
557
573
|
- When `email` is provided in PostHog traits, the `is_internal` flag is automatically computed and set as a person property — `email` itself is **not** forwarded to PostHog
|
|
558
574
|
|
|
575
|
+
#### PostHog identity lifecycle
|
|
576
|
+
|
|
577
|
+
| Scenario | Call |
|
|
578
|
+
| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
579
|
+
| User logs in | `identifyEvent(user_id, { posthog: { email, language, country_of_residence } })` |
|
|
580
|
+
| User logs out | `reset()` |
|
|
581
|
+
| User already identified in a previous session, person properties may be missing | `backfillPersonProperties({ user_id, email, language, country_of_residence })` |
|
|
582
|
+
|
|
583
|
+
**`identifyEvent`** links the anonymous PostHog session to the user and enforces `client_id`. Skip it if the current distinct ID is already the same `user_id` — the library does this check automatically.
|
|
584
|
+
|
|
585
|
+
**`reset`** clears the PostHog session on logout. Future events are anonymous until the next `identifyEvent`.
|
|
586
|
+
|
|
587
|
+
**`backfillPersonProperties`** fills in properties that may be missing on a returning user's profile (e.g. `client_id`, `is_internal`). It checks each property before writing and is a no-op if everything is already present. Call it once after the user ID is available, alongside or instead of `identifyEvent` for returning users.
|
|
588
|
+
|
|
589
|
+
> **Account-switch guard**: both `identifyEvent` and `backfillPersonProperties` detect when PostHog's stored distinct ID belongs to a _different_ identified user (not an anonymous UUID) and call `posthog.reset()` automatically before identifying the new user. This prevents profiles from merging across accounts.
|
|
590
|
+
|
|
559
591
|
### Page Views
|
|
560
592
|
|
|
561
593
|
Track page navigation:
|
|
@@ -574,7 +606,7 @@ Analytics.pageView('/trade', 'Deriv App', {
|
|
|
574
606
|
})
|
|
575
607
|
```
|
|
576
608
|
|
|
577
|
-
**Note**: PostHog automatically
|
|
609
|
+
**Note**: PostHog page views are captured automatically via the enforced `capture_pageview: 'history_change'` setting. Do not call `posthog.capture('$pageview')` manually — see the [⚠ Do not capture `$pageview` manually](#-do-not-capture-pageview-manually) section. Manual page view tracking via `Analytics.pageView()` is primarily for RudderStack.
|
|
578
610
|
|
|
579
611
|
### User Attributes
|
|
580
612
|
|
|
@@ -729,6 +761,57 @@ if (tracking?.has_initialized) {
|
|
|
729
761
|
}
|
|
730
762
|
```
|
|
731
763
|
|
|
764
|
+
## PostHog Feature Flags
|
|
765
|
+
|
|
766
|
+
Access feature flags through the `posthog` instance:
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
const { posthog } = Analytics.getInstances()
|
|
770
|
+
|
|
771
|
+
// Boolean flag — returns true, false, or undefined (not ready)
|
|
772
|
+
const isEnabled = posthog?.isFeatureEnabled('my-flag')
|
|
773
|
+
|
|
774
|
+
// Multivariate flag — returns a string variant, boolean, or undefined
|
|
775
|
+
const variant = posthog?.getFeatureFlag('button-color') // e.g. 'red' | 'blue' | true | undefined
|
|
776
|
+
|
|
777
|
+
// Structured payload attached to a flag
|
|
778
|
+
const config = posthog?.getFeatureFlagPayload('pricing-config') // e.g. { price: 9.99 }
|
|
779
|
+
|
|
780
|
+
// All active flags as a map
|
|
781
|
+
const allFlags = posthog?.getAllFlags() // { 'flag-a': true, 'flag-b': 'variant-x' }
|
|
782
|
+
|
|
783
|
+
// Subscribe to flag changes (fires immediately + on every reload)
|
|
784
|
+
const unsubscribe = posthog?.onFeatureFlags((flags, variants) => {
|
|
785
|
+
console.log('active flags:', flags)
|
|
786
|
+
console.log('variants:', variants)
|
|
787
|
+
})
|
|
788
|
+
// Call unsubscribe() to stop listening
|
|
789
|
+
|
|
790
|
+
// Force a reload from the server (e.g. after login or attribute change)
|
|
791
|
+
posthog?.reloadFeatureFlags()
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
When using PostHog directly (without the `Analytics` wrapper):
|
|
795
|
+
|
|
796
|
+
```typescript
|
|
797
|
+
import { Posthog } from '@deriv-com/analytics/posthog'
|
|
798
|
+
|
|
799
|
+
const posthog = Posthog.getPosthogInstance({ apiKey: 'phc_YOUR_KEY' })
|
|
800
|
+
const isEnabled = posthog.isFeatureEnabled('my-flag')
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
## PostHog Integration Checklist
|
|
804
|
+
|
|
805
|
+
Before shipping, verify:
|
|
806
|
+
|
|
807
|
+
- [ ] `Analytics.initialise` (or `getPosthogInstance`) is called **once** at app startup — not on every render or route change
|
|
808
|
+
- [ ] No `posthog.capture('$pageview')` calls remain — search the codebase and remove them
|
|
809
|
+
- [ ] `identifyEvent` is called on login with `email` in PostHog traits (needed for the `is_internal` flag)
|
|
810
|
+
- [ ] `reset()` is called on logout
|
|
811
|
+
- [ ] `backfillPersonProperties` is called for returning users when the user ID is available
|
|
812
|
+
- [ ] Your domain is in the allowlist — if testing on a non-`deriv.*` domain other than `localhost`, events are silently blocked
|
|
813
|
+
- [ ] `debug: true` is removed or guarded behind `process.env.NODE_ENV === 'development'`
|
|
814
|
+
|
|
732
815
|
## API Reference
|
|
733
816
|
|
|
734
817
|
### `initialise(options: Options): Promise<void>`
|