@ziuchen/umami
v0.0.1
Published
Tiny isomorphic Umami v2 analytics client. Pure fetch, no DOM dependency. Works in browsers, Electron file://, Node.js and edge runtimes.
Maintainers
Readme
@ziuchen/umami
极简 Umami v2 上报客户端。纯 fetch 调用 /api/send REST API,面向 uTools 插件 / Electron / 浏览器,不依赖任何官方 SDK / cookie / DOM mutation observer。
设计动机:
- 官方
umami.jstracker 需要<script>加载,在 Electronfile:/// 严格 CSP 场景下不友好 - 不需要 cookie 持久化(Distinct ID 由调用方控制)
- 体积小、零依赖、TypeScript-first
- API 聚焦不过度抽象:初始化只接受必要静态参数
安装
pnpm add @ziuchen/umami基础用法
import { createUmamiClient } from "@ziuchen/umami";
const umami = createUmamiClient({
endpoint: "https://umami.example.com",
websiteId: "xxxx-xxxx-xxxx-xxxx",
hostname: "app.utools.local", // file:// 下 location.hostname 为空,写死虚拟域名
});
// pageview:默认读 location.pathname / document.title,可 override
await umami.pageview();
await umami.pageview({ url: "/history", title: "History" });
// 自定义事件
await umami.track("clip_copy", { kind: "text", source: "list" });
// 设置 Distinct ID + 静态属性
await umami.identify("device-or-user-id", { product_version: "abc123" });
// 用户登录后再追发动态属性(不动 distinct id)
await umami.setSessionData({ nickname: "Ziu", plan: "member" });
// 性能上报(对应 Umami dashboard 的 Performance 面板)
await umami.sendPerformance({ fcp: 320, lcp: 800, cls: 0.02, ttfb: 50 });API
interface UmamiClientOptions {
endpoint: string; // Umami 实例根地址(不含末尾斜杠)
websiteId: string; // Website UUID
hostname: string; // payload hostname;file:// 用虚拟域名
sendPath?: string; // 默认 "/api/send";改 "/c" 等可绕广告拦截反代
timeoutMs?: number; // 默认 5000
fetch?: typeof fetch; // 自定义 fetch
debug?: boolean; // 失败时 console.warn
}
interface SendOverrides {
url?: string; // 默认 location.pathname + search,再退到 "/"
title?: string; // 默认 document.title
referrer?: string; // 默认 document.referrer
}
interface UmamiClient {
pageview(overrides?: SendOverrides): Promise<void>;
track(name: string, data?: Record<string, unknown>, overrides?: SendOverrides): Promise<void>;
identify(
id: string,
sessionData?: Record<string, unknown>,
overrides?: SendOverrides,
): Promise<void>;
setSessionData(data: Record<string, unknown>, overrides?: SendOverrides): Promise<void>;
sendPerformance(metrics: PerformanceMetrics, overrides?: SendOverrides): Promise<void>;
getDistinctId(): string | undefined;
reset(): void;
}所有上报方法都返回 Promise<void>,网络失败 / 超时静默不抛。
Session properties 是 append-only
Umami v2 服务端把每次 identify / setSessionData 收到的字段都作为新记录追加,dashboard 会列出每个 key 的所有历史值。建议:
- 静态字段(版本号、环境)只在 identify 启动时上报一次
- 动态字段(用户身份)只在真正变化时 setSessionData
- 未知态(如"未登录")干脆不上报,避免污染历史
License
MIT
