npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

onerway-analytics

v1.1.0

Published

Onrway Analytics SDK

Readme

onerway-analytics

客户端埋点 SDK,支持双发:自建数据服务 + Google Tag Manager(GTM)。

安装

npm

npm install onerway-analytics

CDN / 本地文件

<script src="./dist/bundle/index.js"></script>
<!-- 全局变量:window.OnrwayAnalytics -->

快速开始

import { createAnalytics } from 'onerway-analytics';

const analytics = createAnalytics({
  appKey:    'your-app-key',
  serverUrl: 'https://your-server.com/collect',
  env:       'prod',
  debug:     true,
});

上报模式

双发(自建服务 + GTM)

const analytics = createAnalytics({
  appKey:    'your-app-key',
  serverUrl: 'https://your-server.com/collect',
  env:       'prod',
  gtm: {
    containerId: 'GTM-XXXXXXX',
    enabled:     true,
  },
});

只发自建服务

不配置 gtm,或设置 gtm.enabled: false

const analytics = createAnalytics({
  appKey:    'your-app-key',
  serverUrl: 'https://your-server.com/collect',
  env:       'prod',
});

只发 GTM

设置 disableServer: trueserverUrl 可留空,所有事件只推入 dataLayer:

const analytics = createAnalytics({
  appKey:        'your-app-key',
  serverUrl:     '',
  disableServer: true,
  gtm: {
    containerId: 'GTM-XXXXXXX',
    enabled:     true,
  },
});

disableServer: true 时,analytics.flush() 和重试机制均不生效。


API

事件埋点

// 普通事件(进入缓冲区,定时批量发送)
analytics.track('button_click', { target_id: 'buy_btn', scene: 'product' });

// 关键事件(立即发送,不等缓冲区)
analytics.track('payment_success', { order_id: '456' }, { keyEvent: true });

用户标识

// 设置用户 ID 与属性
analytics.identify('user-123', { plan: 'pro', email: '[email protected]' });

// 获取用户信息
const profile = analytics.getUserProfile();
// { userId: 'user-123', anonymousId: 'uuid...', attributes: { plan: 'pro' } }

// 重置用户身份
analytics.reset();

GTM 编程式控制

// 直接推送自定义数据到 dataLayer
analytics.gtm.push({ event: 'custom_event', key: 'value' });

// 推送带事件名的数据
analytics.gtm.track('checkout_start', { step: 1 });

// 设置用户 ID
analytics.gtm.setUserId('user-123');

// 设置用户属性
analytics.gtm.setUserProperties({ plan: 'pro' });

其他方法

analytics.flush();                        // 立即刷新缓冲区
analytics.getSessionId();                 // 获取当前 session ID
analytics.getClientId();                  // 获取匿名客户端 ID
analytics.setClientType('MINI_PROGRAM'); // 设置客户端类型
analytics.setMerchantLanguage('zh');     // 设置商户语言
analytics.destroy();                      // 销毁实例,移除事件监听(SPA 路由切换时使用)

自动埋点

默认开启,通过 data-track-* 属性声明式配置:

<!-- 自定义事件名 -->
<button data-track-name="subscribe_click">订阅</button>

<!-- 带 JSON 属性 -->
<button data-track-name="buy_now"
        data-track-properties='{"product":"shoes","price":299}'>
  立即购买
</button>

<!-- 任意 data-track-* 前缀自动成为属性键 -->
<a data-track-name="share"
   data-track-platform="wechat"
   data-track-position="top">分享</a>

<!-- 忽略该元素 -->
<div data-track-ignore>不追踪</div>

限定追踪范围:

createAnalytics({
  serverUrl:          '...',
  autoTrackSelector:  '#app', // 只追踪 #app 内的点击
});

关闭自动埋点:

createAnalytics({ serverUrl: '...', autoTrack: false });

采样控制

通过 sampleRate 控制上报比例,降低高流量场景的服务器压力。决策在每次页面加载时独立进行——命中采样的会话全量上报,未命中的会话全部丢弃(包括 GTM)。

// 只上报约 10% 的页面会话
const analytics = createAnalytics({
  appKey:     'your-app-key',
  serverUrl:  'https://your-server.com/collect',
  sampleRate: 0.1,
});
  • sampleRate: 1(默认)— 全量上报
  • sampleRate: 0 — 全部丢弃,可用于临时关闭上报
  • sampleRate: 0.1 — 约 10% 的页面会话上报,每次刷新重新决策

采样决策作用于整个会话:同一次页面加载内,所有 track() 要么全部上报,要么全部丢弃,不会出现部分事件缺失的碎片数据。


配置项

| 配置 | 类型 | 默认值 | 说明 | |---|---|---|---| | appKey | string | — | 应用标识 | | serverUrl | string | — | 数据接收端点(disableServer: true 时可留空) | | apiKey | string | — | API Key(不填则按 env 自动解析) | | env | string | — | 环境:beta | test | uat | prod | | debug | boolean | false | 开启控制台日志 | | autoTrack | boolean | true | 自动点击追踪 | | autoTrackPageView | boolean | true | 初始化时自动发送 page_view;设为 false 可手动控制 | | autoTrackSelector | string | — | 自动埋点的 CSS 选择器范围 | | sampleRate | number | 1 | 采样率 0~1;每次页面加载独立掷骰,0.1 表示约 10% 的页面会话上报,0 全不报,1 全量报 | | system | string | — | 系统标识,写入每条事件 | | domain | string | — | 业务域标识,写入每条事件 | | keyEvents | string[] | — | 关键事件名单,命中的事件立即发送 | | bufferFlushInterval | number | 5000 | 缓冲区定时刷新间隔(ms) | | bufferMaxSize | number | 25 | 缓冲区达到此数量立即刷新 | | maxRetryCount | number | 3 | 发送失败最大重试次数(指数退避) | | sessionTimeout | number | 1800000 | 会话超时(ms),默认 30 分钟 | | performance.enabled | boolean | true | Core Web Vitals 采集开关 | | gtm.enabled | boolean | — | GTM 双发开关 | | gtm.containerId | string | — | GTM 容器 ID(GTM-XXXXXXX 格式) | | gtm.dataLayerName | string | 'dataLayer' | 自定义 dataLayer 变量名 | | disableServer | boolean | false | 关闭自建服务上报,只推 GTM |


上报数据结构

自建服务(批量 POST)

{
  "client_id":       "uuid",
  "user_id":         "user-123",
  "session_id":      "uuid",
  "user_properties": { "plan": "pro" },
  "context": {
    "sdk_version": "1.0.0",
    "app_key":     "your-app-key",
    "browser":     { "name": "Chrome", "version": "135" },
    "operating_system": { "name": "Windows", "version": "10" },
    "device_type": "desktop",
    "country":     "CN",
    "language":    "zh-CN",
    "timezone":    "Asia/Shanghai"
  },
  "marketing": {
    "utm_source":   "google",
    "utm_medium":   "cpc",
    "utm_campaign": "spring_sale",
    "landing_page": "https://example.com/?utm_source=google",
    "referrer_url": "https://google.com"
  },
  "events": [
    {
      "event_id":          "uuid",
      "event_name":        "button_click",
      "timestamp":         1700000000000,
      "key_event":         false,
      "batch_event_index": 0,
      "batch_ordering_id": "1700000000000-1",
      "batch_page_id":     "abc-xyz",
      "event_properties": {
        "system":      "web",
        "domain":      "payment",
        "scene":       "product",
        "action":      "click",
        "target_type": "button",
        "target_id":   "buy_btn",
        "page_url":    "https://example.com/product"
      }
    }
  ]
}

GTM dataLayer

每个 track() 调用推入一条:

{
  "event":      "button_click",
  "action":     "click",
  "target_id":  "buy_btn",
  "session_id": "uuid",
  "page_url":   "https://example.com/product",
  "referrer":   ""
}

identify() 推入:

{ "userId": "user-123" }
{ "plan": "pro", "email": "[email protected]" }

采集能力

| 采集项 | 说明 | |---|---| | 点击事件 | 自动埋点(data-track-*)+ 手动 analytics.track() | | 页面浏览 | 初始化时自动发送 page_view(可通过 autoTrackPageView: false 关闭) | | JS 错误 | 全局 window.error / unhandledrejection 自动捕获 | | Core Web Vitals | LCP / FCP / CLS / INP / TTFB(web_vital 事件) | | 设备上下文 | 浏览器、OS、屏幕分辨率、语言、时区、设备类型 | | 营销归因 | UTM 参数持久化、落地页、来源 URL(SPA 路由切换后仍保留) |


可靠性机制

  • 缓冲区 + 批量发送:事件先入缓冲区,满 bufferMaxSize 或到 bufferFlushInterval 后批量发送
  • 指数退避重试:发送失败最多重试 maxRetryCount 次,间隔 1s / 2s / 4s…
  • 本地持久化:超出重试次数的事件写入 localStorage,下次页面加载时自动恢复补发(24 小时内有效)
  • 页面关闭兜底beforeunload / pagehide 时用 sendBeacon 发送缓冲区剩余事件
  • 采样控制sampleRate 在客户端决定是否上报,降低高流量场景的服务器压力

SPA 使用建议

路由切换时销毁旧实例,重建新实例以正确发送新页面的 page_view

// 路由离开时
analytics.destroy();

// 路由进入时
analytics = createAnalytics({ ... });
// 或手动控制
analytics = createAnalytics({ ..., autoTrackPageView: false });
analytics.track('page_view', { page_url: location.href });