diff --git a/apps/desktop/src/auth/context.tsx b/apps/desktop/src/auth/context.tsx
index 4771086208..47cda481f9 100644
--- a/apps/desktop/src/auth/context.tsx
+++ b/apps/desktop/src/auth/context.tsx
@@ -9,6 +9,7 @@ import { useMutation } from "@tanstack/react-query";
import { getVersion } from "@tauri-apps/api/app";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { version as osVersion, platform } from "@tauri-apps/plugin-os";
+import posthog from "posthog-js";
import {
createContext,
useCallback,
@@ -129,6 +130,8 @@ async function trackAuthEvent(
},
});
+ posthog.identify(session.user.id);
+
if (event === "SIGNED_IN") {
void analyticsCommands.event({ event: "user_signed_in" });
}
@@ -136,6 +139,7 @@ async function trackAuthEvent(
if (event === "SIGNED_OUT") {
trackedUserId = null;
+ posthog.reset();
}
}
diff --git a/apps/desktop/src/main.tsx b/apps/desktop/src/main.tsx
index 1156af09b6..59928316b7 100644
--- a/apps/desktop/src/main.tsx
+++ b/apps/desktop/src/main.tsx
@@ -1,4 +1,5 @@
import "./styles/globals.css";
+import "./providers/posthog";
import * as Sentry from "@sentry/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
@@ -18,6 +19,7 @@ import "@hypr/ui/globals.css";
import { createToolRegistry } from "./contexts/tool-registry/core";
import { env } from "./env";
import { initPluginGlobals } from "./plugins/globals";
+import { SessionReplay } from "./providers/session-replay";
import { routeTree } from "./routeTree.gen";
import { TaskManager } from "./services/task-manager";
import { ErrorComponent, NotFoundComponent } from "./shared/control";
@@ -114,6 +116,7 @@ function AppWithTiny() {
+
diff --git a/apps/desktop/src/providers/posthog.ts b/apps/desktop/src/providers/posthog.ts
new file mode 100644
index 0000000000..27a0fe0550
--- /dev/null
+++ b/apps/desktop/src/providers/posthog.ts
@@ -0,0 +1,22 @@
+import posthog from "posthog-js";
+
+import { env } from "~/env";
+
+const key = env.VITE_POSTHOG_API_KEY;
+
+if (key) {
+ posthog.init(key, {
+ api_host: env.VITE_POSTHOG_HOST,
+
+ autocapture: false,
+ capture_pageview: false,
+ capture_pageleave: false,
+
+ disable_session_recording: true,
+
+ session_recording: {
+ maskAllInputs: true,
+ maskTextSelector: "*",
+ },
+ });
+}
diff --git a/apps/desktop/src/providers/session-replay.tsx b/apps/desktop/src/providers/session-replay.tsx
new file mode 100644
index 0000000000..4545fb5497
--- /dev/null
+++ b/apps/desktop/src/providers/session-replay.tsx
@@ -0,0 +1,26 @@
+import posthog from "posthog-js";
+import { useEffect } from "react";
+
+import { useConfigValue } from "~/shared/config";
+import { useTabs } from "~/store/zustand/tabs";
+
+const RECORDED_TAB_TYPES = new Set(["settings", "ai", "onboarding"]);
+
+export function SessionReplay() {
+ const telemetryConsent = useConfigValue("telemetry_consent");
+ const tabType = useTabs((state) => state.currentTab?.type);
+
+ const shouldRecord =
+ telemetryConsent && !!tabType && RECORDED_TAB_TYPES.has(tabType);
+
+ useEffect(() => {
+ if (shouldRecord) {
+ posthog.startSessionRecording();
+ return () => posthog.stopSessionRecording();
+ } else {
+ posthog.stopSessionRecording();
+ }
+ }, [shouldRecord]);
+
+ return null;
+}