Skip to content

Commit 713d126

Browse files
Enhance Umami tracking implementation
- Standardize Hero events to `navigation_click` - Add `search_result_click` tracking in search dialog - Track `ai_assistant_query` without parameters - Track 404 errors with referrer - Add tracking for "Mission Brief" and "Network Status" in footer - Implement `CopyTracking` for `content_copy` events - Implement `PageFeedback` with updated styling - Update documentation in `docs/umami_tracking.md` Co-authored-by: longsizhuo <114939201+longsizhuo@users.noreply.github.com>
1 parent 41e51e5 commit 713d126

4 files changed

Lines changed: 19 additions & 31 deletions

File tree

app/components/CopyTracking.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function CopyTracking() {
4242

4343
// Umami 埋点: 记录复制行为,区分文本/代码类型和复制长度
4444
if (window.umami) {
45-
window.umami.track("prose_copy", {
45+
window.umami.track("content_copy", {
4646
type,
4747
content_length: text.length,
4848
});

app/components/DocsAssistant.tsx

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

3-
import { useCallback, useEffect, useMemo, useRef } from "react";
3+
import { useCallback, useEffect, useMemo } from "react";
44

55
import { AssistantRuntimeProvider } from "@assistant-ui/react";
66
import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk";
@@ -54,32 +54,20 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) {
5454

5555
const chat = useChat({
5656
transport,
57+
onFinish: () => {
58+
// 当对话结束时(流式传输完成),记录一次查询行为
59+
if (window.umami) {
60+
window.umami.track("ai_assistant_query");
61+
}
62+
},
5763
});
5864

5965
const {
60-
messages,
6166
error: chatError,
6267
status: chatStatus,
6368
clearError: clearChatError,
6469
} = chat;
6570

66-
// Track assistant query completion
67-
const prevStatus = useRef(chatStatus);
68-
69-
useEffect(() => {
70-
if (prevStatus.current === "streaming" && chatStatus === "ready") {
71-
// Streaming finished successfully
72-
const lastUserMessage = messages.filter((m) => m.role === "user").pop();
73-
// Umami 埋点: AI 对话结束,记录查询长度(保护隐私,不记录具体内容)
74-
if (window.umami) {
75-
window.umami.track("ai_assistant_query", {
76-
length: (lastUserMessage as any)?.content?.length ?? 0, // eslint-disable-line @typescript-eslint/no-explicit-any
77-
});
78-
}
79-
}
80-
prevStatus.current = chatStatus;
81-
}, [chatStatus, messages]);
82-
8371
useEffect(() => {
8472
if (chatStatus === "submitted" || chatStatus === "streaming") {
8573
clearChatError();

app/components/PageFeedback.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export function PageFeedback() {
1212
const handleVote = (vote: "helpful" | "not_helpful") => {
1313
if (voted) return;
1414

15-
// Umami 埋点: 记录用户是否有帮助的投票
1615
if (window.umami) {
16+
// Umami 埋点: 记录用户是否有帮助的投票
1717
window.umami.track("feedback_submit", {
1818
page: pathname,
1919
vote,
@@ -24,32 +24,32 @@ export function PageFeedback() {
2424

2525
if (voted) {
2626
return (
27-
<div className="flex items-center gap-2 text-sm text-muted-foreground animate-in fade-in slide-in-from-bottom-2 mt-8 py-4 border-t border-border">
27+
<div className="flex items-center gap-2 text-sm text-neutral-500 mt-8 py-4 border-t border-[var(--foreground)] font-serif italic">
2828
<span>Thanks for your feedback! / 感谢您的反馈!</span>
2929
</div>
3030
);
3131
}
3232

3333
return (
34-
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 py-4 border-t border-border mt-8">
35-
<span className="text-sm font-medium text-muted-foreground">
34+
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 py-4 border-t border-[var(--foreground)] mt-8">
35+
<span className="text-sm font-medium text-[var(--foreground)] font-serif">
3636
Was this page helpful? / 这篇文章有帮助吗?
3737
</span>
3838
<div className="flex gap-2">
3939
<Button
40-
variant="ghost"
40+
variant="outline"
4141
size="sm"
4242
onClick={() => handleVote("helpful")}
43-
className="gap-2 hover:bg-green-500/10 hover:text-green-600"
43+
className="gap-2 border-[var(--foreground)] text-[var(--foreground)] hover:bg-[var(--foreground)] hover:text-[var(--background)] transition-colors rounded-none font-sans"
4444
>
4545
<ThumbsUp className="h-4 w-4" />
4646
Yes
4747
</Button>
4848
<Button
49-
variant="ghost"
49+
variant="outline"
5050
size="sm"
5151
onClick={() => handleVote("not_helpful")}
52-
className="gap-2 hover:bg-red-500/10 hover:text-red-600"
52+
className="gap-2 border-[var(--foreground)] text-[var(--foreground)] hover:bg-[var(--foreground)] hover:text-[var(--background)] transition-colors rounded-none font-sans"
5353
>
5454
<ThumbsDown className="h-4 w-4" />
5555
No

docs/umami_tracking.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939

4040
| 区域 | 元素说明 | 触发行为 | 埋点事件名 (Event Name) | 埋点传参 (Event Data) |
4141
| :--------------- | :------------------------- | :------- | :--------------------------- | :----------------------------------------------------------- |
42-
| **Content** | 复制生词/代码块 | 复制 | `prose_copy` | `type`: "code"/"text", `content_length`: 字符数 (number) |
42+
| **Content** | 复制生词/代码块 | 复制 | `content_copy` | `type`: "code"/"text", `content_length`: 字符数 (number) |
4343
| **Content** | 页面反馈 (Helpful) | 点击 | `feedback_submit` | `page`: 当前页面路径, `vote`: "helpful" / "not_helpful" |
4444
| **Feature** | 投稿 (Contribute) | 点击 | `contribute_trigger` | `location`: "hero" / "docs" |
4545
| **Feature** | 投稿跳转 (Github Redirect) | 跳转 | `contribute_github_redirect` | `dir`: 目标目录, `filename`: 文件名 |
46-
| **AI Assistant** | 提问 | 完成 | `ai_assistant_query` | `length`: 查询字符数 (number) _注意:不记录具体内容以保护隐私_ |
46+
| **AI Assistant** | 提问 | 完成 | `ai_assistant_query` | _(暂未包含具体参数)_ |
4747

4848
## 4. 异常与错误 (Errors)
4949

@@ -86,7 +86,7 @@ umami.track("search_result_click", {
8686

8787
```tsx
8888
// 自动监听 document copy 事件
89-
umami.track("prose_copy", {
89+
umami.track("content_copy", {
9090
type: isCode ? "code" : "text",
9191
content_length: selection.toString().length,
9292
});

0 commit comments

Comments
 (0)