Module 7
Enhanced Conversions: user-provided data + SHA-256 normalised hashing
Implement Google Ads Enhanced Conversions by hashing user-provided data (email, phone, name) with SHA-256 before sending to Google.
What this does
Google Ads Enhanced Conversions improves conversion measurement by sending hashed user-provided data (email, phone, name, address) alongside your conversion events. Google matches the hashed data against signed-in Google accounts to attribute conversions that would otherwise be missed.
The data must be normalised and hashed with SHA-256 before sending. Google does not accept unhashed data for Enhanced Conversions.
Normalisation rules (Google's requirements)
Email: trim whitespace, lowercase
Phone: E.164 format (+12025551234), strip spaces/dashes
First name: trim whitespace, lowercase
Last name: trim whitespace, lowercase
SHA-256 hashing function
// Works in modern browsers (Web Crypto API) and Node.js 16+
async function hashField(value) {
const normalised = value.trim().toLowerCase();
const encoded = new TextEncoder().encode(normalised);
const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
}dataLayer push for Enhanced Conversions
// On conversion (checkout complete, form submit, etc.)
async function pushEnhancedConversion({ email, firstName, lastName, phone }) {
const [hashedEmail, hashedFirst, hashedLast, hashedPhone] = await Promise.all([
email ? hashField(email) : null,
firstName ? hashField(firstName) : null,
lastName ? hashField(lastName) : null,
phone ? hashField(normalisePhone(phone)) : null,
]);
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'conversion',
enhanced_conversion_data: {
email: hashedEmail ?? undefined,
first_name: hashedFirst ?? undefined,
last_name: hashedLast ?? undefined,
phone: hashedPhone ?? undefined,
},
});
}
function normalisePhone(phone) {
// Remove all non-digit characters except leading +
const digits = phone.replace(/[^\d+]/g, '');
// Ensure E.164 format - this is a simplified normalisation
// Your implementation should handle country codes correctly
return digits.startsWith('+') ? digits : `+${digits}`;
}GTM configuration
In GTM, configure the Google Ads Conversion Tag with Enhanced Conversions:
- Enable "Enhanced conversions" on the tag
- Set "Enhancement data source" to "Data Layer"
- Map the dataLayer variables:
Email:enhanced_conversion_data.emailFirst name:enhanced_conversion_data.first_nameLast name:enhanced_conversion_data.last_namePhone number:enhanced_conversion_data.phone
GTM will send the hashed values to Google Ads when the conversion fires.
TypeScript version
interface UserData {
email?: string;
firstName?: string;
lastName?: string;
phone?: string;
}
async function buildEnhancedConversionData(user: UserData): Promise<Record<string, string>> {
const result: Record<string, string> = {};
const entries: [string, string | undefined][] = [
['email', user.email],
['first_name', user.firstName],
['last_name', user.lastName],
['phone', user.phone],
];
const hashed = await Promise.all(
entries.map(([, value]) => (value ? hashField(value) : Promise.resolve(null)))
);
entries.forEach(([key], i) => {
if (hashed[i]) result[key] = hashed[i]!;
});
return result;
}Consent requirement
Enhanced Conversions requires ad_storage: 'granted' and ad_user_data: 'granted'. Configure the Google Ads conversion tag in GTM to require both consent types. Do not send Enhanced Conversions data when either signal is denied.
The free Enhanced Conversions Container has the full GTM setup with hashing variables pre-built.
Free container for this module
Enhanced Conversions Container
GTM container implementing Google Ads Enhanced Conversions with SHA-256 normalised hashing of user-provided data. Includes the data layer schema, variable definitions, and the conversion tag configuration.
Get the container →