(null);
const router = useRouter();
- const { data: session } = useSession();
-
- // Note: this is currently the first client side page that gets loaded after a user registers. If this changes, we need to update this.
- // @nocheckin
- useEffect(() => {
- if (session?.user) {
- posthog.identify(session.user.id, {
- email: session.user.email,
- name: session.user.name,
- });
- }
- }, [session?.user]);
const onCreated = useCallback(() => {
router.push(`?step=${nextStep}`);
diff --git a/packages/web/src/app/components/logoutEscapeHatch.tsx b/packages/web/src/app/components/logoutEscapeHatch.tsx
index 8311afe00..ce7754362 100644
--- a/packages/web/src/app/components/logoutEscapeHatch.tsx
+++ b/packages/web/src/app/components/logoutEscapeHatch.tsx
@@ -1,5 +1,7 @@
import { LogOutIcon } from "lucide-react";
import { signOut } from "@/auth";
+import posthog from "posthog-js";
+
interface LogoutEscapeHatchProps {
className?: string;
}
@@ -14,6 +16,8 @@ export const LogoutEscapeHatch = ({
"use server";
await signOut({
redirectTo: "/login",
+ }).then(() => {
+ posthog.reset();
});
}}
>
diff --git a/packages/web/src/app/login/components/loginForm.tsx b/packages/web/src/app/login/components/loginForm.tsx
index 8f479d7a3..3d5d953c7 100644
--- a/packages/web/src/app/login/components/loginForm.tsx
+++ b/packages/web/src/app/login/components/loginForm.tsx
@@ -13,6 +13,12 @@ import { SourcebotLogo } from "@/app/components/sourcebotLogo";
import { TextSeparator } from "@/app/components/textSeparator";
import useCaptureEvent from "@/hooks/useCaptureEvent";
import DemoCard from "@/app/[domain]/onboard/components/demoCard";
+import Link from "next/link";
+import { env } from "@/env.mjs";
+
+const TERMS_OF_SERVICE_URL = "https://sourcebot.dev/terms";
+const PRIVACY_POLICY_URL = "https://sourcebot.dev/privacy";
+
interface LoginFormProps {
callbackUrl?: string;
error?: string;
@@ -98,6 +104,9 @@ export const LoginForm = ({ callbackUrl, error, enabledMethods }: LoginFormProps
]}
/>
+ {env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined && (
+ By signing in, you agree to the Terms of Service and Privacy Policy.
+ )}
)
}
diff --git a/packages/web/src/app/posthogProvider.tsx b/packages/web/src/app/posthogProvider.tsx
index c8198b7ba..12aa91fd4 100644
--- a/packages/web/src/app/posthogProvider.tsx
+++ b/packages/web/src/app/posthogProvider.tsx
@@ -5,13 +5,15 @@ import { PostHogProvider as PHProvider } from 'posthog-js/react'
import { usePathname, useSearchParams } from "next/navigation"
import { Suspense, useEffect } from "react"
import { env } from '@/env.mjs'
+import { useSession } from 'next-auth/react'
+import { captureEvent } from '@/hooks/useCaptureEvent'
+// @see: https://posthog.com/docs/libraries/next-js#capturing-pageviews
function PostHogPageView() {
const pathname = usePathname()
const searchParams = useSearchParams()
const posthog = usePostHog()
- // Track pageviews
useEffect(() => {
if (pathname && posthog) {
let url = window.origin + pathname
@@ -19,7 +21,9 @@ function PostHogPageView() {
url = url + `?${searchParams.toString()}`
}
- posthog.capture('$pageview', { '$current_url': url })
+ captureEvent('$pageview', {
+ $current_url: url,
+ });
}
}, [pathname, searchParams, posthog])
@@ -32,34 +36,55 @@ interface PostHogProviderProps {
}
export function PostHogProvider({ children, disabled }: PostHogProviderProps) {
+ const { data: session } = useSession();
+
useEffect(() => {
if (!disabled && env.NEXT_PUBLIC_POSTHOG_PAPIK) {
+ console.debug(`PostHog telemetry enabled. Cloud environment: ${env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT}`);
posthog.init(env.NEXT_PUBLIC_POSTHOG_PAPIK, {
// @see next.config.mjs for path rewrites to the "/ingest" route.
api_host: "/ingest",
person_profiles: 'identified_only',
capture_pageview: false,
autocapture: false,
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- sanitize_properties: (properties: Record, _event: string) => {
- // https://posthog.com/docs/libraries/js#config
- if (properties['$current_url']) {
- properties['$current_url'] = null;
- }
- if (properties['$ip']) {
- properties['$ip'] = null;
- }
-
- return properties;
- }
+ // In self-hosted mode, we don't want to capture the following
+ // default properties.
+ // @see: https://posthog.com/docs/data/events#default-properties
+ property_denylist: env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === undefined ? [
+ '$current_url',
+ '$pathname',
+ '$session_entry_url',
+ '$session_entry_host',
+ '$session_entry_pathname',
+ '$session_entry_referrer',
+ '$session_entry_referring_domain',
+ '$referrer',
+ '$referring_domain',
+ '$ip',
+ ] : []
});
} else {
- console.log("PostHog telemetry disabled");
+ console.debug("PostHog telemetry disabled");
+ }
+ }, [disabled]);
+
+ useEffect(() => {
+ if (!session) {
+ return;
+ }
+
+ // Only identify the user if we are running in a cloud environment.
+ if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined) {
+ posthog.identify(session.user.id, {
+ email: session.user.email,
+ name: session.user.name,
+ });
}
- }, [disabled])
+ }, [session]);
return (
+ {/* @see: https://github.com/vercel/next.js/issues/51581 */}
diff --git a/packages/web/src/env.mjs b/packages/web/src/env.mjs
index fc839b9a6..31b778410 100644
--- a/packages/web/src/env.mjs
+++ b/packages/web/src/env.mjs
@@ -50,8 +50,10 @@ export const env = createEnv({
// Misc UI flags
SECURITY_CARD_ENABLED: booleanSchema.default('false'),
},
- // @NOTE: Make sure you destructure all client variables in the
- // `experimental__runtimeEnv` block below.
+ // @NOTE: Please make sure of the following:
+ // - Make sure you destructure all client variables in
+ // the `experimental__runtimeEnv` block below.
+ // - Update the Dockerfile to pass these variables as build-args.
client: {
// PostHog
NEXT_PUBLIC_POSTHOG_PAPIK: z.string().optional(),
@@ -59,12 +61,15 @@ export const env = createEnv({
// Misc
NEXT_PUBLIC_SOURCEBOT_VERSION: z.string().default('unknown'),
NEXT_PUBLIC_POLLING_INTERVAL_MS: numberSchema.default(5000),
+
+ NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: z.enum(["dev", "staging", "prod"]).optional(),
},
// For Next.js >= 13.4.4, you only need to destructure client variables:
experimental__runtimeEnv: {
NEXT_PUBLIC_POSTHOG_PAPIK: process.env.NEXT_PUBLIC_POSTHOG_PAPIK,
NEXT_PUBLIC_SOURCEBOT_VERSION: process.env.NEXT_PUBLIC_SOURCEBOT_VERSION,
NEXT_PUBLIC_POLLING_INTERVAL_MS: process.env.NEXT_PUBLIC_POLLING_INTERVAL_MS,
+ NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: process.env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT,
},
skipValidation: process.env.SKIP_ENV_VALIDATION === "1",
emptyStringAsUndefined: true,
diff --git a/packages/web/src/lib/posthogEvents.ts b/packages/web/src/lib/posthogEvents.ts
index 2f36712d7..0cbc95683 100644
--- a/packages/web/src/lib/posthogEvents.ts
+++ b/packages/web/src/lib/posthogEvents.ts
@@ -244,6 +244,10 @@ export type PosthogEventMap = {
wa_demo_card_click: {},
wa_demo_try_card_pressed: {},
wa_share_link_created: {},
+ //////////////////////////////////////////////////////////////////
+ $pageview: {
+ $current_url: string,
+ },
}
export type PosthogEvent = keyof PosthogEventMap;
\ No newline at end of file