Skip to content

Commit 4864b9f

Browse files
committed
posthog migration
1 parent 94e2cbc commit 4864b9f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+359
-545
lines changed

apps/dashboard/.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,8 @@ STRIPE_SECRET_KEY=""
108108

109109
# required for server wallet management
110110
NEXT_PUBLIC_THIRDWEB_VAULT_URL=""
111-
NEXT_PUBLIC_ENGINE_CLOUD_URL=""
111+
NEXT_PUBLIC_ENGINE_CLOUD_URL=""
112+
113+
# posthog setup
114+
NEXT_PUBLIC_POSTHOG_KEY=""
115+
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com

apps/dashboard/knip.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@thirdweb-dev/service-utils",
1414
"@thirdweb-dev/vault-sdk",
1515
"@types/color",
16-
"fast-xml-parser"
16+
"fast-xml-parser",
17+
"posthog-node"
1718
]
1819
}

apps/dashboard/next.config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ const baseNextConfig: NextConfig = {
146146
},
147147
async rewrites() {
148148
return [
149+
{
150+
source: "/_ph/static/:path*",
151+
destination: "https://us-assets.i.posthog.com/static/:path*",
152+
},
153+
{
154+
source: "/_ph/:path*",
155+
destination: "https://us.i.posthog.com/:path*",
156+
},
157+
{
158+
source: "/_ph/decide",
159+
destination: "https://us.i.posthog.com/decide",
160+
},
149161
{
150162
source: "/thirdweb.eth",
151163
destination: "/deployer.thirdweb.eth",
@@ -173,6 +185,8 @@ const baseNextConfig: NextConfig = {
173185
]),
174186
];
175187
},
188+
// This is required to support PostHog trailing slash API requests
189+
skipTrailingSlashRedirect: true,
176190
images: {
177191
dangerouslyAllowSVG: true,
178192
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",

apps/dashboard/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
"date-fns": "4.1.0",
6464
"fast-xml-parser": "^5.2.5",
6565
"fetch-event-stream": "0.1.5",
66-
"flat": "^6.0.1",
6766
"framer-motion": "12.17.0",
6867
"fuse.js": "7.1.0",
6968
"input-otp": "^1.4.1",
@@ -78,7 +77,8 @@
7877
"p-limit": "^6.2.0",
7978
"papaparse": "^5.5.3",
8079
"pluralize": "^8.0.0",
81-
"posthog-js": "1.67.1",
80+
"posthog-js": "1.252.0",
81+
"posthog-node": "5.1.0",
8282
"prettier": "3.5.3",
8383
"qrcode": "^1.5.3",
8484
"react": "19.1.0",
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use client";
2+
3+
import { PostHog } from "posthog-js";
4+
import { useEffect } from "react";
5+
import { DEFAULT_POSTHOG_SETTINGS } from "./shared";
6+
7+
const posthog = new PostHog();
8+
let initialized = false;
9+
10+
function init() {
11+
const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY;
12+
if (!posthogKey) {
13+
console.warn(
14+
"[DASHBOARD_ANALYTICS] NEXT_PUBLIC_POSTHOG_KEY is not set, cannt initialize analytics",
15+
);
16+
return;
17+
}
18+
19+
if (!initialized) {
20+
posthog.init(posthogKey, DEFAULT_POSTHOG_SETTINGS, "dashboard");
21+
initialized = true;
22+
}
23+
}
24+
25+
function identifyUser(userId: string) {
26+
if (!initialized) {
27+
console.warn(
28+
"[DASHBOARD_ANALYTICS] is not initialized, cannot identify user",
29+
);
30+
return;
31+
}
32+
posthog.identify(userId);
33+
}
34+
35+
function identifyTeam(teamId: string) {
36+
if (!initialized) {
37+
console.warn(
38+
"[DASHBOARD_ANALYTICS] is not initialized, cannot identify team",
39+
);
40+
return;
41+
}
42+
posthog.group("team", teamId);
43+
}
44+
45+
export function reset() {
46+
if (!initialized) {
47+
console.warn("[DASHBOARD_ANALYTICS] is not initialized, cannot reset");
48+
return;
49+
}
50+
posthog.reset();
51+
}
52+
53+
export function DashboardAnalyticsInitializer(props: { accountId?: string }) {
54+
// this ONE time we need to use a useEffect to initialize the posthog instance
55+
// eslint-disable-next-line no-restricted-syntax
56+
useEffect(() => {
57+
init();
58+
}, []);
59+
// eslint-disable-next-line no-restricted-syntax
60+
useEffect(() => {
61+
if (props.accountId) {
62+
identifyUser(props.accountId);
63+
}
64+
}, [props.accountId]);
65+
return null;
66+
}
67+
68+
export function TeamIdentifier(props: { teamId: string }) {
69+
// this ONE time we need to use a useEffect to initialize the posthog instance
70+
// eslint-disable-next-line no-restricted-syntax
71+
useEffect(() => {
72+
identifyTeam(props.teamId);
73+
}, [props.teamId]);
74+
return null;
75+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const DEFAULT_POSTHOG_SETTINGS = {
2+
api_host: "/_ph",
3+
ui_host: "https://us.posthog.com",
4+
capture_pageview: "history_change",
5+
capture_pageleave: "if_capture_pageview",
6+
// disable exception capture (for now)
7+
capture_exceptions: false,
8+
// specifically disable autocapture (does not affect pageview capture)
9+
autocapture: false,
10+
debug: process.env.NODE_ENV === "development",
11+
} as const;

apps/dashboard/src/@3rdweb-sdk/react/components/connect-wallet/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import * as analytics from "@/analytics/dasboard.client";
34
import { Button } from "@/components/ui/button";
45
import { useStore } from "@/lib/reactive";
56
import { getSDKTheme } from "app/(app)/components/sdk-component-theme";
@@ -155,6 +156,7 @@ export const CustomConnectWallet = (props: {
155156
}}
156157
onDisconnect={async () => {
157158
try {
159+
analytics.reset();
158160
await doLogout();
159161
} catch (err) {
160162
console.error("Failed to log out", err);

apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import { createTeam } from "@/actions/createTeam";
4+
import * as analytics from "@/analytics/dasboard.client";
45
import type { Project } from "@/api/projects";
56
import type { Team } from "@/api/team";
67
import { useDashboardRouter } from "@/lib/DashboardRouter";
@@ -34,6 +35,7 @@ export function AccountHeader(props: {
3435

3536
const logout = useCallback(async () => {
3637
try {
38+
analytics.reset();
3739
await doLogout();
3840
if (wallet) {
3941
disconnect(wallet);

apps/dashboard/src/app/(app)/account/settings/AccountSettingsPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { confirmEmailWithOTP } from "@/actions/confirmEmail";
33
import { apiServerProxy } from "@/actions/proxies";
44
import { updateAccount } from "@/actions/updateAccount";
5+
import * as analytics from "@/analytics/dasboard.client";
56
import { useDashboardRouter } from "@/lib/DashboardRouter";
67
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
78
import type { ThirdwebClient } from "thirdweb";
@@ -45,6 +46,7 @@ export function AccountSettingsPage(props: {
4546
}
4647
}}
4748
onAccountDeleted={async () => {
49+
analytics.reset();
4850
await doLogout();
4951
if (activeWallet) {
5052
disconnect(activeWallet);

apps/dashboard/src/app/(app)/layout.tsx

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import "../../global.css";
22
import { DashboardRouterTopProgressBar } from "@/lib/DashboardRouter";
33
import { cn } from "@/lib/utils";
4-
import { PHProvider } from "lib/posthog/Posthog";
5-
import { PosthogHeadSetup } from "lib/posthog/PosthogHeadSetup";
6-
import { PostHogPageView } from "lib/posthog/PosthogPageView";
4+
5+
import { DashboardAnalyticsInitializer } from "@/analytics/dasboard.client";
76
import type { Metadata } from "next";
87
import PlausibleProvider from "next-plausible";
98
import { Inter } from "next/font/google";
109
import NextTopLoader from "nextjs-toploader";
10+
import { getRawAccount } from "./account/settings/getAccount";
1111
import { AppRouterProviders } from "./providers";
1212

1313
const fontSans = Inter({
@@ -48,11 +48,12 @@ export const metadata: Metadata = {
4848
},
4949
};
5050

51-
export default function RootLayout({
51+
export default async function RootLayout({
5252
children,
5353
}: {
5454
children: React.ReactNode;
5555
}) {
56+
const account = await getRawAccount();
5657
return (
5758
<html lang="en" suppressHydrationWarning>
5859
<head>
@@ -61,26 +62,20 @@ export default function RootLayout({
6162
customDomain="https://pl.thirdweb.com"
6263
selfHosted
6364
/>
64-
<PosthogHeadSetup />
6565
</head>
66-
<PHProvider disable_session_recording={true}>
67-
<PostHogPageView />
68-
<body
69-
className={cn(
70-
"bg-background font-sans antialiased",
71-
fontSans.variable,
72-
)}
73-
>
74-
<AppRouterProviders>{children}</AppRouterProviders>
75-
<DashboardRouterTopProgressBar />
76-
<NextTopLoader
77-
color="hsl(var(--foreground))"
78-
height={3}
79-
shadow={false}
80-
showSpinner={false}
81-
/>
82-
</body>
83-
</PHProvider>
66+
<body
67+
className={cn("bg-background font-sans antialiased", fontSans.variable)}
68+
>
69+
<AppRouterProviders>{children}</AppRouterProviders>
70+
<DashboardRouterTopProgressBar />
71+
<DashboardAnalyticsInitializer accountId={account?.id} />
72+
<NextTopLoader
73+
color="hsl(var(--foreground))"
74+
height={3}
75+
shadow={false}
76+
showSpinner={false}
77+
/>
78+
</body>
8479
</html>
8580
);
8681
}

0 commit comments

Comments
 (0)