Skip to content
dsh.fish
Bundle

dsh-heatmap

DeepSeek Harness 页面埋点与热力图分析插件:科学埋点采集(点击/聚焦/停留/滚动/曝光)、本地热力图与统计面板、预留 CLI 与外部上传接口、上传前用户授权弹窗。

Source
Olympianz
License
MIT
Updated
Updated 1 hour ago

Readme

# dsh-heatmap

DeepSeek Harness 页面埋点与热力图分析插件。为后续产品设计优化提供量化数据:科学采集页面交互行为,本地展示热力图与统计,预留 CLI 与外部上传接口,上传前强制用户授权。

## 功能一览(在原始需求上补充后的完整设计)

| # | 功能 | 说明 |
|---|------|------|
| 1 | **科学埋点设计** | 四类事件(生命周期 / 交互 / 滚动曝光 / 热力图坐标)+ 稳定元素身份 + schema 版本化,参考主流产品分析(Amplitude / Mixpanel / Heap / Clarity)的埋点原则 |
| 2 | **热力图模式** | 点击 + 鼠标悬停密度热力图,色带「蓝→青→绿→黄→红」;面板标注「本地 / 本人数据」并展示聚合统计 |
| 3 | **CLI / 外部访问接口** | host 侧 `analytics_export` 工具(Agent 可调用)+ `webServer` 上的 `/dsh-heatmap/*` HTTP 路由,预留统一分析平台对接 |
| 4 | **上传授权弹窗** | 数据上传到外部/其他软件前弹出授权弹窗,用户「同意并上传」后才发送 |
| 5 | **隐私最小化**(补充) | 只采集控件身份、坐标、时间、视口;**绝不采集对话正文与输入内容**(输入仅记录长度) |
| 6 | **数据本地化**(补充) | 采集数据默认只存本地 localStorage;host 收集器用 NDJSON 落盘,可随时导出/清空 |
| 7 | **可配置**(补充) | 采样率、事件开关、热力图开关、鼠标热力图、上传地址、授权要求、存储上限均可配置 |

## 埋点设计(事件分类学)

### 事件类型

| 类型 | 触发时机 | 采集字段 | 产品用途 |
|------|---------|---------|---------|
| `session_start` / `session_end` | 页面加载 / 卸载或隐藏 | 会话 id、时间 | 会话数、会话时长 |
| `page_view` | 初始加载 + hash 路由变化 | path、hash | 页面/视图访问量 |
| `click` | 任何可点击元素被点击 | 元素身份 + 视口坐标 | 按钮点击率、**点击热力图** |
| `focus` / `blur` | 元素获得/失去焦点 | 元素身份 | 是否 focus、交互路径 |
| `hover` | 鼠标悬停(250ms 节流,可选) | 视口坐标 + 元素身份 | **悬停/注意力热力图** |
| `scroll_depth` | 滚动停止后(500ms 防抖) | 滚动深度 0..1 | 内容消费深度 |
| `visibility` | 页签可见性变化 | visible | **停留时长**(活跃时段累计) |
| `input` | 输入框输入(1s 节流) | 元素身份 + 输入**长度** | 输入活跃度(不含内容) |
| `impression` | 元素首次进入视口 ≥50%(IntersectionObserver) | 元素身份 | **曝光分析**(哪些面板/控件被看到) |

### 元素身份(稳定指纹)

采集端按优先级生成稳定的 `elementId`,保证跨会话可聚合到同一控件:

```
data-testid > id > aria-label > role#tag > tag:文本摘要(≤40字)
```

同时记录 `tag / role / ariaLabel / title / text` 供分析侧做控件维度下钻。

### 数据模型(schema v1)

```ts
interface AnalyticsEvent {
  v: number            // schema 版本
  id: string           // 事件 uuid
  ts: number           // epoch ms
  sessionId: string    // 会话 uuid
  type: EventType
  page: { path: string; hash: string }
  target?: ElementRef  // 元素身份
  position?: { x: number; y: number } // 热力图坐标
  depth?: number       // 滚动深度
  visible?: boolean    // 可见性
  inputLength?: number // 输入长度(无内容)
}
```

## 架构

```
┌────────────────────────── browser 半部 ──────────────────────────┐
│ tracker.ts     全局埋点采集(document 级监听)                      │
│ storage.ts     本地环形缓冲 + 设置 + 授权(localStorage)          │
│ HeatmapOverlay 热力图 + 统计面板 + 设置 + 上传入口(shell.overlay)│
│ ConsentModal   上传授权弹窗                                        │
└──────────────────────────────┬───────────────────────────────────┘
                                │ 授权后 fetch(POST)
┌──────────────────────────────▼────── host 半部 ──────────────────┐
│ /dsh-heatmap/ingest   批量上报(本地收集器)                        │
│ /dsh-heatmap/export   导出(JSON/NDJSON)                          │
│ /dsh-heatmap/stats    聚合统计                                     │
│ /dsh-heatmap/sessions 会话时间线(回放/复现)                        │
│ /dsh-heatmap/funnel   漏斗分析(有序步骤转化率)                     │
│ /dsh-heatmap/clear    清空                                         │
│ analytics_export 工具 stats/export/sessions/funnel/clear/upload    │
│ AnalyticsStore     NDJSON 落盘 + 内存环形缓冲 + 漏斗/会话聚合        │
└──────────────────────────────────────────────────────────────────┘
```

数据默认只在本机流动:采集→本地;上传→(授权后)host 收集器或配置的外部地址。

## 安装

```sh
dsh plugin --profile web add ./dsh-heatmap
# 或使用 dsh-master:dsh_master_install 工具
```

然后重启 dsh(`dsh web` 或 `dsh --profile web`)。重启后页面右下角会出现 🔥 按钮,打开面板即可查看统计、开启热力图。

## 开发

```sh
# 在插件目录内
pnpm install
pnpm run build   # 构建 lib/client.js(browser 半部)
pnpm run typecheck
```

## 配置

### host 配置(cordis.yml,部署级默认值)

```yaml
- id: dsh-heatmap
  config:
    enabled: true            # host 收集器与工具开关
    dataDir: ''              # 落盘目录;空则 $DSH_HOME/storages/dsh-heatmap
    maxEvents: 20000         # 环形缓冲上限
    uploadEndpoint: ''       # 统一分析平台上传地址(analytics_export upload 目标)
    consentRequired: true    # 上传是否要求授权(文档化;实际弹窗在 browser 半部)
```

### 客户端设置(localStorage,运行时在面板中调整)

| 设置 | 默认 | 说明 |
|------|------|------|
| 热力图模式 | 关 | 开启全屏热力图覆盖层 |
| 采集埋点 | 开 | 总开关 |
| 鼠标热力图 | 关 | 是否采集悬停坐标(开启会增大数据量) |
| 上传需授权 | 开 | 上传前是否弹授权窗 |
| 上传地址 | 空 | 空 = 同源 host 收集器 `/dsh-heatmap/ingest` |

## CLI / 外部访问接口

### 1. Agent 工具(`analytics_export`)

在会话中让 Agent 调用:

```
动作:stats     聚合统计(事件总数/点击/聚焦/曝光/会话数/按类型分布)
动作:export    导出最近 5000 条事件
动作:sessions  会话时间线(最近 20 个会话的有序事件序列,用于回放/复现)
动作:funnel    漏斗分析(需 steps:有序事件类型数组,如 [session_start, click, input])
动作:clear     清空收集器数据
动作:upload    上传到 config.uploadEndpoint(统一分析平台)
```

### 2. HTTP 路由

```sh
curl http://127.0.0.1:PORT/dsh-heatmap/health
curl http://127.0.0.1:PORT/dsh-heatmap/stats
curl http://127.0.0.1:PORT/dsh-heatmap/export?format=json&limit=100
curl http://127.0.0.1:PORT/dsh-heatmap/sessions?limit=20
curl -X POST http://127.0.0.1:PORT/dsh-heatmap/funnel -H 'content-type: application/json' -d '{"steps":["session_start","click","input"]}'
curl -X POST http://127.0.0.1:PORT/dsh-heatmap/ingest -H 'content-type: application/json' -d '{"v":1,"sessionId":"s","sentAt":0,"events":[...]}'
curl -X DELETE http://127.0.0.1:PORT/dsh-heatmap/clear
```

> 端口即 DSH 网页服务的端口(客户端与 host 同源)。

## 统一分析平台对接

预留了三条对接路径,按需选择:

1. **Agent 工具 `upload`**:配置 `uploadEndpoint` 后,让 Agent 调用 `analytics_export`(action=upload)把收集器数据批量 POST 到平台。
2. **HTTP 路由**:`GET /dsh-heatmap/export` 拉取原始事件,由你的平台 SDK/脚本转发。
3. **示例适配脚本**:[`examples/push-to-platform.mjs`](examples/push-to-platform.mjs) —— 从 `/export` 拉取、按 `mapEvent` 适配成平台形状、POST 到 `PLATFORM_ENDPOINT`(仅需改这一个适配函数)。

```sh
DSH_BASE=http://127.0.0.1:3080 \
PLATFORM_ENDPOINT=https://analytics.example.com/ingest \
PLATFORM_API_KEY=sk-xxx \
node examples/push-to-platform.mjs
```

## 隐私与合规

- 采集默认**最小化**:不采集对话正文、不采集输入内容(仅长度)、不采集 PII。
- 数据默认只在用户本机(localStorage / 本地 NDJSON)。
- 上传动作前弹出授权弹窗,明示「上传什么、上传到哪里、不含对话内容」,用户确认后才发送。
- 可随时「清除本地」或在 host 侧 `clear` 删除收集器数据。

## 后续演进(预留)

- 可视化会话回放:在面板内把 `sessions` 时间线渲染成逐步重放。
- 曝光时长:为 `impression` 记录进入/离开视口时长(当前只记首次曝光)。
- 性能埋点:`navigation`/`resource` 时序。

> 生成自 DSH-Master(dsh-master)脚手架并扩展。

Install

dsh plugin --profile web add github:Olympianz/dsh-heatmap

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source