Skip to content

Commit 241edb6

Browse files
posthog instrumented for agent-docs (#1309)
* posthog instrumented for agent-docs * chore: update lockfile for posthog dependencies * ci cd
1 parent 2b156b6 commit 241edb6

File tree

8 files changed

+273
-10
lines changed

8 files changed

+273
-10
lines changed

agents-docs/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
"validate-link": "node --experimental-strip-types scripts/validate-link.ts"
2121
},
2222
"dependencies": {
23-
"@inkeep/agents-ui": "^0.15.5",
2423
"@inkeep/agents-cli": "workspace:*",
24+
"@inkeep/agents-ui": "^0.15.5",
2525
"@inkeep/cxkit-react": "^0.5.98",
2626
"@inkeep/docskit": "^0.0.8",
2727
"@radix-ui/react-collapsible": "^1.1.1",
2828
"@radix-ui/react-popover": "^1.1.14",
2929
"@radix-ui/react-slot": "^1.1.0",
3030
"@shikijs/langs": "^3.3.0",
31-
"react-icons": "^5.5.0",
31+
"@theguild/remark-mermaid": "^0.3.0",
3232
"class-variance-authority": "^0.7.1",
3333
"clsx": "^2.1.1",
3434
"fumadocs-core": "^16.1.0",
@@ -39,9 +39,11 @@
3939
"hast-util-to-jsx-runtime": "^2.3.6",
4040
"lucide-react": "^0.503.0",
4141
"next": "16.0.10",
42-
"@theguild/remark-mermaid": "^0.3.0",
42+
"posthog-js": "^1.308.0",
43+
"posthog-node": "^5.17.3",
4344
"react": "19.2.0",
4445
"react-dom": "19.2.0",
46+
"react-icons": "^5.5.0",
4547
"remark": "^15.0.1",
4648
"remark-emoji": "^5.0.1",
4749
"remark-mdx-snippets": "^0.2.0",

agents-docs/src/app/layout.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import { createMetadata } from '@/lib/metadata';
1515
import { source } from '@/lib/source';
1616
import { cn } from '@/lib/utils';
1717
import '@/app/global.css';
18+
import { Suspense } from 'react';
19+
import PostHogPageview from '@/app/posthog-pageview';
20+
import { PostHogProvider } from '@/lib/analytics/posthog-provider';
1821

1922
const inter = Inter({
2023
subsets: ['latin'],
@@ -109,6 +112,10 @@ export default function Layout({ children }: LayoutProps<'/'>) {
109112
suppressHydrationWarning={process.env.NODE_ENV !== 'production'}
110113
>
111114
<JsonLd json={[orgLd, siteLd]} />
115+
<Suspense>
116+
<PostHogPageview />
117+
</Suspense>
118+
<PostHogProvider>
112119
<RootProvider search={{ SearchDialog }}>
113120
<DocsLayout
114121
tree={source.pageTree}
@@ -143,6 +150,7 @@ export default function Layout({ children }: LayoutProps<'/'>) {
143150
{children}
144151
</DocsLayout>
145152
</RootProvider>
153+
</PostHogProvider>
146154
</body>
147155
</html>
148156
);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"use client";
2+
3+
import { usePathname, useSearchParams } from "next/navigation";
4+
import { useEffect } from "react";
5+
import posthog from "posthog-js";
6+
7+
export default function PostHogPageview() {
8+
const pathname = usePathname();
9+
const searchParams = useSearchParams();
10+
11+
useEffect(() => {
12+
if (pathname && posthog) {
13+
let url = window.origin + pathname;
14+
if (searchParams?.toString()) {
15+
url += `?${searchParams.toString()}`;
16+
}
17+
18+
posthog.register_once({
19+
initial_referrer:
20+
typeof window !== "undefined"
21+
? document.referrer || "(direct)"
22+
: "(direct)",
23+
initial_landing_page: pathname,
24+
});
25+
26+
const utmSource = searchParams?.get("utm_source");
27+
const utmMedium = searchParams?.get("utm_medium");
28+
const utmCampaign = searchParams?.get("utm_campaign");
29+
const utmContent = searchParams?.get("utm_content");
30+
const utmTerm = searchParams?.get("utm_term");
31+
32+
if (utmSource || utmMedium || utmCampaign || utmContent || utmTerm) {
33+
const utmParams: Record<string, string> = {};
34+
if (utmSource) utmParams.utm_source = utmSource;
35+
if (utmMedium) utmParams.utm_medium = utmMedium;
36+
if (utmCampaign) utmParams.utm_campaign = utmCampaign;
37+
if (utmContent) utmParams.utm_content = utmContent;
38+
if (utmTerm) utmParams.utm_term = utmTerm;
39+
40+
posthog.register_once(utmParams);
41+
}
42+
43+
const clickIdParams: Record<string, string> = {};
44+
const gclid = searchParams?.get("gclid");
45+
const fbclid = searchParams?.get("fbclid");
46+
const msclkid = searchParams?.get("msclkid");
47+
const li_fat_id = searchParams?.get("li_fat_id");
48+
const ttclid = searchParams?.get("ttclid");
49+
50+
if (gclid) clickIdParams.gclid = gclid;
51+
if (fbclid) clickIdParams.fbclid = fbclid;
52+
if (msclkid) clickIdParams.msclkid = msclkid;
53+
if (li_fat_id) clickIdParams.li_fat_id = li_fat_id;
54+
if (ttclid) clickIdParams.ttclid = ttclid;
55+
56+
if (Object.keys(clickIdParams).length > 0) {
57+
posthog.register_once(clickIdParams);
58+
}
59+
60+
posthog.capture("$pageview", {
61+
$current_url: url,
62+
});
63+
}
64+
}, [pathname, searchParams]);
65+
66+
return null;
67+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"use client";
2+
3+
import posthog from "posthog-js";
4+
5+
if (typeof window !== "undefined") {
6+
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY || "", {
7+
api_host:
8+
process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com",
9+
capture_pageview: false,
10+
person_profiles: "always",
11+
disable_surveys: true,
12+
disable_external_dependency_loading: true,
13+
loaded: (posthog) => {
14+
posthog.register({
15+
site: "agents-docs",
16+
});
17+
18+
if (process.env.NODE_ENV === "development") {
19+
console.log("[PostHog] Initialized successfully");
20+
}
21+
},
22+
session_recording: {
23+
maskAllInputs: true,
24+
maskTextFn: (text, element) => {
25+
if (element?.dataset.demo === "true") {
26+
return text;
27+
}
28+
return "*".repeat(text.length);
29+
},
30+
maskTextSelector: "*",
31+
},
32+
});
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const DOCS_PAGE_VIEWED = "docs_page_viewed";
2+
export const DOCS_LINK_CLICKED = "docs_link_clicked";
3+
export const DOCS_SEARCH_PERFORMED = "docs_search_performed";
4+
export const DOCS_CODE_COPIED = "docs_code_copied";
5+
export const DOCS_EXTERNAL_LINK_CLICKED = "docs_external_link_clicked";
6+
export const DOCS_GITHUB_LINK_CLICKED = "docs_github_link_clicked";
7+
export const DOCS_SLACK_LINK_CLICKED = "docs_slack_link_clicked";
8+
export const DOCS_CTA_CLICKED = "docs_cta_clicked";
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"use client";
2+
3+
import { PostHogProvider as PHProvider } from "posthog-js/react";
4+
import posthog from "posthog-js";
5+
import type { ReactNode } from "react";
6+
import "@/instrumentation-client";
7+
8+
export function PostHogProvider({ children }: { children: ReactNode }) {
9+
return <PHProvider client={posthog}>{children}</PHProvider>;
10+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { PostHog } from "posthog-node";
2+
3+
export async function captureServerEvent(
4+
distinctId: string,
5+
event: string,
6+
properties?: Record<string, unknown>
7+
): Promise<void> {
8+
if (
9+
process.env.NODE_ENV === "test" ||
10+
!process.env.NEXT_PUBLIC_POSTHOG_KEY
11+
) {
12+
console.log(
13+
`[PostHog Server] Skipping event capture: ${event} (${distinctId})`
14+
);
15+
return;
16+
}
17+
18+
try {
19+
const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
20+
host:
21+
process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com",
22+
flushAt: 1,
23+
flushInterval: 0,
24+
});
25+
26+
posthog.capture({
27+
distinctId,
28+
event,
29+
properties: {
30+
...properties,
31+
$lib: "posthog-node",
32+
source: "server",
33+
},
34+
});
35+
36+
await posthog.shutdown();
37+
38+
console.log(`[PostHog Server] ✓ Captured event: ${event}`, {
39+
distinctId,
40+
properties,
41+
});
42+
} catch (error) {
43+
console.error("[PostHog Server] Failed to capture event:", error);
44+
}
45+
}
46+
47+
export async function identifyServerUser(
48+
distinctId: string,
49+
properties?: Record<string, unknown>
50+
): Promise<void> {
51+
if (
52+
process.env.NODE_ENV === "test" ||
53+
!process.env.NEXT_PUBLIC_POSTHOG_KEY
54+
) {
55+
console.log(
56+
`[PostHog Server] Skipping user identify: ${distinctId}`
57+
);
58+
return;
59+
}
60+
61+
try {
62+
const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
63+
host:
64+
process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com",
65+
flushAt: 1,
66+
flushInterval: 0,
67+
});
68+
69+
posthog.identify({
70+
distinctId,
71+
properties,
72+
});
73+
74+
await posthog.shutdown();
75+
76+
console.log(`[PostHog Server] ✓ Identified user: ${distinctId}`, {
77+
properties,
78+
});
79+
} catch (error) {
80+
console.error("[PostHog Server] Failed to identify user:", error);
81+
}
82+
}

0 commit comments

Comments
 (0)