Pixels
Google Ads Enhanced Conversions for South Africa.
Enhanced Conversions send hashed first-party data (email, phone, name, address) alongside the standard Google Ads conversion so Google can match signed-in users across devices. For South African merchants losing iOS 17 and ITP signal, this typically recovers 10 to 15 percent of unreported conversions and makes Smart Bidding behave again. This guide covers both modes: Enhanced Conversions for Web (tag-based) and via API (server-side), with SA-specific data normalisation.
Prerequisites
- A working Google Ads conversion action (see the Google Ads guide)
- Data access to email and phone on the thank-you page, or in the order webhook
- Google Ads Customer Data Terms accepted in your Ads account
- Shopify Customer Events access, or server endpoint for API mode
Step 1. Accept the Customer Data Terms
Google Ads > Tools > Conversions > Settings > Customer data terms. You cannot enable Enhanced Conversions until this is signed. The terms require that you have consent or another lawful basis to share the data with Google — under POPIA, that means marketing consent from the shopper.
Step 2. Turn on Enhanced Conversions on the conversion action
Open the Purchase conversion > Enhanced conversions > Turn on > Google tag. Pick "Automatic collection" to have Google scrape the page for email / phone fields, or "Manual" to pass explicit user_data in the tag. Manual is more reliable for Shopify because the thank-you DOM changes across themes.
Step 3. Send hashed user_data from Shopify Customer Events (Web mode)
Hash SA email and phone client-side before sending. Google expects SHA-256 hex. Phone must be E.164 (+27...) without spaces or dashes.
async function sha256(v) {
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(v.trim().toLowerCase()));
return [...new Uint8Array(buf)].map(b => b.toString(16).padStart(2, '0')).join('');
}
function normalisePhoneZA(p) {
const digits = (p || '').replace(/[^0-9]/g, '');
if (digits.startsWith('27')) return '+' + digits;
if (digits.startsWith('0')) return '+27' + digits.slice(1);
return '+' + digits;
}
analytics.subscribe('checkout_completed', async (event) => {
const c = event.data.checkout;
const cust = c.order.customer;
const user_data = {};
if (cust?.email) user_data.sha256_email_address = await sha256(cust.email);
if (cust?.phone) user_data.sha256_phone_number = await sha256(normalisePhoneZA(cust.phone));
const addr = c.shippingAddress || {};
const address = {};
if (cust?.firstName) address.sha256_first_name = await sha256(cust.firstName);
if (cust?.lastName) address.sha256_last_name = await sha256(cust.lastName);
if (addr.address1) address.sha256_street_address = await sha256(addr.address1);
address.city = addr.city || '';
address.region = addr.provinceCode || ''; // e.g. 'WC'
address.postal_code = addr.zip || '';
address.country = 'ZA';
user_data.address = [address];
gtag('event', 'conversion', {
send_to: 'AW-XXXXXXXXX/abc123XYZ',
value: Number(c.totalPrice.amount),
currency: c.totalPrice.currencyCode,
transaction_id: String(c.order.id)
});
gtag('set', 'user_data', user_data);
}); Step 4. Send hashed user_data via GTM server-side (preferred)
For stronger reliability and POPIA clarity, send user_data through GTM server-side to the Google Ads Conversion Tag. This keeps raw email off the client. The client fires the conversion with just transaction_id; GTM server attaches user_data server-side using the order webhook.
Step 5. Configure API mode for offline conversions
If your sales close over the phone or via bank transfer (Ozow / EFT), upload conversions via the Google Ads API with user_data attached. Upload within 24 hours for the conversion to attribute to the original click. Check current Google Ads API docs for the latest version — versions bump every few months.
# Using Google Ads API uploadClickConversions
# Replace CUSTOMER_ID, CONVERSION_ACTION_ID, ACCESS_TOKEN, DEV_TOKEN
curl -X POST \
"https://googleads.googleapis.com/v16/customers/CUSTOMER_ID:uploadClickConversions" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "developer-token: YOUR_DEV_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"conversions": [{
"gclid": "GCLID_FROM_ORIGINAL_CLICK",
"conversionAction": "customers/CUSTOMER_ID/conversionActions/CONVERSION_ACTION_ID",
"conversionDateTime": "2026-04-15 10:30:00+02:00",
"conversionValue": 1499.00,
"currencyCode": "ZAR",
"userIdentifiers": [{"hashedEmail": "SHA256_LOWERCASE_HEX"}]
}],
"partialFailure": true
}' Step 6. Normalise SA addresses before hashing
Google hashes name + address too, so normalise. Lowercase, trim whitespace, collapse double spaces. For SA province, use the two-letter ISO region codes: WC (Western Cape), GT (Gauteng), KZN, EC, FS, LP, MP, NC, NW. Anything else (like "gauteng") reduces match quality.
Step 7. Monitor Diagnostics for match rate
Conversion action > Diagnostics tab. Aim for above 70 percent match rate. Below 50 percent means your hashing is wrong — usually an unnormalised phone (missing +27) or a typo in the sha256 hex encoding (uppercase instead of lowercase).
Step 8. Document the POPIA basis
In your privacy policy, disclose that you share hashed personal identifiers with Google Ads for measurement and that the lawful basis is consent collected via the cookie banner. Add the Google Ads Data Processing Terms to your PAIA register.
SA gotchas
- Hashes must be SHA-256 hex lowercase. SA developers who reach for btoa (base64) break match quality silently.
- SA phone numbers with leading zero ("0821234567") are not E.164. Google expects "+27821234567" — normalise before hashing.
- Automatic mode tries to scrape the DOM but Shopify's thank-you page lazy-loads customer data. Manual mode is more reliable.
- Match rate below 40 percent usually means you hashed raw lowercase+trim but kept spaces or a trailing newline. Audit one sample hash with the Google tool.
- Enhanced Conversions without POPIA marketing consent is a DPO incident waiting to happen. Gate it behind the same consent bit you use for the base Ads tag.
Frequently asked questions
Is Google Ads Enhanced Conversions POPIA compliant?
With consent, yes. You collect marketing consent, hash the identifiers, share with Google under the Customer Data Terms. Raw PII never leaves the merchant if done correctly.
Will Enhanced Conversions recover iOS 17 signal?
Partially. Expect 10 to 15 percent recovery on iOS. It is strongest on signed-in Google users (Chrome on Android) and weakest on Safari private browsing.
Do I also need Meta CAPI?
They are independent. Enhanced Conversions is Google-side only. If you advertise on Meta, CAPI is the equivalent recovery tool there.
How do I verify my hashes are correct?
Paste a known email into a SHA-256 tool online and compare the hex output to what your code produces. Look for trimming, lowercase, and hex-vs-base64 bugs.