Lead forms and CRMs can represent the same email with leading spaces, mixed case, plus aliases, Unicode characters, internationalized domains, or a later corrected value. Teams sometimes strip everything after a plus sign or remove dots from every provider before hashing. That can merge distinct mailboxes, disagree with the stored lead, and make browser, server, CRM, and Google uploads impossible to reconcile.
Use this for Google Ads enhanced conversions for leads sent from WordPress forms, CRMs, offline uploads, the Google Ads API, or Data Manager API.
Quick answer
Preserve the raw submitted email in the protected lead record, capture consent and source timestamps, and derive a separate normalized field. Follow Google's documented normalization before SHA-256. Do not remove plus tags or dots unless the current official contract explicitly requires that provider-specific transformation. Build fixtures for spaces, case, plus tags, multiple dots, Unicode local parts, internationalized domains, invalid syntax, changed CRM values, and consent denied. Compare the exact normalized bytes and lowercase hexadecimal hash at form, server, CRM, queue, and upload boundaries.
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Whitespace | SP User@Example.com SP | Trim and lowercase by contract |
| Plus alias | user+demo@example.com | Preserve unless contract says otherwise |
| Gmail dots | first.last@gmail.com | Apply only documented rule |
| Consent denied | Valid email | No hash or upload |
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence | Verification |
| Define the current Google contract | Map raw email, validated email, normalized email, hash encoding, consent state, lead ID, click ID, CRM contact ID, and upload job ID. | Every fixture produces the expected normalized bytes and lowercase hexadecimal hash. |
| Preserve raw and derived fields separately | Create fixtures for leading and trailing spaces, mixed case, plus aliases, dots, subdomains, Unicode, IDN domains, invalid syntax, blanks, and duplicates. | WordPress, CRM, queue, and upload records agree on the source value and lead ID. |
| Run provider and Unicode fixtures | Compare browser and server capture, WordPress storage, CRM formatting, deduplication, queue serialization, and Google upload payloads. | Plus, dot, Unicode, IDN, corrected-value, and invalid branches are documented. |
| Keep identifiers stable end to end | Test a lead whose email is corrected after submission and define which timestamped value owns each conversion event. | Denied consent produces no hash, upload, or sensitive debug record. |
What to check first
- Map raw email, validated email, normalized email, hash encoding, consent state, lead ID, click ID, CRM contact ID, and upload job ID.
- Create fixtures for leading and trailing spaces, mixed case, plus aliases, dots, subdomains, Unicode, IDN domains, invalid syntax, blanks, and duplicates.
- Compare browser and server capture, WordPress storage, CRM formatting, deduplication, queue serialization, and Google upload payloads.
- Test a lead whose email is corrected after submission and define which timestamped value owns each conversion event.
- Suppress hashing and upload when consent or business policy does not permit the processing, and keep the suppression reason auditable.
Field notes
- Write the expected result before changing anything and keep one repeatable synthetic fixture for the full test window.
- Record exact versions and UTC timestamps because caches, retries, scheduled actions, and deployments can change the evidence between checks.
- Test the public path and the stored server-side result, not only an admin preview, isolated command, or API response.
- Review the result again after the relevant cache, queue, cron, webhook, and observation window has completed.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
fixture,raw,normalized,sha256_hex,consent
space_case," User@Example.com "
plus_alias,user+demo@example.com
gmail_dot,first.last@gmail.com
unicode,josé@exämple.test
denied,user@example.com,,,denied
Why this usually happens
- A CRM applies mailbox-provider rules that the WordPress collector does not.
- A developer hashes before trimming and lowercasing, so visually identical values differ.
- The normalized value is overwritten when a salesperson edits the contact later.
- A debug log stores raw email, normalized email, and hash together.
Decision rule
Never add a mailbox-provider shortcut because it improves one match. The normalized bytes must follow the current Google contract and remain reproducible from the consented source value used for that lead event.
Production verification checklist
- Every fixture produces the expected normalized bytes and lowercase hexadecimal hash.
- WordPress, CRM, queue, and upload records agree on the source value and lead ID.
- Plus, dot, Unicode, IDN, corrected-value, and invalid branches are documented.
- Denied consent produces no hash, upload, or sensitive debug record.
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Define the current Google contract
- Preserve raw and derived fields separately
- Run provider and Unicode fixtures
- Keep identifiers stable end to end
- Audit consent and log redaction
Mistakes to avoid
- Changing production before recording exact versions, UTC timestamps, a stable fixture, the expected result, and a tested rollback point.
- Treating one successful screen as proof while logs, stored records, background jobs, caches, emails, APIs, and downstream systems remain unchecked.
- Testing only as an administrator instead of using the role, device, locale, cache state, request path, and failure branch that users actually reach.
- Leaving debug output, temporary exclusions, helper accounts, duplicate hooks, broad permissions, or relaxed firewall rules active after verification.
Questions teams ask during testing
Can I test this directly in production?
Start with read-only evidence. Use staging for code, package, security, checkout, form, privacy, or cache changes. If a production canary is necessary, make it identifiable, reversible, monitored, and incapable of exposing personal data or charging a customer.
How do I avoid a false positive?
Repeat the same fixture with the same versions, URL, role, locale, cache state, and downstream integration. Compare the public result, stored result, and logs instead of relying on one browser view.
What evidence should I retain?
Keep UTC time, exact versions, request or record ID, expected result, actual result, relevant log lines, change made, rollback point, owner, and final verification. Redact credentials, tokens, and personal data.
When is the work complete?
Close it when the primary path passes, failure branches are understood, stored and downstream records reconcile, temporary changes are removed, monitoring is active, and the owner has the evidence packet.
What to tell the client or owner
Give the owner a concise packet with the affected workflow, exact versions, UTC test time, synthetic fixture ID, expected result, actual result, key logs, change made, rollback point, final result, unresolved risks, owner, and next review date. Remove credentials and personal data before sharing it.
When HandL WP should help
Bring in help when this affects leads, checkout, search visibility, security, paid media reporting, or a client production site. HandL WP can trace the issue through WordPress, hosting, cache, tracking, and Search Console, then verify the workflow after the technical fix.
If this is active on a production site, have HandL WP verify enhanced conversions for leads.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references