@behindthescenes/analytics 0.0.9 → 0.0.11

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.
@@ -0,0 +1,936 @@
1
+ # Framework Setup Guide
2
+
3
+ This guide covers setting up the BTS Analytics SDK in popular frontend frameworks.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Plain JavaScript / HTML](#plain-javascript--html)
8
+ - [React](#react)
9
+ - [Next.js](#nextjs)
10
+ - [Remix](#remix)
11
+ - [Vue](#vue)
12
+ - [Svelte](#svelte)
13
+ - [Angular](#angular)
14
+ - [SolidJS](#solidjs)
15
+
16
+ ---
17
+
18
+ ## Plain JavaScript / HTML
19
+
20
+ The simplest way to get started - no build tools required.
21
+
22
+ ### Browser Bundle (CDN)
23
+
24
+ ```html
25
+ <script async src="https://api.bts.it.com/v2/website/analytics/sdk/analytics/latest/browser/browser.js"></script>
26
+ <script>
27
+ window.btsDataLayer = window.btsDataLayer || [];
28
+ function bts(){window.btsDataLayer.push(arguments);}
29
+ bts("js", new Date());
30
+ bts("config", "your-public-site-key", {
31
+ autoPageviews: true
32
+ });
33
+ </script>
34
+ ```
35
+
36
+ ### ES Module Import
37
+
38
+ ```html
39
+ <script type="module">
40
+ import { createBTSAnalytics } from "https://app.behindthescenes.com/sdk/analytics/latest/browser/browser.js";
41
+
42
+ window.btsAnalytics = createBTSAnalytics({
43
+ siteKey: "your-public-site-key"
44
+ });
45
+ </script>
46
+ ```
47
+
48
+ ### Usage Examples
49
+
50
+ ```javascript
51
+ // Track a custom event
52
+ document.querySelector("#watch-preview")?.addEventListener("click", () => {
53
+ window.btsAnalytics.track("watch_preview_clicked", {
54
+ placement: "hero",
55
+ contentId: "intro-preview",
56
+ });
57
+ });
58
+
59
+ // Track a standard conversion
60
+ window.btsAnalytics.trackStandard("lead", {
61
+ formId: "newsletter",
62
+ placement: "footer",
63
+ });
64
+
65
+ // Identify a visitor
66
+ window.btsAnalytics.identify("user_123", {
67
+ email: "fan@example.com",
68
+ plan: "pro",
69
+ });
70
+
71
+ // Track page views manually
72
+ window.btsAnalytics.page("/pricing");
73
+
74
+ // Start a funnel and decorate links
75
+ async function goToCheckout() {
76
+ const { journeyToken } = await window.btsAnalytics.startFunnel("/landing");
77
+ const checkoutUrl = window.btsAnalytics.decorateUrl(
78
+ "https://behindthescenes.com/checkout/your-offer",
79
+ journeyToken,
80
+ );
81
+ window.location.assign(checkoutUrl);
82
+ }
83
+
84
+ // Flush before redirecting
85
+ async function trackAndRedirect() {
86
+ window.btsAnalytics.track("checkout_cta_clicked", {
87
+ placement: "hero",
88
+ });
89
+ await window.btsAnalytics.flushNow();
90
+ window.location.assign("/checkout");
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## React
97
+
98
+ ### Setup: Provider Pattern
99
+
100
+ Create `BTSAnalyticsProvider.tsx`:
101
+
102
+ ```tsx
103
+ import {
104
+ BTSAnalytics,
105
+ createBTSAnalytics,
106
+ } from "@behindthescenes/analytics";
107
+ import {
108
+ createContext,
109
+ PropsWithChildren,
110
+ useContext,
111
+ useMemo,
112
+ } from "react";
113
+
114
+ const BTSAnalyticsContext = createContext<BTSAnalytics | null>(null);
115
+
116
+ export function BTSAnalyticsProvider({ children }: PropsWithChildren) {
117
+ const analytics = useMemo(
118
+ () =>
119
+ createBTSAnalytics({
120
+ siteKey: "your-public-site-key",
121
+ autoPageviews: true,
122
+ }),
123
+ [],
124
+ );
125
+
126
+ return (
127
+ <BTSAnalyticsContext.Provider value={analytics}>
128
+ {children}
129
+ </BTSAnalyticsContext.Provider>
130
+ );
131
+ }
132
+
133
+ export function useBTSAnalytics() {
134
+ const analytics = useContext(BTSAnalyticsContext);
135
+ if (!analytics) {
136
+ throw new Error("useBTSAnalytics must be used inside BTSAnalyticsProvider");
137
+ }
138
+ return analytics;
139
+ }
140
+ ```
141
+
142
+ Wrap your app:
143
+
144
+ ```tsx
145
+ import { BTSAnalyticsProvider } from "./BTSAnalyticsProvider";
146
+
147
+ function App() {
148
+ return (
149
+ <BTSAnalyticsProvider>
150
+ <YourApp />
151
+ </BTSAnalyticsProvider>
152
+ );
153
+ }
154
+ ```
155
+
156
+ ### Usage Examples
157
+
158
+ ```tsx
159
+ import { useBTSAnalytics } from "./BTSAnalyticsProvider";
160
+
161
+ // Track a custom event
162
+ function TrackEventExample() {
163
+ const analytics = useBTSAnalytics();
164
+
165
+ function trackPreviewClick() {
166
+ analytics.track("watch_preview_clicked", {
167
+ placement: "hero",
168
+ contentId: "intro-preview",
169
+ });
170
+ }
171
+
172
+ return <button onClick={trackPreviewClick}>Watch Preview</button>;
173
+ }
174
+
175
+ // Track a standard conversion
176
+ function LeadEventExample() {
177
+ const analytics = useBTSAnalytics();
178
+
179
+ function trackLead() {
180
+ analytics.trackStandard("lead", {
181
+ formId: "newsletter",
182
+ placement: "footer",
183
+ });
184
+ }
185
+
186
+ return <button onClick={trackLead}>Subscribe</button>;
187
+ }
188
+
189
+ // Identify a visitor
190
+ function IdentifyExample() {
191
+ const analytics = useBTSAnalytics();
192
+
193
+ function identifyUser() {
194
+ analytics.identify("user_123", {
195
+ email: "fan@example.com",
196
+ plan: "pro",
197
+ });
198
+ }
199
+
200
+ return <button onClick={identifyUser}>Sign In</button>;
201
+ }
202
+
203
+ // Track page views manually
204
+ function ManualPageView() {
205
+ const analytics = useBTSAnalytics();
206
+
207
+ function trackCurrentPage() {
208
+ analytics.page(window.location.pathname + window.location.search);
209
+ }
210
+
211
+ return <button onClick={trackCurrentPage}>Track Page</button>;
212
+ }
213
+
214
+ // Start a funnel and decorate links
215
+ function JourneyExample() {
216
+ const analytics = useBTSAnalytics();
217
+
218
+ async function goToCheckout() {
219
+ const { journeyToken } = await analytics.startFunnel("/landing");
220
+ const checkoutUrl = analytics.decorateUrl(
221
+ "https://behindthescenes.com/checkout/your-offer",
222
+ journeyToken,
223
+ );
224
+ window.location.assign(checkoutUrl);
225
+ }
226
+
227
+ return <button onClick={goToCheckout}>Checkout</button>;
228
+ }
229
+
230
+ // Flush before redirecting
231
+ function FlushExample() {
232
+ const analytics = useBTSAnalytics();
233
+
234
+ async function trackAndRedirect() {
235
+ analytics.track("checkout_cta_clicked", {
236
+ placement: "hero",
237
+ });
238
+ await analytics.flushNow();
239
+ window.location.assign("/checkout");
240
+ }
241
+
242
+ return <button onClick={trackAndRedirect}>Go to Checkout</button>;
243
+ }
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Next.js
249
+
250
+ ### Setup: App Router
251
+
252
+ Create `app/providers.tsx`:
253
+
254
+ ```tsx
255
+ "use client";
256
+
257
+ import {
258
+ BTSAnalytics,
259
+ createBTSAnalytics,
260
+ } from "@behindthescenes/analytics";
261
+ import {
262
+ createContext,
263
+ PropsWithChildren,
264
+ useContext,
265
+ useMemo,
266
+ } from "react";
267
+
268
+ const BTSAnalyticsContext = createContext<BTSAnalytics | null>(null);
269
+
270
+ export function Providers({ children }: PropsWithChildren) {
271
+ const analytics = useMemo(
272
+ () =>
273
+ createBTSAnalytics({
274
+ siteKey: "your-public-site-key",
275
+ autoPageviews: true,
276
+ }),
277
+ [],
278
+ );
279
+
280
+ return (
281
+ <BTSAnalyticsContext.Provider value={analytics}>
282
+ {children}
283
+ </BTSAnalyticsContext.Provider>
284
+ );
285
+ }
286
+
287
+ export function useBTSAnalytics() {
288
+ const analytics = useContext(BTSAnalyticsContext);
289
+ if (!analytics) {
290
+ throw new Error("useBTSAnalytics must be used inside Providers");
291
+ }
292
+ return analytics;
293
+ }
294
+ ```
295
+
296
+ Update `app/layout.tsx`:
297
+
298
+ ```tsx
299
+ import { Providers } from "./providers";
300
+
301
+ export default function RootLayout({
302
+ children,
303
+ }: {
304
+ children: React.ReactNode;
305
+ }) {
306
+ return (
307
+ <html lang="en">
308
+ <body>
309
+ <Providers>{children}</Providers>
310
+ </body>
311
+ </html>
312
+ );
313
+ }
314
+ ```
315
+
316
+ ### Setup: Pages Router
317
+
318
+ Create a custom `_app.tsx`:
319
+
320
+ ```tsx
321
+ import type { AppProps } from "next/app";
322
+ import { BTSAnalyticsProvider } from "../components/BTSAnalyticsProvider";
323
+
324
+ export default function MyApp({ Component, pageProps }: AppProps) {
325
+ return (
326
+ <BTSAnalyticsProvider>
327
+ <Component {...pageProps} />
328
+ </BTSAnalyticsProvider>
329
+ );
330
+ }
331
+ ```
332
+
333
+ ### Usage Examples
334
+
335
+ Same as the React examples above, using `useBTSAnalytics()` from `@/app/providers`.
336
+
337
+ ---
338
+
339
+ ## Remix
340
+
341
+ ### Setup: Root Provider
342
+
343
+ Update `app/root.tsx`:
344
+
345
+ ```tsx
346
+ import { createBTSAnalytics } from "@behindthescenes/analytics";
347
+ import { useEffect, useMemo } from "react";
348
+ import { Outlet, useLocation } from "react-router";
349
+
350
+ // Create singleton instance
351
+ const analytics = createBTSAnalytics({
352
+ siteKey: "your-public-site-key",
353
+ autoPageviews: false, // Handle manually for Remix
354
+ });
355
+
356
+ export function Layout() {
357
+ const location = useLocation();
358
+ const path = useMemo(
359
+ () => location.pathname + location.search,
360
+ [location.pathname, location.search],
361
+ );
362
+
363
+ useEffect(() => {
364
+ analytics.page(path);
365
+ }, [path]);
366
+
367
+ return <Outlet />;
368
+ }
369
+
370
+ export { analytics };
371
+ ```
372
+
373
+ ### Usage Examples
374
+
375
+ ```tsx
376
+ import { analytics } from "~/root";
377
+
378
+ // Track a custom event
379
+ export function TrackEventExample() {
380
+ function trackPreviewClick() {
381
+ analytics.track("watch_preview_clicked", {
382
+ placement: "hero",
383
+ contentId: "intro-preview",
384
+ });
385
+ }
386
+
387
+ return <button onClick={trackPreviewClick}>Watch Preview</button>;
388
+ }
389
+
390
+ // Track a standard conversion
391
+ export function LeadEventExample() {
392
+ function trackLead() {
393
+ analytics.trackStandard("lead", {
394
+ formId: "newsletter",
395
+ placement: "footer",
396
+ });
397
+ }
398
+
399
+ return <button onClick={trackLead}>Subscribe</button>;
400
+ }
401
+
402
+ // Identify a visitor
403
+ export function IdentifyExample() {
404
+ function identifyUser() {
405
+ analytics.identify("user_123", {
406
+ email: "fan@example.com",
407
+ plan: "pro",
408
+ });
409
+ }
410
+
411
+ return <button onClick={identifyUser}>Sign In</button>;
412
+ }
413
+
414
+ // Track page views manually
415
+ export function ManualPageView() {
416
+ function trackCurrentPage() {
417
+ analytics.page(window.location.pathname + window.location.search);
418
+ }
419
+
420
+ return <button onClick={trackCurrentPage}>Track Page</button>;
421
+ }
422
+
423
+ // Start a funnel and decorate links
424
+ export function JourneyExample() {
425
+ async function goToCheckout() {
426
+ const { journeyToken } = await analytics.startFunnel("/landing");
427
+ const checkoutUrl = analytics.decorateUrl(
428
+ "https://behindthescenes.com/checkout/your-offer",
429
+ journeyToken,
430
+ );
431
+ window.location.assign(checkoutUrl);
432
+ }
433
+
434
+ return <button onClick={goToCheckout}>Checkout</button>;
435
+ }
436
+
437
+ // Flush before redirecting
438
+ export function FlushExample() {
439
+ async function trackAndRedirect() {
440
+ analytics.track("checkout_cta_clicked", {
441
+ placement: "hero",
442
+ });
443
+ await analytics.flushNow();
444
+ window.location.assign("/checkout");
445
+ }
446
+
447
+ return <button onClick={trackAndRedirect}>Go to Checkout</button>;
448
+ }
449
+ ```
450
+
451
+ ---
452
+
453
+ ## Vue
454
+
455
+ ### Setup: Plugin Pattern
456
+
457
+ Create `src/plugins/bts-analytics.ts`:
458
+
459
+ ```typescript
460
+ import { createBTSAnalytics } from "@behindthescenes/analytics";
461
+ import type { App } from "vue";
462
+
463
+ const analytics = createBTSAnalytics({
464
+ siteKey: "your-public-site-key",
465
+ autoPageviews: true,
466
+ });
467
+
468
+ export function installBTSAnalytics(app: App) {
469
+ app.provide("btsAnalytics", analytics);
470
+ }
471
+
472
+ export { analytics };
473
+ ```
474
+
475
+ Register in `main.ts`:
476
+
477
+ ```typescript
478
+ import { createApp } from "vue";
479
+ import App from "./App.vue";
480
+ import { installBTSAnalytics } from "./plugins/bts-analytics";
481
+
482
+ const app = createApp(App);
483
+ app.use(installBTSAnalytics);
484
+ app.mount("#app");
485
+ ```
486
+
487
+ ### Composable
488
+
489
+ Create `src/composables/useAnalytics.ts`:
490
+
491
+ ```typescript
492
+ import { inject } from "vue";
493
+ import type { BTSAnalytics } from "@behindthescenes/analytics";
494
+
495
+ export function useAnalytics(): BTSAnalytics {
496
+ const analytics = inject<BTSAnalytics>("btsAnalytics");
497
+ if (!analytics) {
498
+ throw new Error("useAnalytics must be called inside a Vue app with BTS Analytics installed");
499
+ }
500
+ return analytics;
501
+ }
502
+ ```
503
+
504
+ ### Usage Examples
505
+
506
+ ```vue
507
+ <script setup lang="ts">
508
+ import { useAnalytics } from "@/composables/useAnalytics";
509
+
510
+ const analytics = useAnalytics();
511
+
512
+ // Track a custom event
513
+ function trackPreviewClick() {
514
+ analytics.track("watch_preview_clicked", {
515
+ placement: "hero",
516
+ contentId: "intro-preview",
517
+ });
518
+ }
519
+
520
+ // Track a standard conversion
521
+ function trackLead() {
522
+ analytics.trackStandard("lead", {
523
+ formId: "newsletter",
524
+ placement: "footer",
525
+ });
526
+ }
527
+
528
+ // Identify a visitor
529
+ function identifyUser() {
530
+ analytics.identify("user_123", {
531
+ email: "fan@example.com",
532
+ plan: "pro",
533
+ });
534
+ }
535
+
536
+ // Track page views manually
537
+ function trackCurrentPage() {
538
+ analytics.page(window.location.pathname + window.location.search);
539
+ }
540
+
541
+ // Start a funnel and decorate links
542
+ async function goToCheckout() {
543
+ const { journeyToken } = await analytics.startFunnel("/landing");
544
+ const checkoutUrl = analytics.decorateUrl(
545
+ "https://behindthescenes.com/checkout/your-offer",
546
+ journeyToken,
547
+ );
548
+ window.location.assign(checkoutUrl);
549
+ }
550
+
551
+ // Flush before redirecting
552
+ async function trackAndRedirect() {
553
+ analytics.track("checkout_cta_clicked", {
554
+ placement: "hero",
555
+ });
556
+ await analytics.flushNow();
557
+ window.location.assign("/checkout");
558
+ }
559
+ </script>
560
+
561
+ <template>
562
+ <button @click="trackPreviewClick">Watch Preview</button>
563
+ <button @click="trackLead">Subscribe</button>
564
+ <button @click="identifyUser">Sign In</button>
565
+ <button @click="trackCurrentPage">Track Page</button>
566
+ <button @click="goToCheckout">Checkout</button>
567
+ <button @click="trackAndRedirect">Go to Checkout</button>
568
+ </template>
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Svelte
574
+
575
+ ### Setup: Store Pattern
576
+
577
+ Create `src/lib/analytics.ts`:
578
+
579
+ ```typescript
580
+ import { createBTSAnalytics } from "@behindthescenes/analytics";
581
+
582
+ export const analytics = createBTSAnalytics({
583
+ siteKey: "your-public-site-key",
584
+ autoPageviews: true,
585
+ });
586
+ ```
587
+
588
+ ### Usage in Components
589
+
590
+ ```svelte
591
+ <script lang="ts">
592
+ import { analytics } from "$lib/analytics";
593
+
594
+ // Track a custom event
595
+ function trackPreviewClick() {
596
+ analytics.track("watch_preview_clicked", {
597
+ placement: "hero",
598
+ contentId: "intro-preview",
599
+ });
600
+ }
601
+
602
+ // Track a standard conversion
603
+ function trackLead() {
604
+ analytics.trackStandard("lead", {
605
+ formId: "newsletter",
606
+ placement: "footer",
607
+ });
608
+ }
609
+
610
+ // Identify a visitor
611
+ function identifyUser() {
612
+ analytics.identify("user_123", {
613
+ email: "fan@example.com",
614
+ plan: "pro",
615
+ });
616
+ }
617
+
618
+ // Start a funnel and decorate links
619
+ async function goToCheckout() {
620
+ const { journeyToken } = await analytics.startFunnel("/landing");
621
+ const checkoutUrl = analytics.decorateUrl(
622
+ "https://behindthescenes.com/checkout/your-offer",
623
+ journeyToken,
624
+ );
625
+ window.location.assign(checkoutUrl);
626
+ }
627
+
628
+ // Flush before redirecting
629
+ async function trackAndRedirect() {
630
+ analytics.track("checkout_cta_clicked", {
631
+ placement: "hero",
632
+ });
633
+ await analytics.flushNow();
634
+ window.location.assign("/checkout");
635
+ }
636
+ </script>
637
+
638
+ <button on:click={trackPreviewClick}>Watch Preview</button>
639
+ <button on:click={trackLead}>Subscribe</button>
640
+ <button on:click={identifyUser}>Sign In</button>
641
+ <button on:click={goToCheckout}>Checkout</button>
642
+ <button on:click={trackAndRedirect}>Go to Checkout</button>
643
+ ```
644
+
645
+ ### SvelteKit Setup
646
+
647
+ For SvelteKit with SSR, create a client-side only module:
648
+
649
+ ```typescript
650
+ // src/lib/analytics.client.ts
651
+ import { browser } from "$app/environment";
652
+ import { createBTSAnalytics } from "@behindthescenes/analytics";
653
+
654
+ export const analytics = browser
655
+ ? createBTSAnalytics({
656
+ siteKey: "your-public-site-key",
657
+ autoPageviews: true,
658
+ })
659
+ : null;
660
+ ```
661
+
662
+ Use in components:
663
+
664
+ ```svelte
665
+ <script lang="ts">
666
+ import { analytics } from "$lib/analytics.client";
667
+
668
+ function trackEvent() {
669
+ analytics?.track("button_clicked", { buttonId: "cta" });
670
+ }
671
+ </script>
672
+ ```
673
+
674
+ ---
675
+
676
+ ## Angular
677
+
678
+ ### Setup: Service Pattern
679
+
680
+ Create `src/app/services/bts-analytics.service.ts`:
681
+
682
+ ```typescript
683
+ import { Injectable } from "@angular/core";
684
+ import { createBTSAnalytics, BTSAnalytics } from "@behindthescenes/analytics";
685
+
686
+ @Injectable({
687
+ providedIn: "root",
688
+ })
689
+ export class BTSAnalyticsService {
690
+ private analytics: BTSAnalytics;
691
+
692
+ constructor() {
693
+ this.analytics = createBTSAnalytics({
694
+ siteKey: "your-public-site-key",
695
+ autoPageviews: true,
696
+ });
697
+ }
698
+
699
+ track(eventName: string, properties?: Record<string, unknown>) {
700
+ this.analytics.track(eventName, properties);
701
+ }
702
+
703
+ trackStandard(eventName: string, properties?: Record<string, unknown>) {
704
+ this.analytics.trackStandard(eventName as any, properties);
705
+ }
706
+
707
+ identify(userId: string, traits?: Record<string, unknown>) {
708
+ this.analytics.identify(userId, traits);
709
+ }
710
+
711
+ page(path?: string) {
712
+ this.analytics.page(path);
713
+ }
714
+
715
+ async startFunnel(entryPath?: string) {
716
+ return this.analytics.startFunnel(entryPath);
717
+ }
718
+
719
+ decorateUrl(url: string, journeyToken?: string) {
720
+ return this.analytics.decorateUrl(url, journeyToken);
721
+ }
722
+
723
+ async flushNow() {
724
+ return this.analytics.flushNow();
725
+ }
726
+ }
727
+ ```
728
+
729
+ ### Usage in Components
730
+
731
+ ```typescript
732
+ import { Component } from "@angular/core";
733
+ import { BTSAnalyticsService } from "./services/bts-analytics.service";
734
+
735
+ @Component({
736
+ selector: "app-example",
737
+ template: `
738
+ <button (click)="trackPreviewClick()">Watch Preview</button>
739
+ <button (click)="trackLead()">Subscribe</button>
740
+ <button (click)="identifyUser()">Sign In</button>
741
+ <button (click)="goToCheckout()">Checkout</button>
742
+ `,
743
+ })
744
+ export class ExampleComponent {
745
+ constructor(private analytics: BTSAnalyticsService) {}
746
+
747
+ trackPreviewClick() {
748
+ this.analytics.track("watch_preview_clicked", {
749
+ placement: "hero",
750
+ contentId: "intro-preview",
751
+ });
752
+ }
753
+
754
+ trackLead() {
755
+ this.analytics.trackStandard("lead", {
756
+ formId: "newsletter",
757
+ placement: "footer",
758
+ });
759
+ }
760
+
761
+ identifyUser() {
762
+ this.analytics.identify("user_123", {
763
+ email: "fan@example.com",
764
+ plan: "pro",
765
+ });
766
+ }
767
+
768
+ async goToCheckout() {
769
+ const { journeyToken } = await this.analytics.startFunnel("/landing");
770
+ const checkoutUrl = this.analytics.decorateUrl(
771
+ "https://behindthescenes.com/checkout/your-offer",
772
+ journeyToken,
773
+ );
774
+ window.location.assign(checkoutUrl);
775
+ }
776
+ }
777
+ ```
778
+
779
+ ---
780
+
781
+ ## SolidJS
782
+
783
+ ### Setup: Context Pattern
784
+
785
+ Create `src/context/BTSAnalyticsContext.tsx`:
786
+
787
+ ```tsx
788
+ import { createBTSAnalytics, BTSAnalytics } from "@behindthescenes/analytics";
789
+ import { createContext, useContext, ParentComponent } from "solid-js";
790
+
791
+ const BTSAnalyticsContext = createContext<BTSAnalytics>();
792
+
793
+ export const BTSAnalyticsProvider: ParentComponent = (props) => {
794
+ const analytics = createBTSAnalytics({
795
+ siteKey: "your-public-site-key",
796
+ autoPageviews: true,
797
+ });
798
+
799
+ return (
800
+ <BTSAnalyticsContext.Provider value={analytics}>
801
+ {props.children}
802
+ </BTSAnalyticsContext.Provider>
803
+ );
804
+ };
805
+
806
+ export function useBTSAnalytics() {
807
+ const analytics = useContext(BTSAnalyticsContext);
808
+ if (!analytics) {
809
+ throw new Error("useBTSAnalytics must be used inside BTSAnalyticsProvider");
810
+ }
811
+ return analytics;
812
+ }
813
+ ```
814
+
815
+ ### Usage in Components
816
+
817
+ ```tsx
818
+ import { useBTSAnalytics } from "../context/BTSAnalyticsContext";
819
+
820
+ export function TrackEventExample() {
821
+ const analytics = useBTSAnalytics();
822
+
823
+ function trackPreviewClick() {
824
+ analytics.track("watch_preview_clicked", {
825
+ placement: "hero",
826
+ contentId: "intro-preview",
827
+ });
828
+ }
829
+
830
+ return <button onClick={trackPreviewClick}>Watch Preview</button>;
831
+ }
832
+
833
+ export function LeadEventExample() {
834
+ const analytics = useBTSAnalytics();
835
+
836
+ function trackLead() {
837
+ analytics.trackStandard("lead", {
838
+ formId: "newsletter",
839
+ placement: "footer",
840
+ });
841
+ }
842
+
843
+ return <button onClick={trackLead}>Subscribe</button>;
844
+ }
845
+
846
+ export function IdentifyExample() {
847
+ const analytics = useBTSAnalytics();
848
+
849
+ function identifyUser() {
850
+ analytics.identify("user_123", {
851
+ email: "fan@example.com",
852
+ plan: "pro",
853
+ });
854
+ }
855
+
856
+ return <button onClick={identifyUser}>Sign In</button>;
857
+ }
858
+
859
+ export function JourneyExample() {
860
+ const analytics = useBTSAnalytics();
861
+
862
+ async function goToCheckout() {
863
+ const { journeyToken } = await analytics.startFunnel("/landing");
864
+ const checkoutUrl = analytics.decorateUrl(
865
+ "https://behindthescenes.com/checkout/your-offer",
866
+ journeyToken,
867
+ );
868
+ window.location.assign(checkoutUrl);
869
+ }
870
+
871
+ return <button onClick={goToCheckout}>Checkout</button>;
872
+ }
873
+
874
+ export function FlushExample() {
875
+ const analytics = useBTSAnalytics();
876
+
877
+ async function trackAndRedirect() {
878
+ analytics.track("checkout_cta_clicked", {
879
+ placement: "hero",
880
+ });
881
+ await analytics.flushNow();
882
+ window.location.assign("/checkout");
883
+ }
884
+
885
+ return <button onClick={trackAndRedirect}>Go to Checkout</button>;
886
+ }
887
+ ```
888
+
889
+ ---
890
+
891
+ ## Server-Side Rendering (SSR) Considerations
892
+
893
+ When using frameworks with SSR (Next.js, Remix, SvelteKit), keep these points in mind:
894
+
895
+ ### 1. Client-Only Initialization
896
+
897
+ The SDK requires browser APIs (`window`, `document`, `localStorage`). Always initialize on the client:
898
+
899
+ ```typescript
900
+ // Good
901
+ const analytics = typeof window !== "undefined"
902
+ ? createBTSAnalytics({ siteKey: "..." })
903
+ : null;
904
+
905
+ // Or use framework utilities
906
+ import { browser } from "$app/environment"; // SvelteKit
907
+ ```
908
+
909
+ ### 2. Disable Auto-Pageviews for Manual Control
910
+
911
+ ```typescript
912
+ const analytics = createBTSAnalytics({
913
+ siteKey: "your-public-site-key",
914
+ autoPageviews: false, // Handle manually for SSR frameworks
915
+ });
916
+ ```
917
+
918
+ ### 3. Router Integration
919
+
920
+ Integrate with your framework's router for accurate page tracking:
921
+
922
+ - **Next.js**: Use `usePathname()` in a client component
923
+ - **Remix**: Use `useLocation()` in `root.tsx`
924
+ - **SvelteKit**: Use `$page.url` in `+layout.svelte`
925
+
926
+ ### 4. Cleanup on Navigation
927
+
928
+ The SDK handles most cleanup automatically, but call `destroy()` when unmounting:
929
+
930
+ ```typescript
931
+ import { onCleanup } from "solid-js";
932
+
933
+ onCleanup(() => {
934
+ analytics?.destroy();
935
+ });
936
+ ```