Server-Side GTM + Google Ads Setup Guide
I see broken server-side GTM setups for Google Ads in about 60% of accounts I audit. The most common mistake? People think they can just flip the switch to server-side and everything magically works. It doesn’t. You need proper container architecture, correct API endpoints, and field mapping that actually matches what Google expects.
The data quality improvement is worth it though — I typically see 15-25% more conversion data when server-side is configured correctly.
What You’ll Have Working By The End
- Server-side GTM container properly hosted and configured for Google Ads
- Conversion tracking sending from your server to Google Ads via Measurement Protocol
- Enhanced conversions working server-side with hashed customer data
- Cross-domain measurement configured for multi-domain setups
- Debug tools showing successful data transmission to Google
Prerequisites
- Existing web GTM container with Google Ads conversion tracking
- Google Cloud Platform account (or AWS/Azure if using custom hosting)
- Google Ads account with admin access
- Access to your website’s backend/server for customer data integration
- Basic understanding of APIs and server infrastructure
Step 1: Deploy Your Server-Side GTM Container
First, you need somewhere to run your server container. Google Cloud Run is the easiest option.
In Google Cloud Console:
- Enable the Cloud Run API
- Go to GTM → Admin → Container Settings → Server Container
- Click “Automatically provision tagging server”
- Select your GCP project and region
- Choose “Cloud Run” as deployment target
This gives you a tagging server URL like https://your-container-abcdef.a.run.app
For custom hosting, you’ll deploy the GTM server container image:
docker run -d -p 8080:8080 \
-e CONTAINER_CONFIG="your-container-config-string" \
gcr.io/cloud-tagging-10302018/gtm-cloud-image
The container config string comes from your server container settings in GTM.
Step 2: Configure Your Web Container to Send to Server
In your web GTM container, you need to route events to your server instead of directly to Google Ads.
Create a new Google Ads Conversion Tracking tag:
- Tag Type: Google Ads Conversion Tracking
- Conversion ID: Your existing conversion ID
- Conversion Label: Your existing label
- Transport URL:
https://your-container-abcdef.a.run.app
The transport URL tells the web container to send data to your server instead of directly to Google.
Do this for ALL your Google Ads tags — conversion tracking, remarketing, enhanced conversions.
Step 3: Set Up Server-Side Tags
In your server container, create tags that receive web data and forward it to Google Ads.
Create a Google Ads Conversion Tracking tag (server-side version):
- Tag Type: Google Ads Conversion Tracking
- Conversion ID: Same as your web tag
- Conversion Label: Same as your web tag
- Trigger: Client Name equals “Google Analytics”
The server tag receives the event from your web container and forwards it to Google using the Measurement Protocol.
For enhanced conversions, add these fields to your server tag:
// User-provided data fields
email: {{Email}}, // Variable pulling from customer data
phone: {{Phone}},
first_name: {{First Name}},
last_name: {{Last Name}},
street: {{Street Address}}
Step 4: Configure Data Layer and Customer Data
Server-side enhanced conversions need customer data. You have two options:
Option 1: Send from web container Push customer data to the data layer on conversion pages:
dataLayer.push({
'event': 'purchase',
'transaction_id': 'T12345',
'value': 99.99,
'currency': 'USD',
'customer_data': {
'email': 'customer@example.com',
'phone': '+1234567890',
'first_name': 'John',
'last_name': 'Smith'
}
});
Option 2: Enrich server-side (preferred) Use a Custom Tag template or webhook to pull customer data based on transaction ID:
// In your server container custom tag
const transactionId = data.transaction_id;
const customerData = await fetchCustomerData(transactionId);
// Send to Google Ads with enriched data
const enrichedEvent = {
...originalEvent,
user_data: {
email_address: sha256(customerData.email),
phone_number: sha256(customerData.phone),
first_name: sha256(customerData.first_name),
last_name: sha256(customerData.last_name)
}
};
I prefer option 2 because it keeps PII off the client-side and ensures data consistency.
Step 5: Handle Cross-Domain Tracking
If you have multiple domains, configure your server container to handle cross-domain client IDs.
In your server container, create a Client ID variable that checks for:
_gacookie valueclient_idURL parameter- Fallback to generated UUID
// Server-side Client ID logic
function getClientId() {
const gaCookie = getCookieValues('_ga')[0];
if (gaCookie) {
return gaCookie.split('.').slice(-2).join('.');
}
const urlClientId = getRequestQueryParameter('client_id');
if (urlClientId) {
return urlClientId;
}
return generateRandom(1000000000, 9999999999) + '.' + Math.floor(Date.now() / 1000);
}
Set this Client ID in all your Google Ads server tags to maintain user identity across domains.
Testing & Verification
Server Container Debug:
- In GTM server container, enable Preview mode
- Send a test conversion from your website
- Verify the event appears in server Preview with correct data structure
- Check that your Google Ads server tag fires successfully
Google Ads Verification:
- Go to Google Ads → Tools → Conversions
- Check “Recent conversions” — server-side conversions should appear within 2-4 hours
- Verify conversion values and attribution match expected data
- For enhanced conversions, check the “Enhancement” column shows “Yes”
Data Quality Check: Compare conversion counts between:
- Server container debug logs
- Google Ads conversion reporting
- Your internal order/lead tracking
Acceptable variance is 5-15%. Higher variance indicates data loss or double-counting.
Enhanced Conversions Debug:
Use Google Ads conversion tracking tag helper or check the Network tab for successful POST requests to https://googleadservices.com/conversion/ with em, ph, fn, ln parameters present and properly hashed.
Troubleshooting
Problem: Server container shows successful tag fires but no conversions in Google Ads
Solution: Check your Measurement Protocol payload format. Google Ads requires specific field names (tid for conversion ID, t for transaction type). Use the Google Ads server tag template, don’t build custom Measurement Protocol calls.
Problem: Enhanced conversions showing “No” in Google Ads despite sending customer data Solution: Verify customer data is properly hashed with SHA256 and formatted correctly. Email should be lowercase, phone numbers should include country code. Use GTM’s built-in hashing functions, not custom JavaScript.
Problem: High data variance (>20%) between server logs and Google Ads reporting Solution: Check for duplicate firing. If your web container still has direct Google Ads tags AND server tags, you’re double-sending. Remove direct tags from web container once server-side is working.
Problem: Cross-domain conversions not attributing correctly
Solution: Ensure your Client ID logic is consistent across all domains. Use the same _ga cookie format and pass client_id in cross-domain links. Check that your server container is using the unified Client ID for all Google Ads events.
Problem: Server container timing out or returning 500 errors Solution: Check your hosting resource limits. Cloud Run default timeout is 300 seconds — increase if you’re doing heavy data enrichment. For custom hosting, ensure sufficient CPU/memory allocation.
Problem: Conversion values showing as 0 in Google Ads despite sending correct values
Solution: Verify your currency format matches Google Ads expectations. Use 3-letter currency codes (USD, not $) and decimal values (99.99, not $99.99). Check that your value variable in server container is numeric, not string.
What To Do Next
Once your server-side setup is working, you can expand to other platforms and add more sophisticated data enrichment:
- Set up Facebook Conversions API with Server-Side GTM for cross-platform consistency
- Add more customer data fields for better enhanced conversions matching
- Implement audience syncing for remarketing improvements
Having issues with your server-side tracking setup? I audit tracking implementations daily and can spot configuration issues fast. Get a free tracking audit — I’ll review your server container and identify exactly what’s broken.
This guide is part of the Complete Server-Side GTM Hub — your resource for moving beyond client-side tracking limitations.