Google just killed three separate enhanced conversion setup methods and replaced them with a single on/off toggle. If you configured enhanced conversions through the old Google Tag, GTM variable, or manual JavaScript methods, your setup is about to change, and misconfiguration means silently losing conversion data.
Here’s the part most vendor documentation glosses over: the toggle doesn’t magically figure out where your user data lives. It expects the tag to already have access to hashed or hashable user identifiers through the automatic collection path. If your old setup relied on a custom User-Provided Data variable feeding a specific tag field, that plumbing still matters. It just doesn’t live in the UI the way it used to.
I’ve migrated about a dozen accounts through this consolidation across ecommerce and lead-gen clients. This post is the field guide I wish I’d had before starting.
The three deprecated methods, and how to spot which one you used
Before you can migrate cleanly, you need to know which flavour of enhanced conversions you actually had running. Most accounts I audit have at least two of these three configured simultaneously, which is part of why Google forced the consolidation in the first place.
Method 1: Google Tag (gtag.js) config-level setup
This was the direct on-page implementation. Somewhere in your site’s head or GTM’s Google Tag configuration, you had a block like:
gtag('set', 'user_data', {
"email": "user@example.com",
"phone_number": "+15551234567",
"address": {
"first_name": "Jane",
"last_name": "Doe",
"postal_code": "SW1A 1AA",
"country": "GB"
}
});
gtag('config', 'AW-XXXXXXXXX');
Enhanced conversions were enabled at the Google Ads conversion action level, and the user_data object was picked up automatically from the page context. If you see raw gtag('set', 'user_data', ...) calls in your codebase or a Custom HTML tag in GTM, this is you.
Method 2: GTM User-Provided Data variable
Introduced when GTM added first-class support for enhanced conversions, this method used a dedicated variable type (Google Ads User-Provided Data) that you referenced from the Google Ads Conversion Tracking tag. Two flavours existed inside that variable:
- Automatic collection: GTM scraped the page for email and phone patterns
- Manual configuration: You mapped Data Layer variables or DOM elements to specific fields (email, phone, first_name, last_name, street, city, region, postal_code, country)
You’d find these under Variables → User-Defined, with type Google Ads User-Provided Data. The conversion tag then had a dropdown pointing to this variable under “Include user-provided data from your website.”
Method 3: Manual JavaScript hashing before the tag fires
The paranoid path, and honestly the one I’ve seen most in regulated industries. Developers would SHA-256 hash email and phone client-side, then push the hashed values into the data layer:
async function sha256(value) {
const msgBuffer = new TextEncoder().encode(value.trim().toLowerCase());
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
return Array.from(new Uint8Array(hashBuffer))
.map(b => b.toString(16).padStart(2, '0')).join('');
}
sha256('user@example.com').then(h => {
window.dataLayer.push({
event: 'conversion_ready',
sha256_email_address: h
});
});
Those hashed fields were mapped one-by-one into the conversion tag’s user data section. If you have Custom JavaScript variables in GTM that call crypto.subtle.digest, this is your setup.
Quick identification table
| Signal in GTM/Site | Likely method |
|---|---|
gtag('set', 'user_data', {...}) in page source | Method 1 |
| Variable of type “Google Ads User-Provided Data” | Method 2 |
Custom JS variable containing crypto.subtle.digest | Method 3 |
sha256_email_address in data layer | Method 3 |
| Google Ads Conversion Tag with “Include user-provided data” enabled and pointing at a variable | Method 2 |
| Both Method 1 and Method 2 present | Common mess, prioritise Method 2 |
What the consolidated toggle actually does under the hood
The new experience is a single switch on the Google Ads Conversion Tracking tag inside GTM (and mirrored at the conversion action level in Google Ads). When enabled, the tag looks for user data in this priority order:
- Explicit user data fields configured on the tag itself (if you expanded the advanced section)
user_dataset viagtag('set', ...)earlier in the page lifecycle- Automatic detection: GTM/gtag scans form fields, checkout inputs, and known DOM patterns on the page at conversion time
The payload sent to Google’s conversion endpoint hasn’t changed shape. You still see the same em, pn, fn, ln, ct, rg, pc, co hashed parameters in the network request. What changed is the configuration surface, not the wire format.
The important practical difference: the automatic detection path is now the default. If your Method 2 setup was using explicit Data Layer mappings for reliability (because form scraping is fragile on SPAs and headless checkouts), the toggle alone won’t preserve that. You need to expand the advanced fields section and re-map manually, or push user_data via gtag('set') before the conversion event.
This is the single biggest gotcha. Teams flip the toggle, assume they’re done, and lose 30-60% of their enhanced conversion match rate because the automatic scraper can’t find the email on a Shopify thank-you page or a React-rendered confirmation view.
Step-by-step GTM audit before you migrate
Don’t touch the toggle until you’ve mapped everything. Here’s the audit I run on every account.
Step 1: Inventory all Google Ads conversion tags
In GTM, filter Tags by type = “Google Ads Conversion Tracking”. Export the list. For each tag, note:
- Conversion ID and Label
- Whether “Include user-provided data from your website” is checked
- Which variable is referenced (if any)
- Firing triggers
You’d be shocked how often I find three tags firing for the same purchase event because someone added a new one during a re-platform and never disabled the old.
Step 2: Trace every User-Provided Data variable
For each variable of type Google Ads User-Provided Data:
- Note whether it’s set to Automatic Collection or Manual Configuration
- If manual, document every field mapping (email → dlv.customer.email, phone → CSS selector on #phone-field, etc.)
- Test each Data Layer Variable to confirm it resolves in preview mode on a real conversion
Save this documentation somewhere. When the migration happens and something breaks, you’ll want the old mapping as a reference.
Step 3: Check for gtag(‘set’) calls outside GTM
Search your site source for user_data, gtag('set', and sha256. Any hits mean you have on-page code doing what the GTM variable was doing. This code will keep running after the migration and can conflict with the new toggle logic if the values disagree.
Step 4: Verify consent mode integration
If you’re running Consent Mode v2 (and if you’re in the EU or serving EU users, you should be), check that your user-provided data logic respects ad_user_data and ad_personalization consent states. Enhanced conversions require ad_user_data = granted. Firing hashed PII when a user has denied consent is a compliance problem that survives the migration untouched.
Our team documents these consent gates as part of every GTM implementation audit, and it’s the first place I look when match rates drop after a migration.
Step 5: Establish a baseline match rate
Before you change anything, screenshot the current Enhanced Conversions diagnostics in Google Ads:
- Go to Goals → Conversions → Summary
- Click into the conversion action
- Diagnostics tab → Enhanced conversions section
- Record the “conversions with enhanced conversions data” percentage over the last 7 and 28 days
Without this baseline, you have no way to know if the migration hurt you.
Verification workflow after flipping the toggle
Once you’ve migrated, verify in three places. Skipping any of these leaves blind spots.
Tag Assistant (real-time verification)
Load your site with Tag Assistant enabled, complete a test conversion, and inspect the Google Ads Conversion Tracking tag firing. Expand the tag details and look for:
emparameter present and 64 characters long (SHA-256 hex)pnparameter present if phone is expectedfn,ln,ct,rg,pc,copresent if you were mapping address fields- No plaintext PII visible in the outbound request
If you see raw email addresses in the network payload, your hashing is broken. Google will accept the request but the match will fail silently.
Google Ads diagnostics tab (24-72 hour verification)
Enhanced Conversions diagnostics update on a lag. After 48 hours, compare against your baseline:
| Metric | Healthy | Warning | Broken |
|---|---|---|---|
| Conversions with EC data | 80%+ | 50-79% | Below 50% |
| Match rate (approximate) | 60%+ | 40-59% | Below 40% |
| Health score | Good | Fair | Poor |
| Data quality alerts | None | 1-2 minor | Any major |
If you drop by more than 10 percentage points on “conversions with EC data” after migration, something is wrong with your data source, not the toggle.
Server-side sanity check with a network trace
For the truly cautious, capture a HAR file during a test conversion and grep for the doubleclick.net conversion request. Confirm the hashed values match what you’d compute independently:
# Compute the expected hash for comparison
echo -n "user@example.com" | shasum -a 256
# Should match the em= parameter in the conversion request
Note: values must be lowercased and trimmed before hashing. User@Example.com and user@example.com produce different hashes, and Google’s backend won’t normalise for you.
Common breakage patterns after migration
These are the failure modes I see repeatedly. Each one has a specific fix.
Hashed email mismatches
Symptom: Enhanced conversion data present but match rate collapses.
Cause: Double hashing. Your old Method 3 setup was already hashing email client-side, and the new toggle is treating that hashed string as a raw email and hashing it again. Google receives SHA256(SHA256(email)), which matches nothing.
Fix: If you’re supplying pre-hashed values, use the tag’s advanced field configuration and explicitly set the field format to “Hashed”. If you’re relying on automatic detection, remove the client-side hashing entirely and let the tag do it. Pick one path, not both.
Empty user_data on SPA checkouts
Symptom: EC data present on 20% of conversions instead of 80%+.
Cause: On single-page apps (React, Vue, headless Shopify), the confirmation page rarely contains the customer email in a scrapable form field. The automatic detector finds nothing. This kills Shopify Hydrogen, most headless setups, and any custom checkout.
Fix: Push user data explicitly. In your data layer, on the purchase event:
window.dataLayer.push({
event: 'purchase',
user_data: {
email_address: customer.email,
phone_number: customer.phone,
address: {
first_name: customer.firstName,
last_name: customer.lastName,
postal_code: customer.postalCode,
country: customer.country
}
},
ecommerce: { /* ... */ }
});
Then map these into the tag’s advanced user-provided data fields via Data Layer Variables. Automatic detection is a fallback, not a strategy. For Shopify specifically, our Shopify app work always pushes customer data explicitly on the thank-you event for this exact reason.
Consent mode blocking everything
Symptom: Zero enhanced conversion data after migration.
Cause: The consolidated tag respects consent signals more strictly than the old setup. If ad_user_data is denied or defaulted to denied and never updated, no user data is sent.
Fix: Audit your CMP integration. Confirm that granting marketing/advertising consent updates ad_user_data and ad_personalization to granted. Check with:
gtag('get', 'AW-XXXXXXXXX', 'consent_state', console.log);
Duplicate tags firing conflicting data
Symptom: Some conversions show EC data, others don’t, no clear pattern.
Cause: You have both an old on-page gtag('set', 'user_data', ...) and the new GTM tag with its own configuration. They race. Whichever fires last wins, and on slow connections that’s non-deterministic.
Fix: Kill the on-page implementation. Consolidate everything in GTM. This is what the toggle was designed to force, but Google won’t remove your legacy on-page code for you.
Address field normalisation failures
Symptom: Match rate is decent for email but terrible when address is included.
Cause: Address fields have strict normalisation rules that most implementations get wrong. Region must be a two-letter code or full name matching Google’s expected format. Postal codes must be uppercase for UK addresses. Country must be ISO 3166-1 alpha-2.
Fix: Normalise before pushing to the data layer:
const normalisedAddress = {
first_name: firstName.trim().toLowerCase(),
last_name: lastName.trim().toLowerCase(),
postal_code: postalCode.trim().toUpperCase().replace(/\s+/g, ''),
country: countryCode.trim().toUpperCase()
};
Common Mistakes and Troubleshooting
Flipping the toggle without auditing first. The toggle assumes automatic detection works on your site. On any non-trivial checkout, it doesn’t. Audit before you migrate.
Leaving legacy variables in place. Old Google Ads User-Provided Data variables that are no longer referenced still consume evaluation time and clutter your container. Delete them after migration is verified.
Not versioning your GTM container. Publish a named version (“Pre-EC-consolidation”) before making changes so you can diff or roll back. I’ve seen teams migrate on a Friday, break match rates, and spend the weekend trying to reconstruct the old configuration from memory.
Ignoring the Google Ads diagnostics lag. The diagnostics tab doesn’t reflect changes for 24-72 hours. Don’t panic and re-migrate on day one because the numbers haven’t updated.
Assuming Server-Side GTM setups are exempt. If you’re running SGTM with a Google Ads Conversion client, the same consolidation applies at the server tag level. User data still needs to reach the server container through the request payload or event data.
Testing with your own email. Google’s match graph won’t have your test email tied to a Google account with ad interaction history. Match rate on test data is meaningless. Only production traffic over a week or more tells you if the migration worked.
Not documenting the migration. Six months from now, someone will ask why enhanced conversions are configured a certain way. Write it down in your GTM change log or a shared runbook. Your future self will thank you.
Key Takeaways
- Identify which of the three legacy methods you used before touching the toggle. Automatic migration is not automatic if you had Manual Configuration mappings or client-side hashing.
- The toggle defaults to automatic detection, which fails on SPAs, headless checkouts, and most modern ecommerce. Push user data explicitly through the data layer and map it in the tag’s advanced fields.
- Baseline your match rate in Google Ads diagnostics before migrating. Without a baseline, you can’t measure the impact of the change.
- The three most common post-migration failures are double-hashing (from lingering Method 3 code), empty user data on SPAs, and consent mode blocking. Each has a specific fix, not a general one.
- Verify with Tag Assistant immediately, then Google Ads diagnostics 48-72 hours later. A drop of more than 10 percentage points in EC coverage means something broke.
- Delete legacy variables and on-page
gtag('set', 'user_data')calls after verification. The whole point of the consolidation is one path, not two paths racing each other.
Share this article