OpenAI 广告像素如何通过 __obi 跨站追踪 ChatGPT 用户
OpenAI 在 bzr.openai.com 部署的广告收集器会设置一个名为 __obi 的 Cookie,作用域为 .openai.com。该 Cookie 的值与你在 ChatGPT 上的操作绑定,并关联你的 ChatGPT 账号。之后,当你访问普通网站时,__obi 会被发送至 OpenAI。
所有在 ChatGPT 投放广告的公司,都会在自家网站嵌入一段OpenAI 代码片段,就像零售商安装 Meta 和 Google 的追踪代码一样。用户加载这段代码时,__obi 会连同当前浏览页面的数据(包括搜索的商品、阅读的文章、购买行为等)一并发送给 OpenAI。
简言之,OpenAI 可以将你在这些外部网站的行为,与你的 ChatGPT 账号关联起来。
我在自己的手机上完整复现了这一机制,通过两种独立抓包工具验证,并比对了数月间的流量数据——涵盖 1029 个域名下的 936 个不同广告方像素。

运作机制
步骤一:ChatGPT 创建并签署标识符
在 chatgpt.com 页面,客户端会生成 16 字节随机数,随后调用接口 POST /backend-api/bazaar/obi/sync-token(未登录时调用 /backend-anon/ 路径)。后端会返回一个采用 RS256 算法的 JWT:
{
"iss": "chatgpt-wadi",
"aud": "bzr.openai.com",
"purpose": "obi_sync",
"operation": "set",
"consent_decision": "analytics_allowed",
"consent_policy_version": "user_granular_consent_v1",
"sub": "«已脱敏:64位十六进制账号主体»",
"subject_type": "account_user",
"obi": "«已脱敏:22位标识符»",
"exp": "«签发时间 + 60秒»"
}
其中 sub 代表用户账号,obi 是唯一标识符。该令牌将二者绑定,仅对收集器生效,且 60 秒后过期。bzr 是 OpenAI 广告平台的内部代号「bazaar」,wadi 则是签发该令牌的服务名称。
步骤二:标识符成为 OpenAI 域名下的 Cookie
客户端跨域向 bzr.openai.com/v1/obi/sync 发送 {"token": "«JWT»"} 请求,服务器响应如下:
Set-Cookie: __obi=«已脱敏»; Domain=.openai.com; HttpOnly;
Max-Age=31536000; Path=/; SameSite=none; Secure
SameSite=none 搭配 Secure,是 Cookie 支持跨域请求的必要配置。该 Cookie 的有效期(Max-Age)为一年,且其值与 JWT 中的 obi 字段完全一致。
步骤三:广告方网站将标识符回传
广告方页面会向 OpenAI 服务器发送三类请求。在存储了 __obi Cookie 的手机上,前三类请求均会携带该 Cookie:
| 请求类型 | 是否携带 __obi |
说明 |
|---|---|---|
GET bzrcdn.openai.com/sdk/oaiq.min.js |
是 | SDK 脚本本身的加载请求 |
含 obref 参数的 POST bzr.openai.com/v1/sdk/events |
是 | 转化事件上报 |
无额外参数的 POST bzr.openai.com/v1/sdk/events |
是 | SDK 的「无凭证」路径请求 |
GET bzrcdn.openai.com/pixel-config/… |
完全不携带 Cookie 头 | 控制组请求 |
第一类请求尤为值得关注:尽管像素 SDK 有跳过凭证的代码路径,但浏览器会在 OpenAI 代码运行前,自动将 Cookie 附加到加载 SDK 的 <script src> 请求中。也就是说,只要加载了该标签,标识符就会被泄露。
随标识符传输的数据
上述 SDK 还会从广告方页面收集用户身份信息,其载荷按 OpenAI 的标注分为四类来源:in 代表广告方主动传入的数据,fm、ht、js 则分别是 SDK 从表单字段、页面渲染文本、标签管理器总线中抓取的数据。从观测到的流量来看,抓取到的身份事件(685 次)远多于广告方主动提供的(255 次)。
标签管理器总线是邮箱信息的最大来源。SDK 会替换 window.dataLayer.push 方法,同时读取 adobeDataLayer,并通过解析 gtm.js 脚本标签的 l= 参数定位重命名后的 GTM 层。当前版本会从中提取邮箱和手机号;在 8 月 27 日缩小抓取范围前,0.1.31 版本还会提取姓名和地理位置信息。
邮箱、手机号、姓名会经过 SHA-256 哈希处理后传输,而国家、地区、城市和邮政编码则以明文形式发送。邮政编码是被抓取最多的表单字段,在 28 个网站共出现 100 次相关事件。
URL 会被精简为「源地址+路径」后发送,观测到的 23929 条请求均未携带查询参数。但路径会被完整保留,其中包含医疗状况、债务解决方案流程、诉讼信息收集表单等内容。
在 881 个已知配置的像素中,有 638 个开启了自动匹配功能,涵盖所有观测到的信贷类广告主。该功能由 OpenAI 广告管理器控制,同时设有黑名单,排除密码、一次性验证码、卡号、社保号、出生日期、病史、诊断结果和法院相关字段。
专为跨域设计的 Cookie
在广告方页面的请求中,其他所有 OpenAI Cookie 均被浏览器拦截,唯有 __obi 例外:
| Cookie 名称 | 结果 |
|---|---|
oai-did、oaicom-stable-id |
被拦截,因 SameSite=Lax 配置 |
oai-client-auth-info、会话类 Cookie |
被拦截,因域名不匹配 |
__obi |
成功发送 |
__obi 是唯一配置为 SameSite=None 的 OpenAI 标识符。
观测覆盖范围
在我的设备上,同一个 __obi 值被发送至 OpenAI 的场景,涉及 13 个不同像素 ID 对应的 12 个商业网站,包括 Chewy、Wayfair、ThriftBooks、Eventbrite、HelloFresh、Coursera 和 SeatGeek。所有请求均返回 202 状态码,表示接收成功。
在更广泛的流量数据中,30 个不同的 __obi 值里,有 12 个出现在多个广告方的请求中,其中一个甚至关联了 10 个广告方。
未登录状态下仍可运作
在解码的 932 个同步令牌中,736 个标记为 subject_type: account_user(账号用户),196 个标记为 anonymous(匿名用户)。匿名用户的标识符与账号用户的一样稳定:每台设备对应一个,且至少可保留 27 天。
OpenAI 的 Cookie 政策说明
OpenAI 的Cookie 政策将 __obi 归类为分析类 Cookie,有效期一年,适用域名包括 chatgpt.com 和 openai.com,是该类别下的唯一条目。政策说明称,分析类 Cookie 用于帮助 OpenAI 了解其服务的性能和使用情况。
OpenAI 将分析与营销设为两个独立的授权选项,对应 oai_consent_analytics 和 oai_consent_marketing。我解码的所有同步令牌均携带 consent_decision: analytics_allowed(允许分析),即使用户仅允许分析、拒绝营销授权,该 Cookie 仍会被设置。
OpenAI 的回应
9 月 14 日,我向 press@openai.com 和 privacy@openai.com 发送邮件,说明上述机制并提出两个问题:为何 __obi 被归类为分析类 Cookie?仅允许分析授权、拒绝营销授权的用户是否仍会被设置该 Cookie?OpenAI 客服回复称已收到反馈,会将相关发现转交内部审核,但未直接回答任何问题。需要说明的是,前文提到的脚本加载观测结果,是在发送邮件后才发现的。若 OpenAI 后续给出回应,我会更新本文内容。
局限性
浏览器限制:本次观测基于安卓版 Chrome。Safari 的智能追踪防护会拦截所有第三方 Cookie,而 iOS 版 Chrome 基于 WebKit 内核,因此该机制无法在任何 iOS 浏览器中运作。桌面版 Chrome 未进行测试。
触发概率:大约每 5 次 ChatGPT 会话中,才会有 1 次生成同步令牌。ChatGPT 移动网页端在展示广告时,完全不会触发同步流程。按照下文步骤操作的用户,可能会看到像素触发但未携带 Cookie 的情况。
账号关联未直接观测:202 状态码仅表示收集器接收了携带 Cookie 的事件。根据机制设计可推断,OpenAI 会在服务器端将其与用户账号关联,但我并未直接观测到这一步骤。
技术本身并非首创:Meta 多年前就推出了结构类似的机制:登录账号、像素触发时携带第三方 Cookie、将站外转化与用户档案关联。这是广告技术领域的标准操作。但将其应用于 AI 聊天产品,尚无先例。人们会向这类产品倾诉不会在社交网络分享的内容,且这类产品正越来越多地代表用户执行操作。
像素的另一 Cookie 无此功能:__obref 是设置在广告方自有域名下的 Cookie,每个网站对应不同的值,且各网站无法互相查看。在观测到的 2860 个值中,2828 个仅出现在一个广告方的请求中。
广告方无法获取该信息:__obi 所属域名无法被广告方脚本读取。他们仅安装了转化像素,完全无法知晓自己的访客正被关联到 ChatGPT 身份。