ChatGPT now knows what you do on other websites via ad collector
Hacker News

ChatGPT now knows what you do on other websites via ad collector

ChatGPT now knows what you do on other websites via ad collector

Overview

OpenAI's ad collector (bzr.openai.com) sets a cookie called __obi scoped to .openai.com. The value is sent to OpenAI from ordinary websites you visit. When companies buy ads on ChatGPT, they install a small piece of OpenAI code on their own sites-similar to how retailers install Meta and Google tracking code. Loading that code sends __obi to OpenAI along with data about the page you're browsing, including products you search for, articles you read, and purchase behaviors. The result is that OpenAI can connect what you do on external sites to your ChatGPT account.

How It Works

Step 1 - Creating the Identifier
On chatgpt.com, the client generates 16 random bytes and calls POST /backend-api/bazaar/obi/sync-token (or /backend-anon/ when signed out). The backend returns an 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": "«redacted: 64-hex account subject»",
  "subject_type": "account_user",
  "obi": "«redacted: 22-char identifier»",
  "exp": "«iat + 60s»"
}

The sub field identifies the account, and the obi field is the unique identifier. Together, they bind the user to the collector and expire in 60 seconds. bzr is OpenAI's internal name for the ads platform, and wadi is the issuing service.

Step 2 - Setting the Cross-Site Cookie
The client POSTs {"token": "«JWT»"} cross-site to bzr.openai.com/v1/obi/sync. The response sets a cookie:

Set-Cookie: __obi=«redacted»; Domain=.openai.com; HttpOnly; Max-Age=31536000; Path=/; SameSite=none; Secure

SameSite=none with Secure ensures the cookie is sent on cross-site requests, and Max-Age=31536000 gives it a one-year lifetime.

Step 3 - Advertiser Sites Send Back Data
Three request classes travel from an advertiser's page to OpenAI's hosts:

Request Carries __obi Purpose
GET bzrcdn.openai.com/sdk/oaiq.min.js Yes The script loads itself
POST bzr.openai.com/v1/sdk/events with obref Yes Conversion events
POST bzr.openai.com/v1/sdk/events (bare body) Yes SDK's "no credentials" path
GET bzrcdn.openai.com/pixel-config/… No Control request

Notably, the pixel SDK sometimes omits credentials even though the browser attaches cookies to the request that loads the SDK before OpenAI's code runs. Because the tag loads the cookie, the identifier is disclosed.

What Travels With It

The SDK collects identity from the advertiser's page, separating four sources labeled by OpenAI:

  • in: Values the advertiser passes deliberately
  • fm: Scraped from form fields
  • ht: Rendered page text
  • js: Tag-manager bus data

In observed traffic, scraped identity outnumbered advertiser-supplied identity: 685 events vs. 255. The tag-manager bus was the largest source of email. The SDK replaces window.dataLayer.push with its own function and also reads Adobe Data Layer, locating renamed GTM layers by parsing the l= parameter from the gtm.js script tag. Email and phone are SHA-256 hashed before transmission; country, region, city, and postal code are sent in clear. Postal code was the most-harvested field (100 events across 28 sites). URLs were reduced to origin plus path, with no query strings (none of 23,929 observed carried one). Paths survived, and paths reaching the collector included medical conditions, debt-solutions funnels, and litigation intake forms. Automatic matching was enabled for 638 of 881 pixels with known settings, including every credit and lending advertiser observed. A denylist excludes passwords, one-time codes, card numbers, SSN, date of birth, medical history, diagnosis, and court fields.

Observed Reach

On the author's device, one __obi value was sent to OpenAI from 12 commercial websites under 13 distinct pixel IDs (Chewy, Wayfair, ThriftBooks, Eventbrite, HelloFresh, Coursera, and SeatGeek), with every request returning HTTP 202. In broader traffic, 12 of 30 distinct __obi values appeared under more than one advertiser, and one appeared under ten.

Across 932 decoded sync tokens, 736 carried subject_type: account_user and 196 carried an anonymous subject. The anonymous subject is as stable as the account subject-one per device, persisting at least 27 days.

OpenAI's Cookie Policy

OpenAI's cookie policy lists __obi under Analytics cookies, valid for one year on both chatgpt.com and openai.com. It is the only entry in that section. The policy describes analytics cookies as helping OpenAI understand how its services perform and are used. OpenAI runs analytics and marketing as two separate consent choices, oai_consent_analytics and oai_consent_marketing. Every sync token the author decoded carried consent_decision: analytics_allowed.

OpenAI Response

The author sent the mechanism and two questions to p****@openai.com and p******@openai.com on 14 September, asking why __obi is classified as an analytics cookie and whether a user who grants analytics consent but refuses marketing consent still receives it. OpenAI Support replied that the inquiry would be shared internally for review and did not answer either question. The author notes the script-load observation was made after the inquiry was sent.

Browser Limitations

The mechanism operates on Chrome for Android. Safari's Intelligent Tracking Prevention blocks all third-party cookies, and Chrome on iOS runs on WebKit, so the mechanism does not operate on any iOS browser. Desktop Chrome remains untested. Additionally, the mobile web client serves ads without syncing at all-so some sessions produce no cookie attachment.

Session Gating

Roughly one ChatGPT session in five produces a sync token. The mobile web client does not always trigger synchronization, meaning a visitor might see a pixel fire with no cookie attached and the join is not observed.


Source: Author investigation, cross-checked against multiple months of observed traffic covering 936 distinct advertiser pixels across 1,029 hostnames.

Read on Hacker News ↗ ← Back to News

Comments

No comments yet. Start the discussion.