2025-12-25 13:53:41 -08:00
|
|
|
|
import posthog from "posthog-js";
|
|
|
|
|
|
|
2026-04-18 14:35:14 -07:00
|
|
|
|
/**
|
|
|
|
|
|
* PostHog initialisation for the Next.js renderer.
|
|
|
|
|
|
*
|
|
|
|
|
|
* The same bundle ships in two contexts:
|
|
|
|
|
|
* 1. A normal browser session on surfsense.com -> platform = "web"
|
|
|
|
|
|
* 2. The Electron desktop app (renders the Next app from localhost)
|
|
|
|
|
|
* -> platform = "desktop"
|
|
|
|
|
|
*
|
|
|
|
|
|
* When running inside Electron we also seed `posthog-js` with the main
|
|
|
|
|
|
* process's machine distinctId so that events fired from both the renderer
|
|
|
|
|
|
* (e.g. `chat_message_sent`, page views) and the Electron main process
|
|
|
|
|
|
* (e.g. `desktop_quick_ask_opened`) share a single PostHog person before
|
|
|
|
|
|
* login, and can be merged into the authenticated user afterwards.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
function isElectron(): boolean {
|
|
|
|
|
|
return typeof window !== "undefined" && !!window.electronAPI;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function currentPlatform(): "desktop" | "web" {
|
|
|
|
|
|
return isElectron() ? "desktop" : "web";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function resolveBootstrapDistinctId(): Promise<string | undefined> {
|
|
|
|
|
|
if (!isElectron() || !window.electronAPI?.getAnalyticsContext) return undefined;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const ctx = await window.electronAPI.getAnalyticsContext();
|
|
|
|
|
|
return ctx?.machineId || ctx?.distinctId || undefined;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function initPostHog() {
|
2026-03-11 02:47:46 -07:00
|
|
|
|
try {
|
|
|
|
|
|
if (!process.env.NEXT_PUBLIC_POSTHOG_KEY) return;
|
2026-03-08 17:48:09 -07:00
|
|
|
|
|
2026-04-18 14:35:14 -07:00
|
|
|
|
const platform = currentPlatform();
|
|
|
|
|
|
const bootstrapDistinctId = await resolveBootstrapDistinctId();
|
|
|
|
|
|
|
2026-03-11 02:47:46 -07:00
|
|
|
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
|
2026-03-11 23:18:09 -07:00
|
|
|
|
api_host: "https://assets.surfsense.com",
|
2026-03-11 02:47:46 -07:00
|
|
|
|
ui_host: "https://us.posthog.com",
|
2026-03-11 23:18:09 -07:00
|
|
|
|
defaults: "2026-01-30",
|
2026-03-11 02:47:46 -07:00
|
|
|
|
capture_pageview: "history_change",
|
|
|
|
|
|
capture_pageleave: true,
|
2026-04-18 14:35:14 -07:00
|
|
|
|
...(bootstrapDistinctId
|
|
|
|
|
|
? {
|
|
|
|
|
|
bootstrap: {
|
|
|
|
|
|
distinctID: bootstrapDistinctId,
|
|
|
|
|
|
isIdentifiedID: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
: {}),
|
2026-03-11 15:10:53 -07:00
|
|
|
|
before_send: (event) => {
|
|
|
|
|
|
if (event?.properties) {
|
2026-04-18 14:35:14 -07:00
|
|
|
|
event.properties.platform = platform;
|
|
|
|
|
|
if (platform === "desktop") {
|
|
|
|
|
|
event.properties.is_desktop = true;
|
|
|
|
|
|
}
|
2026-04-08 02:41:33 -07:00
|
|
|
|
|
2026-03-11 02:47:46 -07:00
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
|
|
const ref = params.get("ref");
|
|
|
|
|
|
if (ref) {
|
|
|
|
|
|
event.properties.ref_code = ref;
|
|
|
|
|
|
event.properties.$set = {
|
|
|
|
|
|
...event.properties.$set,
|
|
|
|
|
|
initial_ref_code: ref,
|
|
|
|
|
|
};
|
|
|
|
|
|
event.properties.$set_once = {
|
|
|
|
|
|
...event.properties.$set_once,
|
|
|
|
|
|
first_ref_code: ref,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
event.properties.$set = {
|
|
|
|
|
|
...event.properties.$set,
|
2026-04-18 14:35:14 -07:00
|
|
|
|
platform,
|
2026-03-11 02:47:46 -07:00
|
|
|
|
last_seen_at: new Date().toISOString(),
|
|
|
|
|
|
};
|
2026-04-18 14:35:14 -07:00
|
|
|
|
|
|
|
|
|
|
event.properties.$set_once = {
|
|
|
|
|
|
...event.properties.$set_once,
|
|
|
|
|
|
first_seen_platform: platform,
|
|
|
|
|
|
};
|
2026-03-11 02:47:46 -07:00
|
|
|
|
}
|
|
|
|
|
|
return event;
|
|
|
|
|
|
},
|
|
|
|
|
|
loaded: (ph) => {
|
|
|
|
|
|
if (typeof window !== "undefined") {
|
|
|
|
|
|
window.posthog = ph;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// PostHog init failed (likely ad-blocker) – app must continue to work
|
|
|
|
|
|
}
|
2025-12-25 13:53:41 -08:00
|
|
|
|
}
|
2026-01-27 13:23:45 -05:00
|
|
|
|
|
|
|
|
|
|
if (typeof window !== "undefined") {
|
|
|
|
|
|
window.posthog = posthog;
|
2026-03-08 17:48:09 -07:00
|
|
|
|
|
|
|
|
|
|
if ("requestIdleCallback" in window) {
|
2026-04-18 14:35:14 -07:00
|
|
|
|
requestIdleCallback(() => {
|
|
|
|
|
|
void initPostHog();
|
|
|
|
|
|
});
|
2026-03-08 17:48:09 -07:00
|
|
|
|
} else {
|
2026-04-18 14:35:14 -07:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
void initPostHog();
|
|
|
|
|
|
}, 3500);
|
2026-03-08 17:48:09 -07:00
|
|
|
|
}
|
2026-01-27 13:23:45 -05:00
|
|
|
|
}
|