@dxv-systems/metis-客户端
DXV Metis转换跟踪SDK. 抓取点击 ID (gclid, (中文(简体) ), fbclid, (中文(简体) ), gbraid, (中文(简体) ), wbraid, (中文(简体) ), utm_*)在登陆和向 DXV Metis 中继端点发送签名的服务器侧转换事件时.
发表于
@dxv-systems/conversions最高为0.3.0. 该名称被贬值;API是相同的,只有包名被更改了.
安装
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处理器,任何地方):
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等) :
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次尝试后无法接触.
服务器侧: 发送线索事件
对于格式填充/ 注册转换, 没有附加命令( 引号请求、 联系表、 演示预订) :
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"数字 :
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 字段 :
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)让梅蒂斯告诉一个从未回答过的人拒绝的访客. 缺席意味着决定的,所以现有的发送者保持其意义. 当来访者尚未回答旗帜时,请发:
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)
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。 。 。 .
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 中放出火来, 您需要一种方法来获取 不变 在两边从他们都已经知道的东西, 像顺序号:
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 是 先触后取胜 如果一个有效的饼干已经存在, 请不要覆盖 .
许可证
麻省理工学院