-
Notifications
You must be signed in to change notification settings - Fork 137
Expand file tree
/
Copy pathanalytics.js
More file actions
81 lines (75 loc) · 3.12 KB
/
Copy pathanalytics.js
File metadata and controls
81 lines (75 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { isNativeEmbed, isNativeWindowsApp } from "./native-bridge.js";
/**
* Anonymous product analytics (PostHog), covering all four dashboard
* surfaces: the hosted site, localhost (npm CLI users), and the macOS /
* Windows app WebViews. Every event carries a `shell` property so the
* surfaces can be split apart in PostHog.
*
* Privacy contract (disclosed in the README privacy section):
* - pageviews + explicitly captured events only — autocapture and session
* recording are off, browser Do-Not-Track is respected;
* - on localhost / native-app surfaces the local server's
* /functions/tokentracker-telemetry-pref is consulted first, so
* TOKENTRACKER_NO_TELEMETRY=1 (or DO_NOT_TRACK=1 / config
* `"telemetry": false`) disables dashboard analytics together with the
* daily heartbeat. If the preference cannot be confirmed, analytics stays
* OFF (fail-closed).
*/
// Public project write key (phc_*) — ships in every browser bundle by design
// and cannot read any data. Hardcoded rather than injected via VITE_ env so
// release builds (Vercel, DMG / Windows embedded dashboard, npm package)
// can't silently lose analytics to a missing CI env var.
const POSTHOG_KEY =
import.meta.env.VITE_POSTHOG_KEY || "phc_nXhUfFbyrW9gNvp8iBL83eWPUhAuAYJgcgqUJxwUbBgj";
const POSTHOG_HOST = "https://us.i.posthog.com";
export function resolveAnalyticsShell() {
if (typeof window === "undefined") return "web";
if (isNativeEmbed()) return "mac-app";
if (isNativeWindowsApp()) return "win-app";
const host = window.location.hostname;
if (host === "localhost" || host === "127.0.0.1") return "cli-localhost";
return "web";
}
async function startPosthog(shell) {
// Dynamic import keeps posthog-js (~70-90 KB gzip) out of the eager entry
// chunk — analytics only ever activates in production builds, so localhost
// CLI users, native WebViews, and the share page should not pay for it.
const { default: posthog } = await import("posthog-js");
posthog.init(POSTHOG_KEY, {
api_host: POSTHOG_HOST,
capture_pageview: "history_change", // SPA route changes count as pageviews
autocapture: false,
disable_session_recording: true,
respect_dnt: true,
persistence: "localStorage",
});
posthog.register({ shell });
}
export function initAnalytics() {
if (typeof window === "undefined") return;
// Vite dev server (5173 mock mode) and vitest must never emit events.
if (import.meta.env.DEV || import.meta.env.MODE === "test") return;
try {
const shell = resolveAnalyticsShell();
if (shell === "web") {
void startPosthog(shell).catch(() => {
/* analytics must never break the app */
});
return;
}
// Local surfaces: honor the CLI-side telemetry opt-out, fail-closed.
fetch("/functions/tokentracker-telemetry-pref")
.then((res) => (res.ok ? res.json() : null))
.then((pref) => {
if (pref && pref.disabled === false) {
return startPosthog(shell);
}
return undefined;
})
.catch(() => {
/* preference unknown → analytics stays off */
});
} catch {
/* analytics must never break the app */
}
}