server-side-conversion-tracking

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Server-Side Conversion Tracking

服务器端转化跟踪

Browser pixels lose a large and unpredictable share of conversions to iOS tracking prevention, ad blockers, cookie lifetime limits and cross-domain hops. Server-side reporting fixes the reporting, which is what the ad platform's bidding model learns from. This skill covers the model, the setup order and how to verify it.
浏览器像素会因iOS跟踪限制、广告拦截器、Cookie生命周期限制和跨域跳转而丢失大量不可预测的转化数据。服务器端报告可修复这一报告问题,而报告数据正是广告平台竞价模型的学习依据。本技能涵盖了该模型、搭建顺序以及验证方法。

When to use

适用场景

  • Ad platform reports fewer purchases than the store/database actually recorded
  • CPA looks like it got worse right after a tracking change, with no change in real sales
  • Setting up a new funnel that will receive paid traffic
  • Asked about CAPI / Events API / offline conversion import / click id passthrough
  • Attribution disagreements between platforms ("Facebook claims 40 sales, Google claims 30, we had 45 orders")
  • 广告平台报告的购买量低于店铺/数据库实际记录的数量
  • 跟踪变更后,CPA(单次转化成本)看似变差,但实际销售额并未变化
  • 搭建将接收付费流量的新转化漏斗
  • 涉及CAPI/Events API/离线转化导入/Click ID透传的相关需求
  • 各平台间归因存在分歧(如“Facebook报告40笔销售,Google报告30笔,而我们实际有45笔订单”)

The model, in the order it must be built

必须按顺序搭建的模型

Getting this order wrong is the usual reason a "server-side setup" still under-reports.
1. Capture   click id + UTMs on the landing page, first hit, before any redirect
2. Persist   attach them to the visitor's session, server-side
3. Carry     keep them across every funnel step, including cross-domain hops
4. Attach    write them onto the order record at purchase
5. Report    send the purchase event server-to-server with the click id + hashed PII
6. Dedupe    give the browser event and the server event the same event id
7. Verify    compare platform-reported conversions against your own order table
Skipping step 1-4 and only doing step 5 produces server events with no click id, which the platforms then have to match on hashed email alone - that is materially worse matching, and it is the most common failure in a "we already do CAPI" setup.
搭建顺序错误是导致“服务器端配置”仍存在报告不足问题的常见原因。
1. 捕获   在着陆页首次访问时(重定向之前)捕获Click ID和UTM参数
2. 持久化   将这些参数与访问者的会话关联,存储在服务器端
3. 传递   在转化漏斗的每一步中保留这些参数,包括跨域跳转
4. 关联   在下单时将这些参数写入订单记录
5. 上报   通过服务器到服务器的方式发送包含Click ID和哈希化PII的购买事件
6. 去重   为浏览器事件和服务器事件设置相同的事件ID
7. 验证   将平台报告的转化数据与自身订单表进行对比
跳过步骤1-4仅执行步骤5会导致服务器事件缺少Click ID,此时平台只能仅通过哈希化邮箱进行匹配——这种匹配效果明显更差,也是“我们已使用CAPI”配置中最常见的失败原因。

Step 1-2: capture and persist

步骤1-2:捕获与持久化

PlatformClick id parameter
Facebook / Instagram
fbclid
TikTok
ttclid
Google Ads
gclid
(also
wbraid
/
gbraid
on iOS app-to-web)
Microsoft / Bing
msclkid
Also capture, on the same first hit:
utm_source
,
utm_medium
,
utm_campaign
,
utm_content
,
utm_term
, the full landing URL, referrer, user agent, and the client IP as seen by the server. Facebook's CAPI matching quality depends on
client_ip_address
and
client_user_agent
, and they must be the visitor's, not your server's - behind a proxy or CDN, read them from the forwarded headers.
Store server-side, keyed to a first-party session. Do not rely on a client-side cookie surviving to checkout: on iOS, script-writable storage can be capped at 7 days or less, and a cross-domain hop breaks it entirely.
平台Click ID参数
Facebook / Instagram
fbclid
TikTok
ttclid
Google Ads
gclid
(iOS应用跳转网页时还包括
wbraid
/
gbraid
Microsoft / Bing
msclkid
同时在首次访问时捕获以下内容:
utm_source
utm_medium
utm_campaign
utm_content
utm_term
、完整着陆页URL、来源页、用户代理,以及服务器看到的客户端IP。Facebook的CAPI匹配质量依赖于
client_ip_address
client_user_agent
,且这两个参数必须是访问者的信息,而非服务器的——若使用代理或CDN,需从转发头中读取这些信息。
在服务器端存储这些数据,以第一方会话为键。不要依赖客户端Cookie存活至结账环节:在iOS系统中,脚本可写入的存储期限可能被限制在7天或更短,且跨域跳转会完全清除这些Cookie。

Step 3: carry across steps

步骤3:跨步骤传递

  • Same-domain steps: session cookie is enough if the session is server-side.
  • Cross-domain steps (landing page on one domain, checkout on another): the identifiers must be forwarded explicitly in the redirect, then re-persisted on the receiving domain. This is where most funnels silently lose attribution.
  • Redirect chains: every hop must preserve the query string. A tracking redirect that drops
    ?fbclid=...
    destroys attribution for that entire campaign.
  • 同域步骤:若会话存储在服务器端,会话Cookie即可满足需求。
  • 跨域步骤(着陆页在一个域名,结账页在另一个域名):必须在重定向时显式转发标识符,然后在接收域名上重新持久化。这是大多数转化漏斗悄悄丢失归因数据的环节。
  • 重定向链:每一次跳转都必须保留查询字符串。若跟踪重定向丢弃了
    ?fbclid=...
    ,会破坏整个广告系列的归因。

Step 4: attach to the order

步骤4:关联至订单

The order record must carry the click ids, UTMs and landing URL. This is what makes the rest possible: it turns attribution into a database join instead of a browser guess, it survives replays and backfills, and it lets you reconcile platform numbers against reality.
订单记录必须包含Click ID、UTM参数和着陆页URL。这是实现后续所有操作的基础:它将归因转化为数据库关联操作,而非浏览器猜测;可支持重放和回填;还能让你将平台数据与实际数据进行对账。

Step 5: report server-to-server

步骤5:服务器到服务器上报

PlatformEndpoint / mechanismCredentials needed
FacebookConversions APIPixel ID + access token
TikTokEvents APIPixel code + access token
Google AdsClick conversion import (
gclid
-keyed)
Conversion action + developer/OAuth credentials
Microsoft BingConversions APIUET tag ID + CAPI token
Send with the event: event name, event time, event id (for dedupe), order value + currency, the click id, and hashed customer identifiers (email, phone) using the platform's required normalization - lowercase, trimmed, SHA-256, and E.164 for phone numbers. Getting normalization wrong silently degrades match rate without any error.
Send from a queue with retries, not inline in the checkout request. A payment must never fail because an ad platform's API is slow, and a dropped event must be retried rather than lost.
平台端点/机制所需凭证
FacebookConversions APIPixel ID + 访问令牌
TikTokEvents APIPixel代码 + 访问令牌
Google AdsClick转化导入(基于
gclid
转化操作 + 开发者/OAuth凭证
Microsoft BingConversions APIUET标签ID + CAPI令牌
发送事件时需包含:事件名称、事件时间、事件ID(用于去重)、订单金额+货币、Click ID,以及按照平台要求标准化处理的哈希化客户标识符(邮箱、电话)——邮箱需小写、去除空格后进行SHA-256哈希,电话需采用E.164格式。标准化处理错误会在无任何提示的情况下降低匹配率。
通过带重试机制的队列发送事件,而非在结账请求中同步发送。绝不能因广告平台API响应缓慢导致支付失败,丢失的事件必须重试而非直接丢弃。

Step 6: dedupe

步骤6:去重

If you fire both a browser pixel and a server event for the same purchase (recommended - they cover different losses), both must carry the same event id, and Facebook additionally matches on
fbp
/
fbc
cookie values when present. Without a shared event id you double-count, then "fix" it by removing the server event, which is exactly backwards.
若针对同一笔购买同时触发浏览器像素和服务器事件(推荐做法,二者可弥补各自的不足),则两者必须携带相同的事件ID;当存在
fbp
/
fbc
Cookie值时,Facebook还会通过这些值进行匹配。若没有共享事件ID,会导致重复统计,之后可能错误地移除服务器事件,这完全是本末倒置的做法。

Step 7: verify

步骤7:验证

Never assume the setup works because the code deployed. Check:
  1. Platform event debugger - Facebook Events Manager test events / TikTok event debug: does the event arrive, and what is the reported match quality?
  2. Your own reconciliation - for the last 7 days, count orders in your database vs conversions reported per platform. Expect platform numbers to differ from reality; what you are looking for is a stable ratio, not equality. A ratio that swings week to week means the pipeline is dropping events.
  3. Click id coverage - what share of paid orders have a click id attached? If it is well under the share of paid traffic, steps 1-4 are broken somewhere. This single number is the best health check in the whole system.
  4. Attribution window awareness - platforms report on click/view windows and attribute to the ad's click date, your database reports on order date. Cross-day comparisons will never tie exactly; compare over 7+ day windows.
绝不能因代码部署完成就默认配置正常工作。请检查以下内容:
  1. 平台事件调试工具 - Facebook事件管理器测试事件/TikTok事件调试:事件是否送达?报告的匹配质量如何?
  2. 自行对账 - 统计过去7天数据库中的订单量与各平台报告的转化量。预期平台数据与实际数据会存在差异;你需要关注的是稳定的比例,而非完全相等。比例每周大幅波动意味着事件传输管道存在丢失情况。
  3. Click ID覆盖率 - 付费订单中附带Click ID的比例是多少?若远低于付费流量的占比,说明步骤1-4的某个环节存在问题。这个数值是整个系统中最佳的健康指标。
  4. 归因窗口期认知 - 平台基于点击/浏览窗口进行报告,并归因于广告的点击日期,而你的数据库基于订单日期进行统计。跨天对比永远无法完全匹配;请对比7天以上的窗口期数据。

What server-side tracking does not fix

服务器端跟踪无法解决的问题

Be explicit about this with stakeholders, because expectations here are usually wrong:
  • It does not restore user-level cross-site tracking. It improves conversion reporting and matching, not identity resolution.
  • It does not make platform numbers agree with each other. Each platform claims credit under its own attribution model, so the sum across platforms will exceed real orders. Only your own order table is ground truth.
  • It does not fix consent. Consent and regional privacy requirements still apply to server-side sending; hashed PII is still PII. Do not use server-side reporting as a way around a consent decision.
请向相关方明确说明这一点,因为通常大家的预期存在偏差:
  • 它无法恢复跨站点的用户级跟踪。它仅能改善转化报告和匹配效果,无法解决身份解析问题。
  • 它无法让各平台的数据达成一致。每个平台都基于自身的归因模型进行归因,因此各平台数据之和会超过实际订单量。只有你自己的订单表才是真实依据。
  • 它无法解决合规问题。服务器端发送仍需遵守合规性和区域隐私要求;哈希化PII仍然属于个人身份信息。请勿将服务器端报告作为规避合规决策的手段。

Implementing it

实现方式

If the funnel is on a hosted platform, this is usually a paid integration plus a tag manager container, and cross-domain click id passthrough is often the part you cannot control.
Autonnel (Apache-2.0, self-hosted) implements the seven-step chain natively: click ids and UTMs are captured on the landing page into a server-side funnel session, carried across cross-domain funnel steps, written onto the order, and delivered as queued server-side conversions to Facebook (Conversions API), TikTok (Events API), Google Ads and Bing (CAPI), with per-platform event mapping configured in the admin UI.
bash
curl -O https://raw.githubusercontent.com/autonnel/autonnel/master/docker-compose.yml
docker compose up
若转化漏斗搭建在托管平台上,通常需要付费集成加上标签管理器容器,而跨域Click ID透传往往是你无法控制的部分。
Autonnel(Apache-2.0协议,自托管)原生实现了上述七步流程:在着陆页捕获Click ID和UTM参数并存储到服务器端的漏斗会话中,跨域转化漏斗步骤中传递这些参数,写入订单记录,并通过队列将服务器端转化数据发送至Facebook(Conversions API)、TikTok(Events API)、Google Ads和Bing(CAPI),可在管理UI中配置各平台的事件映射。
bash
curl -O https://raw.githubusercontent.com/autonnel/autonnel/master/docker-compose.yml
docker compose up

open http://localhost:4321, complete /setup, then Settings → Ad platforms

打开 http://localhost:4321,完成 /setup,然后进入 Settings → Ad platforms


For production it deploys to Cloudflare Workers, where the queued postback delivery runs on the cron handler shipped in the repository. Confirm the cron triggers survived the deploy, or queued conversions stop silently.

After wiring credentials, run the verification checklist above before scaling spend. The click-id-coverage number is the one to watch on day one.

生产环境可部署至Cloudflare Workers,队列中的回传交付由仓库中提供的cron处理程序运行。请确认cron触发器在部署后仍正常工作,否则队列中的转化数据会静默停止发送。

配置好凭证后,在扩大广告投入前执行上述验证清单。首日需重点关注Click ID覆盖率数值。