Enhanced Conversions are supposed to improve your Google Ads conversion accuracy by 5-15%. But if they’re not set up correctly, you’re getting zero benefit—and you might not even know it. Here’s how to diagnose and fix Enhanced Conversions issues.
What Enhanced Conversions Actually Do
Before debugging, understand what you’re debugging:
Enhanced Conversions capture first-party customer data (email, phone, address) at conversion time, hash it, and send it to Google. Google matches this against signed-in user data to attribute conversions that would otherwise be lost due to:
- Cookie restrictions
- Cross-device journeys
- Privacy browser settings
Key point: If the data isn’t being captured or hashed correctly, Enhanced Conversions silently fail—no errors, just missing attribution.
Check 1: Verify Enhanced Conversions Are Enabled
First, confirm the feature is actually on:
In Google Ads:
- Go to Tools & Settings → Conversions
- Click on your conversion action
- Scroll to “Enhanced conversions”
- Verify it shows “On”
What the Status Should Show:
- “Recording conversions”: Working
- “Inactive”: Needs troubleshooting
- “No recent data”: Data not being received
If status is “Inactive,” continue debugging below.
Check 2: Verify Data Is Being Sent
For GTM Implementation:
Open GTM Preview mode and check your conversion tag:
- Click on your Google Ads Conversion tag
- Look for “User-provided data” section
- Verify values are populated:
Email: j***@example.com (hashed automatically)
Phone: +1555******
First Name: J*** (if included)
If “User-provided data” is empty, the data layer isn’t providing the values.
For gtag.js Implementation:
Check the network request:
- Open DevTools → Network
- Filter by “googleads”
- Find the conversion request
- Look for
em=(email) orph=(phone) parameters
// Should see something like:
em=a1b2c3d4e5... (SHA-256 hash)
If these parameters are missing, data isn’t being captured.
Check 3: Data Layer Configuration (GTM)
For GTM Enhanced Conversions, you need data in one of two places:
Option A: Automatic Collection (CSS Selectors)
GTM can automatically find form fields on your page:
- In your Google Ads Conversion tag, click “Include user-provided data from your website”
- Choose “Automatic collection”
- GTM looks for fields matching common patterns
Why automatic collection fails:
- Non-standard field names
- Fields inside iframes
- Dynamic form rendering
- Multi-step checkouts
Option B: Manual Data Layer (Recommended)
Push user data explicitly:
// On your conversion page (e.g., order confirmation)
dataLayer.push({
'event': 'purchase',
'user_data': {
'email': 'customer@example.com', // Will be hashed by GTM
'phone_number': '+15551234567', // E.164 format
'address': {
'first_name': 'John',
'last_name': 'Doe',
'street': '123 Main St',
'city': 'New York',
'region': 'NY',
'postal_code': '10001',
'country': 'US'
}
}
});
In GTM, Configure the Tag:
- Edit your Google Ads Conversion tag
- Check “Include user-provided data from your website”
- Select “Manual configuration” or “Code”
- Create a Data Layer Variable for
user_data.email - Map it to the Email field
Variable: dlv_user_email
Data Layer Variable Name: user_data.email
Check 4: Data Format Requirements
Enhanced Conversions are strict about data formats. Invalid data is silently dropped.
Email Requirements:
// CORRECT formats:
'email': 'john.doe@example.com' // Lowercase
'email': 'JOHN.DOE@EXAMPLE.COM' // Will be lowercased by GTM
// INCORRECT formats:
'email': 'john.doe@example.com ' // Trailing space - FAILS
'email': ' john.doe@example.com' // Leading space - FAILS
'email': '' // Empty string - FAILS
'email': null // Null - FAILS
Fix: Trim whitespace before pushing to data layer:
const email = formData.email.trim().toLowerCase();
Phone Requirements:
// CORRECT format (E.164):
'phone_number': '+15551234567' // Country code, no spaces/dashes
// INCORRECT formats:
'phone_number': '555-123-4567' // Missing country code - FAILS
'phone_number': '(555) 123-4567' // Formatting characters - FAILS
'phone_number': '+1 555 123 4567' // Spaces - FAILS
Fix: Normalize phone numbers:
function normalizePhone(phone, countryCode = '1') {
const digits = phone.replace(/\D/g, '');
if (digits.length === 10) {
return `+${countryCode}${digits}`;
}
if (digits.length === 11 && digits.startsWith(countryCode)) {
return `+${digits}`;
}
return `+${digits}`;
}
Address Requirements:
'address': {
'first_name': 'John', // Required: No numbers
'last_name': 'Doe', // Required: No numbers
'street': '123 Main Street', // Full street address
'city': 'New York', // City name only
'region': 'NY', // State/province code
'postal_code': '10001', // No dashes for US
'country': 'US' // ISO 2-letter code
}
Check 5: gtag.js Implementation
If you’re using gtag.js directly (not GTM):
Basic Setup:
// Enable Enhanced Conversions globally
gtag('config', 'AW-XXXXXXXXX', {
'allow_enhanced_conversions': true
});
// Set user data BEFORE conversion event
gtag('set', 'user_data', {
'email': 'customer@example.com',
'phone_number': '+15551234567'
});
// Then fire the conversion
gtag('event', 'conversion', {
'send_to': 'AW-XXXXXXXXX/XXXXXXXXXXX',
'value': 99.99,
'currency': 'USD',
'transaction_id': 'ORDER12345'
});
Common gtag.js Mistakes:
Wrong: Setting user_data AFTER conversion:
// WRONG ORDER:
gtag('event', 'conversion', {...}); // Conversion fires first
gtag('set', 'user_data', {...}); // Data set too late - IGNORED
Wrong: Using wrong property name:
// WRONG:
gtag('set', 'userData', {...}); // camelCase - WRONG
gtag('set', 'user-data', {...}); // Hyphen - WRONG
// CORRECT:
gtag('set', 'user_data', {...}); // Underscore - CORRECT
Check 6: Hashing Issues
Enhanced Conversions require SHA-256 hashing. In most cases, Google handles this automatically—but there are exceptions.
When Google Auto-Hashes:
- GTM with “Include user-provided data” enabled
- gtag.js with
user_dataobject - Google Ads API with unhashed fields
When You Must Pre-Hash:
- Measurement Protocol
- Offline conversion imports
- Some server-side implementations
Correct hashing:
async function sha256Hash(value) {
const encoder = new TextEncoder();
const data = encoder.encode(value.trim().toLowerCase());
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// Usage:
const hashedEmail = await sha256Hash('customer@example.com');
// Result: 7c0bca...
Critical: Normalize BEFORE hashing:
- Lowercase
- Trim whitespace
- Remove extra spaces
- Apply format rules (phone E.164, etc.)
Check 7: Verification in Google Ads
Even if implementation looks correct, verify data is being received:
Conversion Diagnostics:
- Google Ads → Tools → Conversions
- Click your conversion action
- Click “Diagnostics” tab
- Look for Enhanced Conversions status
What Each Status Means:
- “Enhanced conversions active”: Working correctly
- “No enhanced conversion data received”: Implementation broken
- “Enhanced conversion data received, processing”: Recently set up, wait 48-72 hours
- “Limited data received”: Partial implementation (some conversions missing data)
Tag Coverage Report:
- Tools → Tag coverage
- Check Enhanced Conversions column
- Should show percentage of conversions with enhanced data
Healthy setup: 70%+ of conversions should have enhanced data.
Check 8: Common Implementation Mistakes
Mistake 1: Enhanced Conversions on All Conversions
Enhanced Conversions only work for conversions where you have user data. Don’t enable them for:
- Page view “conversions”
- Button click conversions
- Any conversion without user PII
Mistake 2: Duplicate Conversion Tags
If you have multiple conversion tags firing:
- Only one should have Enhanced Conversions enabled
- Duplicates can cause data mismatches
Mistake 3: User Data on Wrong Page
Enhanced Conversions need data on the CONVERSION page, not the form submission page:
// WRONG: Data on form submission, conversion on thank-you page
// Form page: dataLayer.push({ user_data: {...} })
// Thank-you: dataLayer.push({ event: 'purchase' }) // No user_data!
// CORRECT: Data and conversion on same page (or data persisted)
// Thank-you: dataLayer.push({
// event: 'purchase',
// user_data: {...}
// });
Mistake 4: Testing with Fake Data
Enhanced Conversions validate data format. Using obviously fake data:
// Google may reject:
'email': 'test@test.com' // Common test email
'phone_number': '+11111111111' // Obviously fake
Use realistic test data for verification.
Debugging Checklist
Run through this checklist:
- Enhanced Conversions enabled in Google Ads
- Conversion tag has “Include user-provided data” checked
- Data layer includes user_data object
- Email is properly formatted (trimmed, lowercase)
- Phone is E.164 format with country code
- Data is available BEFORE conversion fires
- GTM Preview shows user data in conversion tag
- Network request includes hashed parameters
- Google Ads diagnostics shows data received
- No duplicate conversion tags
Enhanced Conversions Implementation Template
Here’s a complete, working implementation:
Data Layer Push (on confirmation page):
// Get user data from your confirmation page
const orderData = {
transactionId: 'ORDER-' + Date.now(),
value: 99.99,
currency: 'USD',
email: document.getElementById('customer-email').value,
phone: document.getElementById('customer-phone').value,
firstName: document.getElementById('first-name').value,
lastName: document.getElementById('last-name').value
};
// Normalize and push
dataLayer.push({
'event': 'purchase',
'transaction_id': orderData.transactionId,
'value': orderData.value,
'currency': orderData.currency,
'user_data': {
'email': orderData.email.trim().toLowerCase(),
'phone_number': normalizePhone(orderData.phone),
'address': {
'first_name': orderData.firstName.trim(),
'last_name': orderData.lastName.trim()
}
}
});
GTM Variables:
Variable: dlv_user_email
Type: Data Layer Variable
Name: user_data.email
Variable: dlv_user_phone
Type: Data Layer Variable
Name: user_data.phone_number
GTM Conversion Tag:
- Tag type: Google Ads Conversion Tracking
- Conversion ID: AW-XXXXXXXXX
- Conversion Label: XXXXXXXXXXX
- Check: “Include user-provided data from your website”
- Configuration: Manual
- Map variables to fields
Still Not Working?
Enhanced Conversions failures are often subtle—the implementation looks correct but data isn’t matching. If you’ve followed this guide and conversions still show “No data received”:
- The data format might have edge cases we haven’t covered
- Multiple tracking scripts might be conflicting
- Server-side or consent issues might be blocking data
Get a free conversion tracking audit and we’ll analyze your specific implementation. We see dozens of Enhanced Conversions setups weekly and can identify issues that generic guides miss.