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

@clipto/traffic-source

v0.3.0

Published

Shared traffic-source attribution format for Clipto sites and webhooks

Readme

@clipto/traffic-source

用于生成与解析流量来源的 TypeScript 包,供不同站点及服务共享同一数据格式。提供来源 ID、URL 渠道识别、渠道历史和复合来源的构建与解析;不依赖站点框架、Cookie、支付 SDK 或上报协议。由调用方决定何时采集、存储和上报来源。

安装

pnpm add @clipto/traffic-source

快速开始

import {
  buildSourceId,
  buildTrafficSource,
  parseTrafficSourceWithFallback,
  classifyTrafficChannel,
} from "@clipto/traffic-source";

const firstTouch = buildSourceId({
  payment: "stripe",
  product: "web",
  businessType: "trans",
  channelType: "seo",
});

const trafficSource = buildTrafficSource({
  firstTouch,
  checkout: "stripe-web-trans-semgoogle-meeting",
  history: "seo_semgoogle",
});

const result = parseTrafficSourceWithFallback(trafficSource);
const checkout = result.slots.checkout;
if (checkout.source) {
  const classification = classifyTrafficChannel(checkout.source.channelType);
  console.log(classification.category);
}

trafficSource 的值为 stripe-web-trans-seo/stripe-web-trans-semgoogle-meeting//seo_semgoogle。四槽依次表示首次落地、本次下单、套餐变更和渠道历史集合;新购时第三槽为空正常,第四槽不是完整访问时间线。单条来源 ID 字符串格式仍为 payment-product-business-channel[-scene],对象字段为 payment/product/businessType/channelType/creative?。

来源 ID

| 函数 | 参数 | 返回及用途 | | --------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | buildSourceId(info, onInvalid?) | info 包含必填的 payment、product、businessType、channelType 和可选 creative;回调接收新字段名数组 | 转小写、去首尾空格后生成来源 ID;无效时返回 "",可通过回调获知无效字段。前四段不能包含 - 或 /,creative 可包含 -,不能包含 /。 | | parseSourceId(raw) | 单条来源 ID 字符串 | 严格返回 { payment, product, businessType, channelType, creative? };不能解析时返回 null。creative 中多余的连字符原样保留。 |

payment、product 和 businessType 由接入方定义;SDK 不限定支付平台、产品和业务值。第五段 creative 只是既有字段改名,历史值可能来自页面场景或 adid,不保证是广告素材 ID。

URL 与渠道

| 函数或常量 | 参数 | 返回及用途 | | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | getChannelFromUrl(targetUrl) | 完整 URL 字符串或 URL 对象 | 只读取当前 URL 的参数,按内置优先级返回渠道编码;无匹配时返回 "seo",不读取 Cookie。 | | generateSourceIdFromUrl(targetUrl, options) | 完整 URL 字符串;options 必须提供 payment、product、resolveBusinessType(pathname),可提供 resolveCreative(pathname, params)、channelType、onInvalid | 使用 URL 渠道规则及调用方提供的业务/场景映射生成来源 ID。传入 channelType 时跳过默认渠道识别;字段无效时返回 ""。 | | generateChannelHistory(targetUrl, trafficHistory, trafficSource, newTrafficSource) | 当前 URL、已有历史字符串、首次来源 ID、本次来源 ID | 返回下划线分隔的渠道历史;优先选本次、首次或 URL 中的 SEM,将选中渠道去重后放在末尾。它不是完整访问时间线。 | | isPaidChannel(channel?) | 渠道编码 | 返回布尔值;现有规则把 SEM、kol 前缀、affiliate、ambassador 视为付费,其他值返回 false。此旧判断不等于“已知渠道分类”。 | | TrafficChannel、SEM_CHANNELS | 无 | 现有渠道编码常量;新渠道可能未收录,请勿将它们当作封闭的产品枚举。 |

import {
  generateSourceIdFromUrl,
  getChannelFromUrl,
} from "@clipto/traffic-source";

const url = "https://example.com/meeting?gclid=click&adid=730736096338";
getChannelFromUrl(url);

generateSourceIdFromUrl(url, {
  payment: "stripe",
  product: "web",
  resolveBusinessType: (pathname) =>
    pathname.includes("meeting") ? "trans" : "home",
  resolveCreative: (_pathname, params) => params.get("adid") ?? "",
});

上述调用分别返回 "semgoogle" 和 "stripe-web-trans-semgoogle-730736096338"。URL 渠道识别覆盖指定 banner、KOL、referral、SEM 来源/点击参数、ambassador、affiliate,最后回退到 seo;URL 路径如何映射到业务及场景仍由接入方决定。

复合来源

| 函数 | 参数 | 返回及用途 | | -------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | buildTrafficSource(parts) | firstTouch、checkout 必填;planChange、history 可选 | 按 firstTouch/checkout/planChange/history 生成四槽字符串,保留空槽。 | | parseTrafficSource(raw) | 复合来源字符串 | 返回原文、四槽原始值、sources(前三槽的严格解析对象或 null)、status(complete/legacy/invalid)和 sourceStatus(valid/partial/invalid)。不抛解析异常。 | | parseTrafficSourceWithFallback(raw, fallbackCheckout?) | 复合来源字符串、可选的独立下单来源 ID | 保留 parseTrafficSource 的全部原始字段,另加 slots.firstTouch/checkout/planChange:每槽有 raw、source、status、origin。仅原第二槽为空时采用独立 ID,不修改原复合字符串或顶层 sources。 | | updateTrafficSource(raw, planChange, history) | 旧复合串、新第三槽来源 ID、新第四槽渠道历史 | 更新第三、第四槽;旧串不足四槽时补空,不校验或修复已有内容。 |

每个 slots.*.status 为 "valid" | "missing" | "invalid",origin 为 "composite" | "fallback" | "none"。例如历史数据只有第一槽:

import { parseTrafficSourceWithFallback } from "@clipto/traffic-source";

const result = parseTrafficSourceWithFallback(
  "stripe-web-home-seo",
  "stripe-web-trans-semgoogle-meeting",
);

result.status;
result.checkout;
result.slots.checkout;

这三个表达式依次得到 "legacy"、"" 和 { raw: "stripe-web-trans-semgoogle-meeting", source: { payment: "stripe", product: "web", businessType: "trans", channelType: "semgoogle", creative: "meeting" }, status: "valid", origin: "fallback" }。若第二槽有非空但非法的值,不会回退;第一槽和第三槽也不会用别的槽冒充。status 只表示槽位结构,不保证每个 sources.* 有效;消费某槽请检查其 sources.* !== null 或 slots.*.status === "valid"。

公共分类

| 函数 | 参数 | 返回及用途 | | ------------------------------------ | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | classifyTrafficChannel(channel) | 单个渠道编码,例如 "semgoogle" | 返回 { channel, category, name }。已知 SEM/KOL 等编码映射为渠道类别和标准化名称;未知或动态值保留原值,返回 category: "unknown"、name: null。 | | classifyPlanChangeChannel(channel) | 第三槽已解析来源的 channelType 值,不是完整来源 ID | 返回 { channel, category },类别为 upgrade_reason、traffic_channel 或 unknown。五个已知升级标签是 3file、30min、downloader、starter、free;不限制第三槽只使用它们。 |

import {
  classifyPlanChangeChannel,
  classifyTrafficChannel,
} from "@clipto/traffic-source";

classifyTrafficChannel("semgoogle");
classifyTrafficChannel("new-campaign");
classifyPlanChangeChannel("downloader");

以上依次返回 { channel: "semgoogle", category: "SEM", name: "Google 付费投放" }、{ channel: "new-campaign", category: "unknown", name: null } 和 { channel: "downloader", category: "upgrade_reason" }。同一个 downloader 在普通渠道语境可能是 banner;升级标签不能反推唯一入口。来源 ID 也不能反推原始 UTM、campaign、adGroup;creative 的历史值可能来自页面场景或 adid,不能据此推断广告素材 ID。

旧数据兼容

| 函数 | 参数 | 返回及用途 | | -------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------ | | parseLegacySourceId(raw) | 旧版单条来源字符串 | 仅供旧调用方:空值返回空字段对象,少于四段时抛错,超过五段时忽略多余段;新接入应使用 parseSourceId。 | | isLegacySourceId(raw) | 单条来源字符串 | 仅按 - 分割后的段数是否为 4~5 段返回布尔值,不代表严格格式有效。 |

更完整的输入/返回样例和渠道优先级见仓库中的 docs/api/traffic-source-contract.md(此目录不随 npm 包发布)。