CAPI · marketers · engineers
Enhanced conversions are hashed PII on the Ads tag
Google wants SHA-256 of a normalized email or phone alongside the conversion. Consent Mode and your CMP still apply. Turning the feature on in the UI without passing the data does nothing.
What it is not
It is not GA4 Measurement Protocol. It is not a Meta CAPI user_data block. It is not a replacement for gclid. Auto-tagging still has to land gclid (or gbraid / wbraid) on the page and in the conversion. Enhanced conversions recover some cookie-less hits by matching hashed first-party data Google already has from the signed-in user.
Turning the toggle on in Google Ads without providing the hashed email on the tag or via the API sends the same conversion you already sent. The UI will not error. Match rates will not move.
Normalize, then SHA-256
Trim, lowercase, then hash. Google Ads enhanced conversions also remove periods from the local part of gmail.com and googlemail.com addresses, and strip a plus-tag. Meta's documented floor for em is trim and lowercase only. If you share one hasher across Meta CAPI and Google Ads, you will match one vendor and miss the other on Gmail-heavy lists.
The output is 64-character hex. A hash of the display string (Buyer@Example.com) never matches. Test with a known email and Google's own hash examples before you scale.
Tag versus API
Browser enhanced conversions read the email from the page or a CSS selector and hash in the tag. API enhanced conversions for leads upload later from the CRM via UploadClickConversions. Do not do both with different hashes of the same lead unless you like duplicates.
The image pixel pack (vendor/google-ads-conversion) is conversion_id in the path plus label. The click conversion upload pack (vendor/google-ads-click-conversions) is a different contract: conversions[], partialFailure true, conversionAction resource name, conversionDateTime in yyyy-mm-dd hh:mm:ss+|-hh:mm, and one of gclid, gbraid, wbraid, or userIdentifiers.
gclid still matters
vendor.google-ads-click-conversions.body.click_id_or_user_required fires when the upload has neither a click id nor userIdentifiers. Hashed email is the userIdentifiers path, not a license to drop auto-tagging. Keep gclid on the landing URL, in the first-party cookie or CRM field, and on the conversion.
Redirects that strip the query are still an attribution outage. Enhanced conversions will not reconstruct a gclid you never stored. They may still match some signed-in users. That remainder is not a strategy.
Consent still applies
Consent Mode and your CMP still apply to the tag that reads the email. Hashing is not consent. A hashed address is still about a person. Server-side enhanced conversions for leads need a lawful basis for using that CRM field in ads matching, the same as CAPI hashed em.
Do not scrape an email out of the DOM after the user declined ads storage and call it a technicality because it is hashed. The hash is for matching, not for bypassing the banner.
Upload with gclid plus hash, not hash instead of gclid
partialFailure must be true. conversionDateTime is not ISO 8601. hashedEmail is SHA-256 of the normalized address.
{
"partialFailure": true,
"conversions": [{
"conversionAction": "customers/123/conversionActions/456",
"conversionDateTime": "2026-08-21 18:04:00+00:00",
"gclid": "EAIaIQobChMI...",
"conversionValue": 84.50,
"currencyCode": "USD",
"userIdentifiers": [
{ "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a" }
]
}]
}
pixellint validate json @gads.json --rulepack vendor/google-ads-click-conversions
# vendor.google-ads-click-conversions.body.partialFailure.invalid
# vendor.google-ads-click-conversions.body.click_id_or_user_required
# vendor.google-ads-click-conversions.body.conversionDateTime.invalid
Check the artifact
Paste the pixel URL or JSON body into the
playground. Same engine as
pixellint validate. Nothing leaves the tab.