# @dxv-systems/metis-client 中文文档

规范地址：https://npmcn.com/package/%40dxv-systems/metis-client/

版本：0\.16\.1
npm 元数据更新时间：2026-11-09T19:46:55.462Z
中文译文更新时间：2026-11-13T02:07:24.818Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40dxv-systems/metis-client
原文对照：https://npmcn.com/package/%40dxv-systems/metis-client/?lang=original
项目主页：https://github.com/dxv-systems/dxv-packages#readme
源码仓库：https://github.com/dxv-systems/dxv-packages

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：61.6 kB，24 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=24\.0\.0
- 运行依赖：0 个
- 首次发布：2026-09-06T10:06:03.900Z
- 最新版本发布：2026-11-09T19:46:55.264Z
- 近 30 天下载量：5295（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

第十五届 Metis 转换跟踪 SDK — 点击ID 捕获和签名转换事件排放

## 安装

```sh
npm install @dxv-systems/metis-client
```

也可以使用：`pnpm add @dxv-systems/metis-client`、`yarn add @dxv-systems/metis-client`、`bun add @dxv-systems/metis-client`

## README

# @dxv-systems/metis-客户端

DXV Metis转换跟踪SDK. 抓取点击 ID (`gclid`, (中文(简体) ), `fbclid`, (中文(简体) ), `gbraid`, (中文(简体) ), `wbraid`, (中文(简体) ), `utm_*`)在登陆和向 DXV Metis 中继端点发送签名的服务器侧转换事件时.

> 发表于 `@dxv-systems/conversions` 最高为0.3.0. 该名称被贬值;API是相同的,只有包名被更改了.

## 安装

```bash
npm install @dxv-systems/metis-client
```

## 上岗

当您的 Metis 账户建立后, DXV 给出三个值:

-   `customerId` — 整数, 在梅蒂斯识别客户记录
-   `relaySecret` - HMAC 签名密钥(作为证书处理)
-   `relayUrl` - 典型的梅蒂斯端点基座 `https://metis.dxvagentic.com` (较老的) `https://marketing.dxvagentic.com` 也还在工作)

在您的 Webshop 的部署中将这些存储为环境变量 。 以下实例 `DXV_CUSTOMER_ID`, (中文(简体) ), `DXV_CONVERSIONS_RELAY_SECRET` 财务报告和审定财务报表 `DXV_CONVERSIONS_RELAY_URL`。此软件包本身不读取:您将值传递到其中.

## 客户端: 着陆时点击ID

在您的登陆页面处理器(Next.js中件、Express处理器,任何地方):

```ts
import { CLICK_IDS_COOKIE, captureClickIds, parseClickIdsCookie, serializeClickIdsCookie } from "@dxv-systems/metis-client/client";

// On every request to a public page:
const url = new URL(request.url);
const captured = captureClickIds(url.searchParams);

if (captured) {
  // First-touch wins: don't overwrite an existing valid cookie.
  const existing = parseClickIdsCookie(request.cookies.get(CLICK_IDS_COOKIE)?.value);
  if (!existing) {
    response.cookies.set(CLICK_IDS_COOKIE, serializeClickIdsCookie(captured), {
      maxAge: 30 * 24 * 60 * 60, // 30 days
      httpOnly: false,           // intentionally readable from client (analytics)
      sameSite: "lax",
      secure: true,
    });
  }
}
```

`CLICK_IDS_COOKIE` (单位:千美元)`"dxv_click_ids"`从两者中导出) `/client` 财务报告和审定财务报表 `/server`,所以应用不再重复饼干名称. 饼干在0.7.0前写作(无 `gbraid`编号 :`wbraid`仍作解说.

### Cookie 编码

`parseClickIdsCookie` 以任何你碰巧持有的形式持有的值 : 原始 %- 编码字符串 `Cookie` 页眉, 或已解码 字符串框架 cookie API 返回 。 你不必知道自己有哪个.

这在实践中很重要. `next/headers` `cookies()` 财务报告和审定财务报表 `NextRequest.cookies.get()` 解码信头本身,同时 `NextResponse.cookies.set()` **编码** 你给它,所以一个饼干写 通过中间软件,在 `serializeClickIdsCookie`自己的编码,是 存储了双编码。 包含正文的值 `%` 联合国 `utm_campaign` 联 合 国 `50%-korting`仍然正确分析各种形式.

## 服务器侧: 发送购买事件

在您的订单中完成的处理器( Stripe webhook等) :

```ts
import { emitPurchase } from "@dxv-systems/metis-client/server";
import { parseClickIdsCookie } from "@dxv-systems/metis-client/client";

await emitPurchase({
  customerId: Number(process.env.DXV_CUSTOMER_ID),
  relaySecret: process.env.DXV_CONVERSIONS_RELAY_SECRET!,
  relayUrl: process.env.DXV_CONVERSIONS_RELAY_URL!,
  eventId: order.id,   // optional; see "Deduping with a browser pixel" below
  order: {
    id: order.id,
    totalCents: order.totalCents,
    currency: "EUR",
  },
  clickIds: parseClickIdsCookie(cookies.get(CLICK_IDS_COOKIE)),
  customer: {
    email: order.customer.email,    // plaintext; package hashes per Meta CAPI spec
    phone: order.customer.phone,
  },
  consent: {
    adUserData: consentState.adUserData,
    adPersonalization: consentState.adPersonalization,
  },
});
```

`emitPurchase` 在5xx上重复3次 以指数回放。 它扔出输入错误 :

-   `InvalidConfigError` ——失踪/空 `relaySecret`, (中文(简体) ), `relayUrl`,或 `customerId`,或无效字段。 在任何网络通话前被丢弃.
-   `RelayBadRequestError` - Metis 返回 4xx( 可能是 stale ) `relaySecret` 或错 `customerId`) (中文(简体) ). 未复审.
-   `RelayUnavailableError` ——梅蒂斯3次尝试后无法接触.

## 服务器侧: 发送线索事件

对于格式填充/ 注册转换, 没有附加命令( 引号请求、 联系表、 演示预订) :

```ts
import { emitLead } from "@dxv-systems/metis-client/server";
import { parseClickIdsCookie } from "@dxv-systems/metis-client/client";

await emitLead({
  customerId: Number(process.env.DXV_CUSTOMER_ID),
  relaySecret: process.env.DXV_CONVERSIONS_RELAY_SECRET!,
  relayUrl: process.env.DXV_CONVERSIONS_RELAY_URL!,
  eventId: submission.id,   // optional; see "Deduping with a browser pixel" below
  lead: {
    id: submission.id,
    valueCents: 0,   // optional; omit if the lead has no estimated value
    currency: "EUR", // optional; only meaningful alongside valueCents
  },
  clickIds: parseClickIdsCookie(cookies.get(CLICK_IDS_COOKIE)),
  customer: {
    email: submission.email,
    phone: submission.phone,
  },
});
```

`emitLead` 共享配置验证、 PII 散列、 签名和重试行为 `emitPurchase` ——同打出错误,同打出5xx重试/4xx-脂肪规则. 只有输入形状不同: `lead` (无) `order`),以及 `lead.id` 是唯一需要的字段.

Metis存储了主导事件,并征得同意后将其转发至购买等广告平台.

### 工作应用程序 : `lead.kind` (0.15.0) (中文(简体) )

一个职业页面发送一个工作应用程序作为线索 `kind: "application"`数字 :

```ts
await emitLead({ /* ... */, lead: { id: application.id, kind: "application" } });
```

梅蒂斯计算申请,除了询问和 **从不转发** 给Meta、Google或Pinterest,不管访客同意什么:一个向申请人传授的广告平台找到申请人而不是客户。 它没有为它们提供散列识别器. `kind: "lead"` 这跟不说一样 任何其它值抛出 `InvalidConfigError` 在发送任何信息之前 需要知道球场的Metis(2026年10月后);一个更老的球会忽略了它.

## 服务器侧: 发送漏斗步骤( 0. 0.0)

`emitFunnelEvent({ event: "view_content" | "add_to_cart" | "initiate_checkout", eventId, funnel?: { valueCents?, currency?, items?: [{ id, quantity, priceCents? }] }, clickIds, customer, consent, context })` metis只向Meta 报告浏览步骤. `eventId` 需要:通过浏览器像素所用的一个,所以Meta去除它们. 只有在双方同意的信号都是真实的且访客决定的情况下,梅蒂斯才保留该步骤,从不算作转换. `context.actionSource` 也许只有 `website`使用的大多数场地 `@dxv-systems/measurement`是因为 `funnelRouteHandler` 换句话说.

## 博茨和应用程序提示 (0.16.0)

`isBotUserAgent(userAgent)` 财务报告和审定财务报表 `BOT_USER_AGENT_TOKENS` (从) `./server`) 名称已知bots, crawers, 链接预览器, 无头浏览器和脚本 HTTP 客户端(Googlebot, AdsBot, bingbot, facebook externalhit, Headless Chrome, 卷曲, wget, python- requests and more), 匹配为小写子串. 只有明确的名字:一个赤裸的"机器人"也会匹配真实的手机. 缺席不是机器人. `@dxv-systems/measurement` 在发送前从这些漏斗步骤中去掉,而梅蒂斯使用相同的列表再次以摄取的方式去掉. 采购和线索从不过滤.

每一次发射,和 `fetchConsentPlatforms`选项 `appId` (应用程序的ID在梅蒂斯, 一个正整数, 否则 `InvalidConfigError`) (中文(简体) ). 发件人: `X-DXV-App-Id`,所以Metis先尝试该应用程序的秘密,而不是每个组织的秘密(或者,为了 `consent-platforms` 无 `customerId`每个应用程序。 这只是个提示:签名仍然为应用程序取名,没有标题的Metis忽略了它.

Metis每分钟限制每个app的接力事件(600个漏斗台阶,120个购买和线索). 超过极限,它回答 429,这是一个 `RelayBadRequestError` 而不复试.

## 更多匹配密钥 (0. 14. 0)

`customer` 还要 `externalId` (店主的客户或领导身份), `firstName`, (中文(简体) ), `lastName`, (中文(简体) ), `city`, (中文(简体) ), `postalCode` 财务报告和审定财务报表 `country` (ISO 3166-1 alpha-2,例如:. `"NL"`),所有可选和简写. 他们像电子邮件一样,是正常的,是散发的:

| 外地 | 发送为 | 正常化为 |
| --- | --- | --- |
| `externalId` | `externalIdSha256` | 已修剪, 案件保存( 标识不透明) |
| `firstName`, (中文(简体) ), `lastName` | `firstNameSha256`, (中文(简体) ), `lastNameSha256` | NFC,小写,无平分,单内空格("Jean-Luc" →) `jeanluc`,"Zoë" – (中文(简体) ) `zoë`(中文(简体) ) |
| `city` | `citySha256` | 小写字母和数字,重音会下降(''s-Hertogenbosch' →) `shertogenbosch`(中文(简体) ) |
| `postalCode` | `postalCodeSha256` | 小写,没有空格或破折号(“1234 AB”) − `1234ab`); 一个美国代码保留了5个数字 |
| `country` | `countrySha256` | 小写 α-2 (`nl`(中文(简体) ) |
| `postalCode`, (中文(简体) ), `country` | `postalCode`, (中文(简体) ), `countryCode`, (中文(简体) ), **简单** | 修剪后, 大写`1234 AB`, (中文(简体) ), `NL`(中文(简体) ) |

平原对之所以存在,是因为Google的"数据管理器"取了一个地址的邮政和地区代码未覆盖(只有名称被散列). 一个空地,或者一个不是两个字母的国家,被排除在外,从不作为空字符串而散去. IP 和用户代理端保持无阴影 `context`和以前一样.

梅蒂斯寄给Meta(`external_id`, (中文(简体) ), `fn`, (中文(简体) ), `ln`, (中文(简体) ), `ct`, (中文(简体) ), `zp`, (中文(简体) ), `country`),将Google作为地址(黑名、平原地区和邮政编码)和Pinterest(`external_id`, (中文(简体) ), `fn`, (中文(简体) ), `ln`, (中文(简体) ), `ct`, (中文(简体) ), `zp`, (中文(简体) ), `country`),每个都只有在访客同意的情况下,如电子邮件. **需要了解字段的梅蒂斯版本**:一个更年长的人接受尸体并放下.

`captureClickIds` 还抓取 `ttclid` (TikTok语), `msclkid` (微软)和 `epik` (兴趣)进入相同的先触 `dxv_click_ids` 饼干,和 `detectPaidTouch` 算作付费点击。 Metis 向前移动 `epik` 利息; `ttclid` 财务报告和审定财务报表 `msclkid` 是为后来的转发者保存的.

## 同意

两者 `emitPurchase` 财务报告和审定财务报表 `emitLead` 接受选项 `consent` 字段 :

```ts
consent: {
  adUserData: boolean;        // Google Consent Mode v2 "ad_user_data"
  adPersonalization: boolean; // Google Consent Mode v2 "ad_personalization"
  decided?: boolean;          // has the visitor answered the banner? absent = yes
  platforms?: ("google" | "meta" | "pinterest")[]; // what the banner named (0.13.0); absent = not recorded
}
```

**在实践中,这不是可选的.** Metis 存储每个事件, 不管怎样, 但是它的 Meta CAPI / Google 离线转换转发器失败了 关闭: 一个没有连接到的事件 `consent` 对象从不转发,只存储。 如果你想让转换实际到达Meta或Google,就必须通过 `consent` 从您的商店前端已经运行的 同意管理平台( CMP, 饼干横幅, 自己的首选店) 读取. `adUserData` 财务报告和审定财务报表 `adPersonalization` 当对象存在时需要; 没有部分形式.

### 还没回答的访客

`decided` (加到0.7.0)让梅蒂斯告诉一个从未回答过的人拒绝的访客. 缺席意味着决定的,所以现有的发送者保持其意义. 当来访者尚未回答旗帜时,请发:

```ts
consent: { adUserData: false, adPersonalization: false, decided: false }
```

这与其它任何未同意的情况一样, 奥米 `consent` 完全只有当你的融合没有任何同意信息时; Metis报告作为一个发送漏洞,这与"未决定"不同. `decided` 一定是一个布尔当场.

### 游客同意的平台(0.13.0)

`consent.platforms` 列出访问者回答时命名的横幅的广告平台; Metis只转发给那些。 名字来自 `CONSENT_PLATFORMS` (单位:千美元)`google`, (中文(简体) ), `meta`, (中文(简体) ), `pinterest`从 `/client` 财务报告和审定财务报表 `/server`),每个最多一次;任何其他投出 `InvalidConfigError`。当旗帜没有记录一个列表时,将其删除.

## 服务器侧: 询问 Metis 哪些平台的横幅名称 (0. 13. 0)

```ts
import { fetchConsentPlatforms } from "@dxv-systems/metis-client/server";

const answer = await fetchConsentPlatforms({ relayUrl, relaySecret, customerId });
// { platforms: ["google", "meta"], version: "3f2a9c1b7d4e" } or null
```

它发出 `GET {relayUrl}/api/relay/v1/consent-platforms?customerId={customerId}`,以中继 POST 形式在空出的身体上签名: `X-DXV-Signature` 是HMAC-SHA256的六分位数 `` `${timestamp}.` `` 带着接力的秘密, `X-DXV-Timestamp` 同样的毫秒印出. `customerId` 是可选的;没有它,Metis会尝试针对每个活动应用程序的秘密. 它从未丢出: 任何失败( 网络、 默认3 s 的超时、 非-2xx 、 错误的答案) 返回 `null`。删除未知的平台名称。 选项 : `fetchImpl`, (中文(简体) ), `timeoutMs`使用的大多数场地 `@dxv-systems/measurement`是因为 `consentPlatformsHandler` 相反,它会缓存答案 并回到每个平台.

## 付费触摸旗

`detectPaidTouch(input)` (从) `/client` 或者说 `/server`,在0.8.0中添加)返回 `true` 当一个着陆URL说访问来自一个广告:任何 `gclid`, (中文(简体) ), `fbclid`, (中文(简体) ), `gbraid` 或者说 `wbraid` 有并非空地,或 `utm_medium` (trimmed, case- 不敏感) 是其中之一 `cpc`, (中文(简体) ), `ppc`, (中文(简体) ), `cpm`, (中文(简体) ), `cpv`, (中文(简体) ), `paid`, (中文(简体) ), `paidsocial`, (中文(简体) ), `paid_social`, (中文(简体) ), `paid-social`, (中文(简体) ), `paidsearch`, (中文(简体) ), `paid_search`, (中文(简体) ), `paid-search`, (中文(简体) ), `display`它接受 `URLSearchParams`、查询字符串、完整 URL 字符串或 `URL`。 。 。 .

```ts
import { detectPaidTouch } from "@dxv-systems/metis-client/client";

const paidTouch = detectPaidTouch(window.location.search); // keep in a variable
await emitLead({ /* ... */, paidTouch });
```

两者 `emitPurchase` 财务报告和审定财务报表 `emitLead` 接受选项 `paidTouch: boolean`,作为顶级域发送。 Metis的同意监视器将它算作将被拒绝和未决定的访客分为付费和有机;它从未被转发给Meta或Google. 当您不知道时( 缺席意味着未知) , 把它放出来 。 它一定是一个布尔当场.

**将结果保存在记忆中.** 永远不要写到饼干,本地Storage或任何其他存储器上:那是未经同意的设备存储. 完全重装或回访应当给出"未知"(omt the flag),而不是猜测.

## 用浏览器像素编程

如果你的站点 _(单位:千美元)_ 从浏览器中报告此转换( a Meta 像素) `Purchase`编号 :`Lead` 事件, a `gtag` 转换事件),通过相同 `eventId` 对像素调用和 `emitPurchase`编号 :`emitLead`. Meta和Google通过匹配事件名称外加共享事件ID来对服务器事件去除浏览器事件——没有它,一旦Metis开始转发服务器事件后,双方报告的转换就会被计算出两次.

`eventId` 是可选的 —— 如果您没有用于此转换的浏览器边对应器, 请省略 。 当提供时, 它必须是最多为 256 个字符的非空字符串( 只拒绝空白字符串 ) ; 使用您在像素和服务器呼叫( a) 之间已经共享的 ID `nanoid`,命令参考,UUID).

### 设计可复制的事件 ID

如果您的浏览器像素和服务器侧放出不共享进程状态—— 常见的情况, 因为像素在确认页面上起火, 服务器在稍后从 Webhook 中放出火来, 您需要一种方法来获取 _不变_ 在两边从他们都已经知道的东西, 像顺序号:

```ts
import { purchaseEventUuid } from "@dxv-systems/metis-client/client"; // or /server

const eventId = purchaseEventUuid(order.number);
// Pass this to both the pixel call (fbq('track', 'Purchase', {}, { eventID: eventId })
// or posthog.capture(..., { uuid: eventId })) and to emitPurchase's `eventId` field.
```

`purchaseEventUuid` 以及更普遍的 `deterministicEventUuid` 纯函数 **两者** `/client` 财务报告和审定财务报表 `/server` ——浏览器需要一台来计算其像素调用时的ID,服务器需要相同的功能来在后期为中继放出时重算出同一种ID,而无需两者协调. 定点论是整点:一个随机的每事id在事实发生后无法被复制,而Meta/PostHog通过匹配该id来对准它的浏览器对应器来去dupe一个服务器事件——把它弄错了,并且每一个转发的转换双数,沉默地.

输出还被塑造为有效的 RFC-4122 uuid 而不是像可读字符串 `purchase:ORD-0001`,因为这个链条中的几个平台(PostHog including)只接受一个有效的uuid作为事件id,并且静悄悄地以一个随机的交换,否则——再次没有出错,只是一个悄悄地停止工作的解脱.

用于铅转换 `leadEventUuid(lead.id)` 相同方式(等于 `deterministicEventUuid("lead:" + lead.id)`),所以是一个浏览器 `Lead` 像素和 `emitLead` 共享一个事件 id.

**双方必须使用它,否则解脱无效.** 如果您的存储前缀的像素以一个方式获得其id,而服务器则从另一个方式(或者一方使用随机的ID)获得,Meta/PostHog无法告诉这两个事件是相同的转换,一旦Metis向上转发服务器边事件,就会得到两次计数.

## 公约

-   钱入一分钱(一分). Metis 验证 `totalCents > 0`。 。 。 .
-   货币作为ISO 4217(例如. `EUR`, (中文(简体) ), `USD`) (中文(简体) ).
-   PII(电子邮件、电话、外部身份证、姓名、城市、邮政编码、国家) **记忆中的散列** 网络调用前; 纯文本从不退出进程, 但邮政和国家代码 Google 采取平原 (0. 14.0) 。 Metis只将散列保留在它可能转发的一行(同意,或经认证的下线销售)上,一旦不再可能,即可清除.
-   电话在已知国家时被两次散开(`+31…`, (中文(简体) ), `0031…`,或 `phoneCountryCode: "31"`: `phoneSha256` 作为国家代码(Meta)和 `phoneE164Sha256` 与 `+` (谷歌声). 没有国家,只有数字 `phoneSha256` 和以前一样发送.
-   `phoneE164(phone, countryCode?)` 财务报告和审定财务报表 `phoneWithCountryCode` 从 `./client` 也 (0. 12. 0) , 因此浏览器可以像服务器那样将手机格式化 .
-   Gmail 或 Google 邮件地址, 日期之前有点 `@` 也作两次散列( 0.11.0 ): `emailSha256` 已键入( Meta) 和 `emailGoogleSha256` 没有点(Google 匹配它那样). 任何其他地址发送 `emailSha256` 只有这个.
-   `context` (0.9.0) 携带客户端IP,用户代理,页面 URL和 `actionSource` (单位:千美元)`website`,或 `phone_call` 编号 : `email` 编号 : `chat` 编号 : `physical_store` 编号 : `other` 销售人员进入). `clickIds` 可能携带Meta的 `_fbc` 编号 : `_fbp` 饼干作为 `fbc` 编号 : `fbp`。 。 。 .
-   点击ID cookie 是 **先触后取胜** 如果一个有效的饼干已经存在, 请不要覆盖 .

## 许可证

麻省理工学院

## 常见问题

### @dxv-systems/metis-client 是什么？

第十五届 Metis 转换跟踪 SDK — 点击ID 捕获和签名转换事件排放

### 如何安装 @dxv-systems/metis-client？

在项目目录运行 npm install @dxv-systems/metis-client，或使用 pnpm add / yarn add / bun add。

### @dxv-systems/metis-client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @dxv-systems/metis-client 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @dxv-systems/metis-client 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=24\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @dxv-systems/metis-client 可以商用吗？

@dxv-systems/metis-client 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @dxv-systems/metis-client 的下载量有多少？

根据 npm 官方下载统计，@dxv-systems/metis-client 在 2026/10/13 – 2026/11/11 这 30 天内被下载 5,295 次，日均约 177 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @dxv-systems/metis-client 还在维护吗？

最新版本 0\.16\.1 发布于 2026/11/10（3 天前）；至今共发布 15 个版本，其中过去 12 个月发布了 15 个；首次发布于 2026/09/06。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

