@pang3fan-creator/analytics-kit
v0.5.0
Published
Typed clients for querying Google Search Console, Google Analytics 4, Microsoft Clarity, Bing Webmaster Tools, Ahrefs, and keyword difficulty data. Runtime-agnostic (Node.js / Cloudflare Workers / edge).
Maintainers
Readme
analytics-kit
类型安全的网站分析数据查询客户端,用于在 Node.js 项目中查询六个平台的数据:
- Google Search Console(搜索表现:点击/展示/排名/CTR)
- Google Analytics 4(runReport 报表)
- Microsoft Clarity(仪表盘指标 + 实验性会话列表)
- Bing Webmaster Tools(排名与流量 / 关键词 / 页面)
- Ahrefs(免费公开端点:域名权重 DR 查询)
- 关键词难度(哥飞版)(seo.web.cafe 的关键词难度分、搜索量趋势与外链预算)
零 Node 专有依赖(仅 jose),基于全局 fetch,可在 Node.js 18+ / Cloudflare Workers / Deno / Bun 中运行。刻意不使用 googleapis 等官方包,因为它们依赖的 google-auth-library/gaxios 栈无法可靠运行在 Workers 等 edge 运行时。
安装
# 发布后(推荐)
pnpm add @pang3fan-creator/analytics-kit
# 发布前的私有引用方式:
pnpm add git+ssh://[email protected]/pang3fan-creator/analytics-kit.git前置配置(一次性)
Google(GSC + GA4 共用一套服务账号)
- 在 Google Cloud Console 创建项目,启用两个 API:
- Search Console API
- Google Analytics Data API
- 创建服务账号(IAM → Service Accounts),生成 JSON 密钥并下载。
- 授权访问数据(最常见踩坑点,漏掉必 403):
- GSC:设置 → 用户和权限 → 添加服务账号邮箱为用户(Restricted 权限即可)
- GA4:管理 → 属性访问管理 → 添加服务账号邮箱为 Viewer
Microsoft Clarity
- Clarity 项目 → Settings → Data Export → Generate new API Token(仅项目管理员可操作)
- Token 与单个项目绑定;每个项目需要各自的 token
Bing Webmaster Tools
- Bing Webmaster → 右上角 Settings → API Access → 接受条款 → API Key → Generate API Key
- API Key 按账号生成(不是站点),一个 Key 可用于账号下所有已验证站点;删除后必须更新所有引用它的项目
- 站点标识为 URL-prefix 形式(如
https://example.com/),Bing 不支持 Google 的sc-domain:网域资源语法
Ahrefs(当前仅免费公开端点)
- Ahrefs → Account settings → API keys → 生成 APIv3 Key(无需付费订阅;公共端点免费、消耗 0 units)
- 注意:
site-audit/*、keywords-explorer/*等订阅端点在公共 Key 下会 401(返["Error","Unauthorized"]),仅subscription-info/limits-and-usage在付费计划下可用;本库目前只实现免费能力,付费端点待升级 Lite+ 后按需扩展 - 域名权重数据公开显示需标注 "Domain Rating by Ahrefs"(许可条款)
环境变量
| 变量 | 说明 |
|---|---|
| GOOGLE_SERVICE_ACCOUNT_EMAIL | 服务账号邮箱(client_email) |
| GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY | 服务账号私钥(private_key),单行 \n 转义自动还原 |
| GSC_SITE_URL | GSC 属性:https://example.com/ 或 sc-domain:example.com |
| GA4_PROPERTY_ID | GA4 纯数字 Property ID(不是 G- 开头的数据流 ID) |
| CLARITY_API_TOKEN | Clarity 项目 API Token |
| BING_API_KEY | Bing Webmaster API Key(设置 → API Access → API Key,账号级) |
| BING_SITE_URL | Bing 站点标识,URL-prefix 形式,如 https://example.com/ |
| AHREFS_API_KEY | Ahrefs APIv3 Key(Account settings → API keys;免费公共端点无需订阅) |
| KD_API_TOKEN | 关键词难度(哥飞版)API Token,在 seo.web.cafe/kd 登录后生成(wc_mcp_ 前缀) |
所有变量都可以不设——改为在创建客户端时显式传参(Cloudflare Workers 无 process.env 时用这种方式)。
用法
Google Search Console
import { createGscClient } from '@pang3fan-creator/analytics-kit'
const gsc = createGscClient() // 自动读环境变量
const result = await gsc.searchAnalytics({
startDate: '2026-08-01',
endDate: '2026-08-21',
dimensions: ['query', 'page'],
rowLimit: 1000,
})
// 自动分页拉全量(内部循环 startRow)
const allRows = await gsc.searchAnalyticsAll({
startDate: '2026-08-01',
endDate: '2026-08-21',
dimensions: ['query'],
}, { maxRows: 50_000 })结果固定按 clicks 降序;keys[] 的顺序与请求的 dimensions 一致。
Google Analytics 4
import { createGa4Client, toRowObjects } from '@pang3fan-creator/analytics-kit'
const ga4 = createGa4Client()
const report = await ga4.runReport({
dateRanges: [{ startDate: '29daysAgo', endDate: 'today' }],
dimensions: [{ name: 'country' }],
metrics: [{ name: 'sessions' }, { name: 'activeUsers' }],
returnPropertyQuota: true,
})
// 行转对象:{ country: 'China', sessions: '123', ... }
const rows = toRowObjects(report)
// 自动分页(按 rowCount 循环 offset)
const all = await ga4.runReportAll({
dateRanges: [{ startDate: '90daysAgo', endDate: 'today' }],
dimensions: [{ name: 'pagePath' }],
metrics: [{ name: 'screenPageViews' }],
})GA4 与 GSC 共享同一服务账号凭据时,access token 自动复用缓存:两个客户端默认都以合并后的只读 scopes(webmasters.readonly + analytics.readonly)请求 token,同凭据每小时只换一次。
所有客户端都支持 timeoutMs(毫秒)为每次请求注入超时:
const gsc = createGscClient({ timeoutMs: 30_000 })Bing Webmaster Tools
import { createBingClient } from '@pang3fan-creator/analytics-kit'
const bing = createBingClient() // 自动读环境变量
// 排名与流量(按天,近一个月)
const traffic = await bing.getRankAndTrafficStats()
// [{ date: '2026-08-21', clicks: 16, impressions: 202 }, ...]
// 关键词明细(官方扁平结构:每行一个查询词)
const queries = await bing.getQueryStats()
// [{ query: 'schedule maker', clicks: 15, impressions: 100, avgClickPosition: 18, avgImpressionPosition: 17, date: '2011-09-16' }, ...]
// 页面流量(官方 Query 字段承载页面 URL)
const pages = await bing.getPageStats()Bing 走官方 JSON/HTTP 协议(其 SOAP/POX 协议将于 2026-08-31 退役,本库只使用 JSON 端点)。单个 API Key 可查询账号下所有已验证站点,按 BING_SITE_URL 区分目标站。注意三点:
- 位置字段粒度:
avgClickPosition/avgImpressionPosition与 GSC 的position不同,是 Bing 原始刻度(如18对应 UI 显示的1.8),展示前请自行 ÷10 - 日期格式:微软序列化为
/Date(毫秒数±时区)/,本库已按带时区的本地日历日期归一化为YYYY-MM-DD(不会因 UTC 截断出现跨日偏移) - 日期范围:
GetQueryStats/GetPageStats不支持服务端日期参数,返回全量数据,需要窗口时请客户端过滤 - 误传
sc-domain:形式的站点标识会抛出带说明的AnalyticsKitConfigError
Ahrefs
import { createAhrefsClient } from '@pang3fan-creator/analytics-kit'
const ahrefs = createAhrefsClient() // 自动读环境变量
// 任意域名/URL 的 Domain Rating(0 units,免费)
const dr = await ahrefs.getDomainRating('tanship.app')
console.log(dr.domainRating) // 22
console.log(dr.license) // 署名条款 URL(公开显示时需标注 "Domain Rating by Ahrefs")
// 查看当前 Key 的计划/额度(0 units;公共 Key 会 401,需 Lite+ 计划)
const limits = await ahrefs.getLimitsAndUsage()
console.log(limits.subscription, limits.unitsUsageApiKey, limits.unitsLimitApiKey, limits.usageResetDate)当前覆盖官方免费公开端点;site-audit / keywords-explorer 等订阅端点消耗 API units(50/次起),需要升级到 Lite 及以上后才可用(届时再按需扩展方法)。
Microsoft Clarity
import { createClarityClient } from '@pang3fan-creator/analytics-kit'
const clarity = createClarityClient()
// 官方 Export API:仅最近 1-3 天,10 次/项目/天
const insights = await clarity.getLiveInsights({
numOfDays: 3,
dimensions: ['Device', 'Country/Region'], // 最多 3 个
})
for (const metric of insights) {
console.log(metric.metricName) // 如 "Traffic"、"RageClickCount"
for (const row of metric.rows) {
console.log(row.dimensions) // { Device: 'Mobile', ... }
console.log(row.values) // 计数字符串已转为数字
}
}归一化处理了官方响应的已知陷阱:
- 计数字段是 JSON 字符串 → 已转为 number
- 维度回显键名大小写不稳定(如 URL 回显为
Url)→ 统一映射回请求时的维度名 - 注意:
totalSessionCount包含 bot 会话(totalBotSessionCount),人类会话需自行相减;摩擦类指标没有原始计数,只有发生率与subTotal/sessionsCount - 需要原始结构时改用
getRawLiveInsights()
实验性:会话列表(走未文档化的 clarity.microsoft.com/mcp/recordings/sample 端点,即官方 MCP 服务器所用接口;无 SLA,可能随官方变更失效):
const sessions = await clarity.listSessions({
start: new Date('2026-08-20T00:00:00Z'),
end: new Date('2026-08-21T00:00:00Z'),
sortBy: 'SessionDuration_DESC', // 可选,默认 SessionStart_DESC
count: 100, // 上限 250
filters: {
deviceType: ['Mobile'],
rageClickPresent: true,
deadClickPresent: true,
javascriptErrors: [''],
},
})响应结构未文档化,返回解析后的 JSON 原样值。
关键词难度(哥飞版)
import { createKdClient } from '@pang3fan-creator/analytics-kit'
const kd = createKdClient()
const result = await kd.estimateKeywordDifficulty({
keyword: 'ai photo editor', // 必填,英文关键词
gl: 'us', // 可选,默认 us
hl: 'en', // 可选,默认 en
force: true, // 可选,跳过 7 天结论缓存强制重算
})
result.score // 难度分 0–100(品牌词为「衍生内容进入难度」口径)
result.level // '极易' | '容易' | '中等' | '困难' | '极难'
result.keywordType // 'generic' | 'brand'(自动识别品牌词)
result.reasons // 中文判断原因与各信号加减分明细
result.keywordVolume // 月搜索量(可能为 null)
result.keywordTrend // { domain, volume, estimatedValue, ratio },ratio ≥ 1 表示快速上升期
result.linkBudget // 进入前十的引用域预算:quality / directory 两轨 low/mid/high
result.details // 前十盘面明细:DR、访问量、域名年龄、是否专门经营、体验数据等
// 自包含 Markdown 报告(适合存档 / 转发 / 喂给 AI)
const report = await kd.estimateKeywordDifficultyMarkdown({ keyword: 'ai logo maker' })额度说明:网页 / MCP / HTTP API 三端共用每日额度(游客 10 次、登录用户 100 次、VIP 500 次),另有每分钟 10 次的瞬时保险丝;429 错误体中的 error 字段可区分 rate(触发保险丝)与 quota(日额度用完)。
Cloudflare Workers 中使用
Workers 没有 process.env,创建客户端时显式传配置即可:
export default {
async fetch(request: Request, env: Env) {
const gsc = createGscClient({
siteUrl: env.GSC_SITE_URL,
clientEmail: env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
privateKey: env.GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY,
})
// ...
},
}错误处理
所有失败都抛出统一的 AnalyticsKitError——HTTP 错误、网络失败、超时、外部中断和响应解析失败都不会漏网,调用方只需 instanceof 一种判断:
import { AnalyticsKitError } from '@pang3fan-creator/analytics-kit'
try {
await gsc.searchAnalytics({ ... })
} catch (error) {
if (error instanceof AnalyticsKitError) {
error.platform // 'gsc' | 'ga4' | 'clarity' | 'kd' | 'bing' | 'ahrefs' | 'google-auth'
error.kind // 'http' | 'network' | 'timeout' | 'abort' | 'parse'
error.status // HTTP 状态码(仅 kind === 'http' 时存在)
error.body // 服务端错误体(仅 HTTP 错误)
error.cause // 原始错误(仅非 HTTP 错误)
}
}已知边界:本库不做自动重试/退避(由调用方决定策略)、不对响应做运行时 schema 校验(类型安全覆盖输入与文档化契约);配置类问题抛 AnalyticsKitConfigError。
平台限制速查
| 限制 | GSC | GA4 | Clarity | 关键词难度(哥飞版) | Bing | Ahrefs | |---|---|---|---|---|---|---| | 单请求行数上限 | 25,000 | 250,000 | 1,000(不可分页) | 单关键词一次查询 | 近月按天聚合,无分行参数 | 单域名 DR 一次查询 | | 数据窗口 | 16 个月 | 视属性配置 | 仅最近 3 天 | 实时计算 + 7 天结论缓存 | 约一个月(按天) | 实时 | | 频率限制 | 1,200 QPM/站点 | 按 token 配额(标准属性约 200k tokens/天) | 10 次/天/项目 | 三端共享日额度(游客 10 / 登录 100 / VIP 500)+ 10 次/分钟 | 官方未公开限额(宽松) | 免费公开端点 0 units,无公布限额 | | 数据延迟 | 2–3 天 | 数小时–1 天 | 数小时 | 实时 | 4–5 天 | 实时 |
GA4 注意:单请求最多返回 250,000 行;runReportAll 通过 offset 深翻页拉取更大结果集时,官方服务端在大 offset 下可能出现不稳定或超时,建议用 maxRows 控制总量或缩小维度基数。
Clarity 官方 API 只覆盖近 72 小时且每天仅 10 次调用——若需历史留存,请在业务侧定时调用并将结果持久化到自己的存储。
开发
pnpm test # vitest 单测(全部 mock fetch,不发真实网络请求)
pnpm typecheck # tsc --noEmit
pnpm build # tsdown 构建 dist/发布:npm publish(需先登录 npm 账号 pang3fan-creator;prepublishOnly 钩子会自动跑 typecheck + test + build)。接入真实凭据的冒烟验证建议在各业务项目中进行。
