@deriv-com/analytics 1.39.7 → 1.40.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.
Files changed (47) hide show
  1. package/README.md +148 -145
  2. package/dist/browser/analytics.bundle.global.js +5 -5
  3. package/dist/browser/analytics.bundle.global.js.map +1 -1
  4. package/dist/browser/analytics.esm.mjs +1 -1
  5. package/dist/browser/analytics.esm.mjs.map +1 -1
  6. package/dist/{chunk-GTT7DF4Y.mjs → chunk-4V72P52P.mjs} +2 -2
  7. package/dist/chunk-4V72P52P.mjs.map +1 -0
  8. package/dist/{chunk-YZ34YKBW.js → chunk-6BHMKTVG.js} +2 -2
  9. package/dist/chunk-6BHMKTVG.js.map +1 -0
  10. package/dist/index.d.mts +9 -10
  11. package/dist/index.d.ts +9 -10
  12. package/dist/index.js +2 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +2 -2
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/metafile-cjs.json +1 -1
  17. package/dist/metafile-esm.json +1 -1
  18. package/dist/metafile-iife.json +1 -1
  19. package/dist/{posthog-DUxm7AzZ.d.ts → posthog-BqcxWQRm.d.mts} +4 -3
  20. package/dist/{posthog-DfHTd53-.d.mts → posthog-BqcxWQRm.d.ts} +4 -3
  21. package/dist/{posthog-B3LUVMYU.mjs → posthog-OLSRFYED.mjs} +3 -3
  22. package/dist/{posthog-B3LUVMYU.mjs.map → posthog-OLSRFYED.mjs.map} +1 -1
  23. package/dist/providers/posthog/index.d.mts +1 -2
  24. package/dist/providers/posthog/index.d.ts +1 -2
  25. package/dist/providers/posthog/index.js +2 -2
  26. package/dist/providers/posthog/index.js.map +1 -1
  27. package/dist/providers/posthog/index.mjs +2 -2
  28. package/dist/providers/posthog/index.mjs.map +1 -1
  29. package/dist/providers/rudderstack/index.d.mts +1 -2
  30. package/dist/providers/rudderstack/index.d.ts +1 -2
  31. package/dist/providers/rudderstack/index.js +1 -1
  32. package/dist/providers/rudderstack/index.mjs +1 -1
  33. package/package.json +1 -6
  34. package/dist/chunk-5PFWZVJN.mjs +0 -3
  35. package/dist/chunk-5PFWZVJN.mjs.map +0 -1
  36. package/dist/chunk-GTT7DF4Y.mjs.map +0 -1
  37. package/dist/chunk-NCHU4435.js +0 -3
  38. package/dist/chunk-NCHU4435.js.map +0 -1
  39. package/dist/chunk-YZ34YKBW.js.map +0 -1
  40. package/dist/types-DoMejCXv.d.mts +0 -361
  41. package/dist/types-DoMejCXv.d.ts +0 -361
  42. package/dist/utils/analytics-cache/index.d.mts +0 -139
  43. package/dist/utils/analytics-cache/index.d.ts +0 -139
  44. package/dist/utils/analytics-cache/index.js +0 -2
  45. package/dist/utils/analytics-cache/index.js.map +0 -1
  46. package/dist/utils/analytics-cache/index.mjs +0 -2
  47. package/dist/utils/analytics-cache/index.mjs.map +0 -1
package/README.md CHANGED
@@ -8,9 +8,8 @@ A modern, tree-shakeable analytics library for tracking user events with RudderS
8
8
  - 🎄 **Tree-Shakeable**: Only bundle what you use - each provider can be imported independently
9
9
  - 📡 **Offline-First**: Automatic event caching when offline with replay on reconnection
10
10
  - ⚡ **Performance Optimized**: Batching, deduplication, and SendBeacon API for fast tracking
11
- - 🔐 **Type-Safe**: Full TypeScript support with discriminated unions for event payloads
12
11
  - 🔄 **Backward Compatible**: Supports older React, Node.js, and other legacy package versions
13
- - 💾 **Advanced Caching**: Cookie-based and in-memory caching for robust event delivery
12
+ - 💾 **Advanced Caching**: localStorage and in-memory caching for robust event delivery
14
13
  - 🎥 **Session Recording**: Built-in PostHog session recording with customizable settings
15
14
 
16
15
  > **Note**: GrowthBook support is deprecated and will be removed in a future major version. For A/B testing and feature flags, we recommend using PostHog's built-in feature flag capabilities.
@@ -124,7 +123,6 @@ await Analytics.initialise({
124
123
  // PostHog for analytics and session recording (optional)
125
124
  posthogOptions: {
126
125
  apiKey: 'phc_YOUR_POSTHOG_KEY',
127
- allowedDomains: ['deriv.com', 'deriv.team', 'deriv.ae'],
128
126
  config: {
129
127
  session_recording: {
130
128
  recordCrossOriginIframes: true,
@@ -153,41 +151,58 @@ Analytics.identifyEvent('CR123456', {
153
151
 
154
152
  ### React Integration
155
153
 
156
- Create an analytics initialization hook:
154
+ The recommended pattern is a single `useAnalytics` hook that handles initialization and exposes all tracking methods:
157
155
 
158
156
  ```typescript
159
157
  // hooks/useAnalytics.ts
160
158
  import { useEffect } from 'react'
161
159
  import { Analytics } from '@deriv-com/analytics'
162
160
 
161
+ let isInitialized = false
162
+
163
163
  export function useAnalytics() {
164
164
  useEffect(() => {
165
+ if (isInitialized) return
166
+ isInitialized = true
167
+
168
+ const rudderstackKey = process.env.REACT_APP_RUDDERSTACK_KEY // ← replace with your env var
169
+ const posthogKey = process.env.REACT_APP_POSTHOG_KEY // ← replace with your env var
170
+
171
+ if (!rudderstackKey && !posthogKey) return
172
+
165
173
  Analytics.initialise({
166
- rudderstackKey: process.env.REACT_APP_RUDDERSTACK_KEY!,
167
- posthogOptions: {
168
- apiKey: process.env.REACT_APP_POSTHOG_KEY!,
169
- config: {
170
- autocapture: true,
174
+ ...(rudderstackKey && { rudderstackKey }),
175
+ ...(posthogKey && {
176
+ posthogOptions: {
177
+ apiKey: posthogKey,
178
+ api_host: process.env.REACT_APP_POSTHOG_HOST,
171
179
  },
172
- },
180
+ }),
181
+ debug: process.env.NODE_ENV === 'development',
173
182
  })
174
183
  }, [])
184
+
185
+ return {
186
+ trackEvent: Analytics.trackEvent,
187
+ identifyEvent: Analytics.identifyEvent,
188
+ pageView: Analytics.pageView,
189
+ loadEvent: Analytics.loadEvent,
190
+ setAttributes: Analytics.setAttributes,
191
+ reset: Analytics.reset,
192
+ }
175
193
  }
194
+ ```
176
195
 
196
+ Call the hook once at the top of your app:
197
+
198
+ ```tsx
177
199
  // App.tsx
178
200
  import { useAnalytics } from './hooks/useAnalytics'
179
201
 
180
202
  function App() {
181
- useAnalytics()
203
+ const { trackEvent } = useAnalytics()
182
204
 
183
- const handleSignup = () => {
184
- Analytics.trackEvent('ce_virtual_signup_form', {
185
- action: 'signup_modal_open',
186
- form_source: 'header_cta',
187
- })
188
- }
189
-
190
- return <button onClick={handleSignup}>Sign Up</button>
205
+ return <button onClick={() => trackEvent('ce_signup_button', { action: 'click' })}>Sign Up</button>
191
206
  }
192
207
  ```
193
208
 
@@ -195,28 +210,63 @@ function App() {
195
210
 
196
211
  #### App Router (Next.js 13+)
197
212
 
213
+ Use the same `useAnalytics` hook (with `NEXT_PUBLIC_` env var prefix) inside a dedicated client provider:
214
+
198
215
  ```typescript
199
- // app/providers.tsx
216
+ // hooks/useAnalytics.ts
200
217
  'use client'
201
218
 
202
- import { Analytics } from '@deriv-com/analytics'
203
219
  import { useEffect } from 'react'
220
+ import { Analytics } from '@deriv-com/analytics'
204
221
 
205
- export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
222
+ let isInitialized = false
223
+
224
+ export function useAnalytics() {
206
225
  useEffect(() => {
226
+ if (isInitialized) return
227
+ isInitialized = true
228
+
229
+ const rudderstackKey = process.env.NEXT_PUBLIC_RUDDERSTACK_KEY // ← replace with your env var
230
+ const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY // ← replace with your env var
231
+
232
+ if (!rudderstackKey && !posthogKey) return
233
+
207
234
  Analytics.initialise({
208
- rudderstackKey: process.env.NEXT_PUBLIC_RUDDERSTACK_KEY!,
209
- posthogOptions: {
210
- apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY!,
211
- },
235
+ ...(rudderstackKey && { rudderstackKey }),
236
+ ...(posthogKey && {
237
+ posthogOptions: {
238
+ apiKey: posthogKey,
239
+ api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
240
+ },
241
+ }),
242
+ debug: process.env.NODE_ENV === 'development',
212
243
  })
213
244
  }, [])
214
245
 
246
+ return {
247
+ trackEvent: Analytics.trackEvent,
248
+ identifyEvent: Analytics.identifyEvent,
249
+ pageView: Analytics.pageView,
250
+ loadEvent: Analytics.loadEvent,
251
+ setAttributes: Analytics.setAttributes,
252
+ reset: Analytics.reset,
253
+ }
254
+ }
255
+ ```
256
+
257
+ ```tsx
258
+ // app/analytics-provider.tsx
259
+ 'use client'
260
+
261
+ import { useAnalytics } from '@/hooks/useAnalytics'
262
+
263
+ export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
264
+ useAnalytics()
215
265
  return <>{children}</>
216
266
  }
217
267
 
218
268
  // app/layout.tsx
219
- import { AnalyticsProvider } from './providers'
269
+ import { AnalyticsProvider } from './analytics-provider'
220
270
 
221
271
  export default function RootLayout({ children }: { children: React.ReactNode }) {
222
272
  return (
@@ -233,20 +283,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
233
283
 
234
284
  ```typescript
235
285
  // pages/_app.tsx
236
- import { Analytics } from '@deriv-com/analytics'
237
- import { useEffect } from 'react'
286
+ import { useAnalytics } from '../hooks/useAnalytics'
238
287
  import type { AppProps } from 'next/app'
239
288
 
240
289
  export default function App({ Component, pageProps }: AppProps) {
241
- useEffect(() => {
242
- Analytics.initialise({
243
- rudderstackKey: process.env.NEXT_PUBLIC_RUDDERSTACK_KEY!,
244
- posthogOptions: {
245
- apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY!,
246
- },
247
- })
248
- }, [])
249
-
290
+ useAnalytics()
250
291
  return <Component {...pageProps} />
251
292
  }
252
293
  ```
@@ -333,7 +374,7 @@ await Analytics.initialise({
333
374
  - **Event Batching**: Flushes after 10 events or 10 seconds
334
375
  - **SendBeacon API**: Uses `navigator.sendBeacon` for better performance on page unload
335
376
  - **Automatic Retry**: Failed requests are automatically retried
336
- - **Cookie Management**: Automatic anonymous ID generation and persistence (2-year cookie lifetime)
377
+ - **Cookie Management**: Automatic anonymous ID generation and persistence (6-month cookie lifetime)
337
378
  - **Offline Support**: Events are cached when offline and replayed when connection is restored
338
379
 
339
380
  ### PostHog Configuration
@@ -347,13 +388,19 @@ await Analytics.initialise({
347
388
  // Required: API key
348
389
  apiKey: 'phc_YOUR_KEY',
349
390
 
350
- // Optional: Domain allowlist for security
351
- allowedDomains: ['deriv.com', 'deriv.team', 'deriv.ae'],
391
+ // Optional: Override the PostHog API host.
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).
398
+ api_host: 'https://ph.deriv.com',
352
399
 
353
400
  // Optional: PostHog configuration
354
401
  config: {
355
- // API endpoints (defaults shown)
356
- api_host: 'https://ph.deriv.com',
402
+ // ui_host controls where the PostHog UI links point (e.g. session replay links).
403
+ // This is separate from api_host and should remain pointed at the PostHog cloud UI.
357
404
  ui_host: 'https://us.posthog.com',
358
405
 
359
406
  // Session recording
@@ -385,18 +432,18 @@ await Analytics.initialise({
385
432
  })
386
433
  ```
387
434
 
435
+ #### Stale Cookie Cleanup
436
+
437
+ On every PostHog initialization, the library automatically removes leftover `ph_*_posthog` cookies from previous or rotated API keys. This prevents stale cookies from accumulating in users' browsers when the PostHog project key changes.
438
+
388
439
  #### Domain Allowlisting
389
440
 
390
- For security, PostHog can be configured to only send events from specific domains:
441
+ PostHog events are only sent from the following domains (hardcoded internally):
391
442
 
392
- ```typescript
393
- posthogOptions: {
394
- apiKey: 'phc_YOUR_KEY',
395
- allowedDomains: ['deriv.com', 'deriv.team', 'deriv.ae'],
396
- }
397
- ```
443
+ - `deriv.com`, `deriv.be`, `deriv.me`, `deriv.team`, `deriv.ae`
444
+ - `localhost` and `127.0.0.1` are always allowed
398
445
 
399
- Events from `app.deriv.com`, `staging.deriv.team`, etc. will be sent. Events from other domains will be blocked.
446
+ Events from any other domain are silently blocked. This list is not user-configurable.
400
447
 
401
448
  #### Session Recording Customization
402
449
 
@@ -446,9 +493,7 @@ await Analytics.initialise({
446
493
 
447
494
  ### Event Tracking
448
495
 
449
- Track custom events with associated data. Supports both V1 (flat) and V2 (structured) formats:
450
-
451
- #### V1 Event Format (Flat Structure)
496
+ Track custom events with any payload there are no enforced property types. Send exactly what your event needs:
452
497
 
453
498
  ```typescript
454
499
  Analytics.trackEvent('ce_login_form', {
@@ -456,22 +501,14 @@ Analytics.trackEvent('ce_login_form', {
456
501
  login_provider: 'email',
457
502
  form_name: 'main_login',
458
503
  })
459
- ```
460
-
461
- #### V2 Event Format (Structured with Metadata)
462
504
 
463
- ```typescript
464
- Analytics.trackEvent('ce_get_start_page', {
465
- action: 'click',
466
- form_name: 'signup_form',
505
+ Analytics.trackEvent('ce_signup_form', {
506
+ action: 'signup_done',
507
+ signup_provider: 'google',
467
508
  cta_information: {
468
509
  cta_name: 'get_started',
469
510
  section_name: 'hero',
470
511
  },
471
- event_metadata: {
472
- page_name: '/home',
473
- user_language: 'en',
474
- },
475
512
  })
476
513
  ```
477
514
 
@@ -541,7 +578,7 @@ Analytics.pageView('/trade', 'Deriv App', {
541
578
 
542
579
  ### User Attributes
543
580
 
544
- Set user and context attributes that are automatically included in all events:
581
+ Set user and context attributes that are automatically included in all subsequent events. Pass any key-value pairs — no fixed schema is enforced:
545
582
 
546
583
  ```typescript
547
584
  Analytics.setAttributes({
@@ -553,11 +590,10 @@ Analytics.setAttributes({
553
590
  account_mode: 'demo',
554
591
  residence_country: 'US',
555
592
  loggedIn: true,
593
+ // any additional fields your app needs
556
594
  })
557
595
  ```
558
596
 
559
- **All subsequent events will include these attributes automatically.**
560
-
561
597
  ### Reset User Session
562
598
 
563
599
  Clear user session from all providers (e.g., on logout):
@@ -568,94 +604,42 @@ Analytics.reset()
568
604
 
569
605
  ## Caching & Offline Support
570
606
 
571
- The package includes robust caching mechanisms to ensure no events are lost:
572
-
573
- ### Cookie-Based Caching
607
+ The package includes automatic caching to ensure no events are lost — no extra configuration needed.
574
608
 
575
- Events are cached in cookies when:
609
+ ### localStorage Caching (SDK not yet loaded)
576
610
 
577
- - **RudderStack SDK hasn't loaded yet** - Events are stored and replayed once the SDK initializes
578
- - **User is offline** - Events are queued and sent when connection is restored
611
+ When you call `trackEvent` or `pageView` before `initialise()` completes, events are stored in `localStorage` and replayed automatically once the SDK loads:
579
612
 
580
613
  ```typescript
581
- // Automatic - no configuration needed
614
+ // Safe to call before initialise() — automatically replayed on load
582
615
  Analytics.trackEvent('button_clicked', { button: 'submit' })
583
- // ↓ If offline or SDK not ready, stored in cookies
584
- // ↓ Automatically sent when online/SDK ready
616
+ Analytics.pageView('/dashboard')
585
617
  ```
586
618
 
587
- **Technical Details:**
619
+ ### In-Memory Caching (offline)
588
620
 
589
- - Cookies have a 7-day expiration
590
- - Maximum 10 cached events (oldest events dropped if exceeded)
591
- - Automatic cleanup after successful replay
592
- - SameSite=Lax for security
593
-
594
- ### In-Memory Caching
595
-
596
- In addition to cookie caching, events are cached in memory when the user is offline but the SDK is initialized:
621
+ When the user is offline but the SDK is already initialized, events are held in memory and flushed on the next online `trackEvent` call:
597
622
 
598
623
  ```typescript
599
- // While offline
624
+ // While offline — queued in memory, sent automatically when back online
600
625
  Analytics.trackEvent('offline_event', { data: 'cached' })
601
- // ↓ Stored in memory
602
- // ↓ Sent immediately when online
603
-
604
- // Check offline status
605
- window.addEventListener('online', () => {
606
- // Cached events automatically sent
607
- })
608
626
  ```
609
627
 
610
- ### Page View Caching
628
+ ### Route-Based Events
611
629
 
612
- Page views are also cached using the same mechanism:
630
+ Fire events only on specific pages using `loadEvent`:
613
631
 
614
632
  ```typescript
615
- // While SDK is loading
616
- Analytics.pageView('/dashboard')
617
- // ↓ Cached in cookies
618
- // ↓ Replayed once SDK is ready
619
- ```
620
-
621
- ### Advanced Caching Utilities
622
-
623
- For complex scenarios requiring more control, use the advanced caching utilities:
624
-
625
- ```typescript
626
- import { cacheTrackEvents } from '@deriv-com/analytics'
627
-
628
- // Track events with automatic caching before SDK loads
629
- cacheTrackEvents.track({
630
- name: 'ce_login_form',
631
- properties: { action: 'open' },
632
- })
633
-
634
- // Add click event listeners with auto-retry
635
- cacheTrackEvents.addEventHandler([
633
+ Analytics.loadEvent([
636
634
  {
637
- element: '.signup-button',
638
- event: {
639
- name: 'ce_button_click',
640
- properties: { button_name: 'signup' },
641
- },
642
- cache: true, // Cache if SDK not ready
635
+ pages: ['dashboard', 'profile'],
636
+ event: { name: 'ce_page_load', properties: { page_type: 'authenticated' } },
643
637
  },
644
- ])
645
-
646
- // Track page-specific events
647
- cacheTrackEvents.pageLoadEvent([
648
638
  {
649
- pages: ['dashboard', 'profile'],
650
- event: {
651
- name: 'ce_page_load',
652
- properties: { page_type: 'authenticated' },
653
- },
639
+ excludedPages: ['login'],
640
+ event: { name: 'ce_authenticated_view', properties: {} },
654
641
  },
655
642
  ])
656
-
657
- // Automatic pageview tracking
658
- cacheTrackEvents.pageView()
659
643
  ```
660
644
 
661
645
  ## Debug Mode
@@ -685,7 +669,6 @@ import { Posthog } from '@deriv-com/analytics/posthog'
685
669
 
686
670
  const posthog = Posthog.getPosthogInstance({
687
671
  apiKey: 'phc_YOUR_KEY',
688
- allowedDomains: ['deriv.com'],
689
672
  config: {
690
673
  autocapture: true,
691
674
  session_recording: {
@@ -759,7 +742,14 @@ interface Options {
759
742
  rudderstackKey?: string
760
743
  posthogOptions?: {
761
744
  apiKey: string
762
- allowedDomains?: string[]
745
+ /**
746
+ * Optional PostHog API host. If omitted, resolved automatically based on window.location.hostname:
747
+ * *.deriv.me → https://ph.deriv.me
748
+ * *.deriv.be → https://ph.deriv.be
749
+ * *.deriv.ae → https://ph.deriv.ae
750
+ * all others → https://ph.deriv.com (default; also used server-side)
751
+ */
752
+ api_host?: string
763
753
  config?: PostHogConfig
764
754
  }
765
755
  /** Enable verbose debug logging — all analytics calls are logged prefixed with [ANALYTIC] */
@@ -767,9 +757,9 @@ interface Options {
767
757
  }
768
758
  ```
769
759
 
770
- ### `trackEvent<T>(event: T, payload: TAllEvents[T]): void`
760
+ ### `trackEvent(event: string, payload: Record<string, any>): void`
771
761
 
772
- Track a typed event.
762
+ Track an event. No payload schema is enforced — send any key-value pairs.
773
763
 
774
764
  ### `pageView(url: string, platform?: string, properties?: Record<string, unknown>): void`
775
765
 
@@ -779,18 +769,31 @@ Track page navigation.
779
769
 
780
770
  Link anonymous session to a user ID with optional traits. When PostHog is active and traits include an `email` field (via provider-specific `posthog` key), `is_internal` is automatically computed and set as a person property — the email itself is not stored in PostHog.
781
771
 
782
- ### `backfillPersonProperties(user_id: string, email: string): void`
772
+ ### `backfillPersonProperties({ user_id, email?, country_of_residence? }): void`
783
773
 
784
774
  Backfills PostHog person properties for users identified in previous sessions. Sets `client_id` and `is_internal` if they are not already present. No-op if PostHog is not initialized or `user_id` is empty.
785
775
 
786
776
  ```typescript
787
777
  // Call after PostHog has loaded and user ID is available
788
- Analytics.backfillPersonProperties('CR123456', 'user@example.com')
778
+ Analytics.backfillPersonProperties({ user_id: 'CR123456', email: 'user@example.com', country_of_residence: 'US' })
789
779
  ```
790
780
 
791
- ### `setAttributes(attributes: TCoreAttributes): void`
781
+ ### `setAttributes(attributes: Record<string, any>): void`
782
+
783
+ Update user attributes that flow to all providers. No schema is enforced.
792
784
 
793
- Update user attributes that flow to all providers.
785
+ ### `loadEvent(items: PageLoadEventConfig[]): void`
786
+
787
+ Fire events conditionally based on the current page pathname.
788
+
789
+ ```typescript
790
+ type PageLoadEventConfig = {
791
+ pages?: string[] // fire only on these pages
792
+ excludedPages?: string[] // fire on all pages except these
793
+ event: { name: string; properties: Record<string, any> }
794
+ callback?: () => { name: string; properties: Record<string, any> }
795
+ }
796
+ ```
794
797
 
795
798
  ### `reset(): void`
796
799
 
@@ -862,8 +865,8 @@ Estimated sizes (minified + gzipped):
862
865
 
863
866
  1. **Check online status**: Run `navigator.onLine` in console
864
867
  2. **Verify SDK loaded**: Run `Analytics.getInstances().tracking.has_initialized`
865
- 3. **Check cookies**: Look for `rudder_*` and `analytics_cached_*` cookies in DevTools
866
- 4. **Clear cache manually**: Clear cookies or run `Analytics.reset()`
868
+ 3. **Check storage**: Open DevTools → Application → Local Storage — look for `cached_analytics_events` and `cached_analytics_page_views` keys. The `rudder_anonymous_id` is still stored as a cookie.
869
+ 4. **Clear cache manually**: Clear localStorage keys or run `Analytics.reset()`
867
870
 
868
871
  ## Migration Guide
869
872