Identity & hashing
Every identifier you add gives the platform another way to match the event. Pass raw fields on user and clickIds — adscapi normalizes and SHA-256 hashes each one per the platform's rules. You never hash anything yourself.
Rule: raw in, hashed out
- Never pre-hash email, phone, or name. Double-hashing silently kills match rate
- adscapi lowercases / trims / E.164-normalizes where each platform requires it, then hashes
- Click ids (
gclid,fbclid, …) andfbc/fbpare sent as-is — they are not PII hashes
ConversionUserData
| Field | Type |
|---|---|
email | string? |
phone | string? |
firstName | string? |
lastName | string? |
city | string? |
state | string? (region is an alias) |
zip | string? |
country | string? |
dateOfBirth | string? |
gender | 'm' | 'f' |
externalId | string? |
ip | string? |
userAgent | string? |
fbc | string? |
fbp | string? |
Priority if you can only capture some
| Priority | Fields |
|---|---|
| 1 — strongest | email + phone + click IDs (gclid, fbclid, ttclid, …) |
| 2 | ip + userAgent |
| 3 | firstName, lastName, city, state, zip, country |
| 4 | externalId, dateOfBirth, gender, fbc/fbp |
Capture click ids client-side with pixel helpers (pixelSnippet() / parseClickIds()) so they survive into the server event.
Example
ts
await ads.conversions.track({
name: 'purchase',
value: 49,
currency: 'USD',
user: {
email: 'jane@example.com', // raw — never pre-hash
phone: '+1 415 555 2671',
firstName: 'Jane',
lastName: 'Doe',
city: 'Austin',
state: 'TX', // region is an alias
zip: '78701',
country: 'US',
dateOfBirth: '19900115',
gender: 'f',
externalId: 'cust_123',
ip: req.ip,
userAgent: req.headers['user-agent'],
fbc, // Meta click cookie
fbp, // Meta browser id cookie
},
clickIds: {
fbclid, gclid, ttclid, msclkid,
twclid, epik, sccid, li_fat_id, rdt_uuid,
},
consent: { adUserData: true, adPersonalization: true },
});Related
- Match quality — the EMQ feedback loop
- Consent — required before identity is useful
- conversions.track()