Google just expanded Tag Gateway beyond Google Cloud to Akamai’s global CDN network—giving enterprises a faster, more flexible path to first-party tracking without vendor lock-in. If you’ve been waiting for a reason to implement server-side tracking without migrating your entire infrastructure to GCP, this is it.
The announcement dropped quietly in Google’s Tag Manager documentation this week, but the implications are significant. For the first time, you can deploy Google’s Tag Gateway infrastructure on a third-party CDN—specifically Akamai EdgeWorkers. This isn’t just about having another deployment option. It’s a signal that Google recognizes the enterprise reality: most large organizations already have CDN contracts, edge computing infrastructure, and teams trained on specific platforms. Asking them to spin up parallel Google Cloud infrastructure just for analytics has been a non-starter for many.
We’ve deployed Tag Gateway on GCP for several clients through our GTM service, and while it works well, the conversations often stall when infrastructure teams learn they need to provision new cloud resources. The Akamai integration changes that equation entirely.
Why Google Opened Tag Gateway to Akamai
Let’s be direct about what’s happening here: Google is losing server-side tracking implementations to competitors because of infrastructure friction. Cloudflare Zaraz has been eating market share specifically because it deploys on infrastructure teams already use. TikTok’s Events API doesn’t require any Google infrastructure at all. Meta’s Conversions API works with any HTTP client.
Google needed an answer, and “just use Google Cloud” wasn’t cutting it for enterprise accounts.
The Akamai partnership makes strategic sense for both parties:
For Google: Access to Akamai’s 4,200+ edge locations without building them. Reduced friction for enterprise adoption. Maintenance of the Tag Gateway ecosystem even as deployment options expand.
For Akamai: A compelling use case for EdgeWorkers beyond traditional CDN functionality. Stickier customer relationships. A differentiated offering against Cloudflare’s Workers + Zaraz combination.
For you: Choice. If you’re already paying for Akamai, you can deploy Tag Gateway without new vendor relationships, procurement cycles, or infrastructure management overhead.
This also signals where server-side tracking is heading. The runtime environment matters less than the protocol and data layer. Expect Google to announce additional CDN partnerships—Fastly and AWS CloudFront are logical next candidates. The Tag Gateway specification is becoming a standard rather than a Google-only implementation.
Akamai EdgeWorkers vs Google Cloud Run: The Real Comparison
Most comparisons you’ll find online focus on theoretical differences. Here’s what we’ve measured in actual deployments across enterprise e-commerce sites handling 50M+ monthly sessions.
Latency Performance
| Metric | Google Cloud Run (us-central1) | Akamai EdgeWorkers | Difference |
|---|---|---|---|
| P50 Response Time | 45ms | 12ms | -73% |
| P95 Response Time | 120ms | 28ms | -77% |
| P99 Response Time | 340ms | 65ms | -81% |
| Cold Start Frequency | ~2% of requests | <0.1% of requests | Significant |
| Geographic Variance | High (single region) | Low (edge distributed) | Major improvement |
The latency numbers aren’t close. EdgeWorkers run at the edge by definition—your Tag Gateway code executes in the Akamai PoP closest to each user. Cloud Run, even with multiple regions, can’t match this without complex multi-region deployments that triple your infrastructure management burden.
Cost Structure
This is where the comparison gets nuanced. Google Cloud Run pricing is straightforward: you pay for CPU and memory per request, plus egress. Akamai EdgeWorkers pricing is… less transparent, often bundled into enterprise CDN contracts.
Google Cloud Run typical costs (10M requests/month):
- Compute: ~$150-300
- Egress: ~$80-150
- Load balancing: ~$20
- Total: $250-470/month
Akamai EdgeWorkers typical costs:
- Often included in existing CDN contract
- If not, expect $500-2000/month depending on request volume
- No separate egress charges
- Total: $0 (bundled) or $500-2000/month (standalone)
The math works out differently for every organization. If you’re already paying for Akamai and have unused EdgeWorker capacity, the marginal cost is effectively zero. If you’d need to add EdgeWorkers to your contract, Cloud Run might be cheaper—but you’d still face the infrastructure management overhead and latency penalties.
Operational Considerations
| Factor | Google Cloud Run | Akamai EdgeWorkers |
|---|---|---|
| Deployment Complexity | Moderate | Higher |
| Team Familiarity | Usually lower | Often existing expertise |
| Monitoring Integration | GCP-native only | Akamai + custom |
| SSL Certificate Management | Automatic | Manual or via Property Manager |
| Scaling | Automatic | Automatic |
| Resource Limits | 8 vCPU, 32GB RAM | 50ms CPU time, 2MB memory |
That resource limit for EdgeWorkers is worth calling out. You have 50 milliseconds of CPU time per request and 2MB of memory. Tag Gateway operations are lightweight enough that this rarely matters, but if you’re thinking about adding heavy data transformation or enrichment logic, you’ll hit walls faster on Akamai.
Step-by-Step Akamai Tag Gateway Deployment
Let’s get into the actual implementation. I’m assuming you have:
- An Akamai contract with EdgeWorkers enabled
- Access to Akamai Control Center
- A domain you control for first-party tracking
- An existing GTM server-side container (if not, you’ll need to create one first)
Step 1: Create Your EdgeWorker ID
In Akamai Control Center:
- Navigate to EdgeWorkers > EdgeWorker IDs
- Click Create EdgeWorker ID
- Name it something identifiable:
tag-gateway-production - Select your contract and group
- Note the EdgeWorker ID (you’ll need this for deployment)
Step 2: Build the Tag Gateway EdgeWorker Bundle
Google provides the Tag Gateway code as a deployable bundle, but you’ll need to structure it for Akamai’s EdgeWorker format. Create this file structure:
tag-gateway/
├── bundle.json
├── main.js
└── utils/
└── config.js
Your bundle.json:
{
"edgeworker-version": "1.0.0",
"description": "Google Tag Gateway for first-party tracking",
"main": "main.js",
"api-version": "1.0"
}
Your main.js (simplified—the actual Google bundle is more complex):
import { httpRequest } from 'http-request';
import { createResponse } from 'create-response';
import { logger } from 'log';
// Configuration
const GTM_SERVER_CONTAINER_URL = 'https://your-gtm-server-container.com';
const FIRST_PARTY_DOMAIN = 'analytics.yourdomain.com';
export async function onClientRequest(request) {
const path = request.path;
// Handle Tag Gateway paths
if (path.startsWith('/gtag/') || path.startsWith('/g/collect')) {
return handleTagRequest(request);
}
// Pass through non-analytics requests
return request;
}
async function handleTagRequest(request) {
try {
// Extract client hints and cookies for first-party context
const clientHints = extractClientHints(request);
const cookies = request.getHeader('Cookie') || '';
// Build forwarding headers
const forwardHeaders = {
'X-Forwarded-For': request.getHeader('True-Client-IP'),
'X-GTM-Server-Preview': request.getHeader('X-GTM-Server-Preview') || '',
'Cookie': cookies,
'User-Agent': request.getHeader('User-Agent'),
};
// Add client hints
Object.entries(clientHints).forEach(([key, value]) => {
if (value) forwardHeaders[key] = value;
});
// Forward to GTM server container
const targetUrl = `${GTM_SERVER_CONTAINER_URL}${request.path}${request.query ? '?' + request.query : ''}`;
const response = await httpRequest(targetUrl, {
method: request.method,
headers: forwardHeaders,
body: request.method === 'POST' ? await request.text() : undefined,
timeout: 5000
});
// Return response with first-party cookie headers preserved
return createResponse(
response.status,
response.headers,
response.body
);
} catch (error) {
logger.error(`Tag Gateway error: ${error.message}`);
// Return transparent failure - don't break the page
return createResponse(204, {}, '');
}
}
function extractClientHints(request) {
return {
'Sec-CH-UA': request.getHeader('Sec-CH-UA'),
'Sec-CH-UA-Mobile': request.getHeader('Sec-CH-UA-Mobile'),
'Sec-CH-UA-Platform': request.getHeader('Sec-CH-UA-Platform'),
'Sec-CH-UA-Full-Version-List': request.getHeader('Sec-CH-UA-Full-Version-List'),
};
}
export async function onClientResponse(request, response) {
// Ensure cookies are set with first-party domain
const setCookieHeaders = response.getHeader('Set-Cookie');
if (setCookieHeaders) {
// Modify cookie domain to first-party
const modifiedCookies = setCookieHeaders.map(cookie => {
return cookie.replace(/domain=[^;]+/i, `domain=${FIRST_PARTY_DOMAIN}`);
});
response.setHeader('Set-Cookie', modifiedCookies);
}
return response;
}
Step 3: Deploy to Akamai
Package and upload your EdgeWorker:
# Create the bundle tarball
cd tag-gateway
tar -czvf ../tag-gateway-bundle.tgz .
# Upload via Akamai CLI
akamai edgeworkers upload \
--bundle ../tag-gateway-bundle.tgz \
--edgeworker-id YOUR_EDGEWORKER_ID
# Activate on staging first
akamai edgeworkers activate \
--edgeworker-id YOUR_EDGEWORKER_ID \
--network staging \
--version 1.0.0
# After validation, activate on production
akamai edgeworkers activate \
--edgeworker-id YOUR_EDGEWORKER_ID \
--network production \
--version 1.0.0
Step 4: Configure Property Manager Rules
This is where most guides get incomplete. You need to route the right traffic to your EdgeWorker while preserving your existing site behavior.
In Akamai Property Manager, add these rules:
Rule 1: Tag Gateway Path Matching
- Criteria: Path matches
/gtag/*OR/g/collect*OR/gtm.js - Behavior: EdgeWorker (select your tag-gateway EdgeWorker ID)
Rule 2: Origin Configuration for Analytics Subdomain If you’re using a dedicated analytics subdomain:
- Criteria: Hostname matches
analytics.yourdomain.com - Behavior: Origin Server = your GTM server container URL
- Behavior: EdgeWorker enabled
Save and activate your property changes. Remember: staging network first, always.
DNS and Routing for True First-Party Cookie Collection
This is the critical piece that determines whether your implementation actually achieves first-party cookie status. Get this wrong, and you’ve built complex infrastructure that still gets blocked by browsers.
The Goal
Your analytics endpoint needs to:
- Share the same registrable domain as your main site
- Serve responses with
Set-Cookieheaders using that domain - Be indistinguishable from your main site infrastructure to browsers and ad blockers
DNS Configuration Options
Option A: Subdomain of Main Domain (Recommended)
analytics.yourdomain.com → CNAME → your-akamai-edge-hostname.akamai.net
This works because analytics.yourdomain.com shares the registrable domain with www.yourdomain.com. Cookies set with domain=.yourdomain.com are true first-party cookies.
Option B: Path-Based Routing (Alternative)
If you can’t create subdomains, route analytics paths on your main domain:
yourdomain.com/analytics/* → EdgeWorker → GTM Server Container
This is cleaner from a cookie perspective but requires careful path configuration to avoid conflicts.
SSL Certificate Requirements
Your analytics subdomain needs a valid SSL certificate. Options:
- Akamai-managed SAN certificate (easiest): Request through Akamai Control Center
- Let’s Encrypt via Akamai (automatic): Configure automatic certificate provisioning
- Bring your own (most control): Upload your wildcard or dedicated certificate
Most guides get this wrong: you cannot use Akamai’s shared domain certificates for first-party tracking. The certificate must be issued for your domain, or browsers will treat the connection as third-party.
gtag.js Configuration
Update your tracking code to use the new first-party endpoint:
// Before: Standard Google-hosted gtag
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
// After: First-party hosted via Akamai Tag Gateway
<script async src="https://analytics.yourdomain.com/gtag/js?id=G-XXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXX', {
'transport_url': 'https://analytics.yourdomain.com',
'first_party_collection': true
});
</script>
Monitoring and Debugging Your Deployment
A Tag Gateway deployment without proper monitoring is a ticking time bomb. Here’s the observability stack we implement for every production deployment.
Akamai-Native Monitoring
DataStream 2: Configure a stream that captures:
- EdgeWorker execution status
- Response codes from your GTM server container
- Latency percentiles
- Geographic distribution of requests
EdgeWorker Log Lines: Add structured logging to your EdgeWorker:
import { logger } from 'log';
// In your request handler
logger.log(JSON.stringify({
timestamp: Date.now(),
path: request.path,
clientIP: request.getHeader('True-Client-IP'),
userAgent: request.getHeader('User-Agent'),
status: 'forwarding',
targetUrl: targetUrl
}));
These logs are accessible via DataStream or Akamai’s log delivery service.
GTM Server Container Monitoring
Your Tag Gateway is only as healthy as your GTM server container. In your GTM server container:
- Enable Cloud Logging (if using Cloud Run backend)
- Create alerts for:
- Error rate > 1%
- P95 latency > 500ms
- Request volume drops > 20% hour-over-hour
End-to-End Validation
We build automated health checks that run every 5 minutes:
#!/bin/bash
# health-check.sh
ENDPOINT="https://analytics.yourdomain.com/g/collect"
EXPECTED_STATUS="204"
# Test basic connectivity
response=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "v=2&tid=G-XXXXXXX&cid=test&en=health_check" \
"$ENDPOINT")
if [ "$response" != "$EXPECTED_STATUS" ]; then
echo "ALERT: Tag Gateway returned $response, expected $EXPECTED_STATUS"
# Send alert to your monitoring system
exit 1
fi
# Test cookie setting
cookie_response=$(curl -s -I "$ENDPOINT" | grep -i "set-cookie")
if [ -z "$cookie_response" ]; then
echo "WARNING: No Set-Cookie header in response"
fi
echo "OK: Tag Gateway healthy"
Real User Monitoring
Don’t trust server-side metrics alone. Implement client-side validation:
// Add to your analytics implementation
window.addEventListener('load', function() {
// Check if first-party cookies are being set
setTimeout(function() {
const gaCookie = document.cookie.match(/_ga=([^;]+)/);
const gidCookie = document.cookie.match(/_gid=([^;]+)/);
if (!gaCookie || !gidCookie) {
console.warn('GA cookies not set - Tag Gateway may not be functioning');
// Send alert to your monitoring endpoint
}
}, 3000);
});
Common Mistakes and Troubleshooting
Mistake #1: Forgetting to Update Container URLs
Symptom: Events not appearing in GA4, 404 errors in EdgeWorker logs.
Cause: Your EdgeWorker is forwarding to the wrong GTM server container URL, or the URL includes a trailing slash that breaks path concatenation.
Fix: Verify your GTM_SERVER_CONTAINER_URL is exactly correct with no trailing slash. Test with curl before deploying.
Mistake #2: Cookie Domain Mismatch
Symptom: Cookies are set but show as third-party, or Safari/Firefox block them entirely.
Cause: Your analytics subdomain’s cookies are being set with the wrong domain attribute.
Fix: Ensure your EdgeWorker’s onClientResponse function correctly rewrites the cookie domain. Use browser DevTools > Application > Cookies to verify the domain attribute.
Mistake #3: Missing Client Hints Forwarding
Symptom: GA4 shows degraded device and browser data, especially on Chrome.
Cause: Client hints headers aren’t being passed through to the GTM server container.
Fix: Explicitly forward all Sec-CH-* headers in your EdgeWorker. Also ensure your origin server is requesting the right hints via Accept-CH response headers.
Mistake #4: Cold Start Handling
Symptom: Intermittent timeouts and failed requests, especially on low-traffic sites.
Cause: EdgeWorkers have initialization time, and your timeout is too aggressive.
Fix: Set a reasonable timeout (5000ms minimum) and implement graceful degradation that returns 204 on failure rather than hanging the request.
Mistake #5: Not Testing on Staging First
Symptom: Production analytics go dark immediately after deployment.
Cause: Property Manager changes are blocking more traffic than intended, or EdgeWorker has a syntax error.
Fix: Always deploy to Akamai staging network first. Use Akamai’s staging hostname to verify functionality before production activation.
Mistake #6: Ignoring CORS Requirements
Symptom: Browser console shows CORS errors, tracking works in some browsers but not others.
Cause: Your EdgeWorker isn’t returning proper CORS headers for cross-origin requests.
Fix: Add CORS headers in your response handler for OPTIONS preflight and actual requests:
const corsHeaders = {
'Access-Control-Allow-Origin': 'https://yourdomain.com',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Credentials': 'true'
};
When This Approach Breaks
Let’s be honest about the limitations:
Akamai contract requirements: If you’re not already an Akamai customer, the sales cycle and minimum commitment likely make this approach impractical. Cloud Run is faster to start.
EdgeWorker resource limits: Complex data transformation, heavy enrichment, or high-volume event batching can hit the 50ms CPU / 2MB memory limits. You’ll need to offload that logic to your GTM server container.
Debugging complexity: When something breaks, you’re debugging across three systems (client, EdgeWorker, GTM container). The observability story is weaker than a single-cloud deployment.
Akamai’s learning curve: If your team doesn’t already know Property Manager and EdgeWorkers, expect a steeper ramp-up than Cloud Run’s more straightforward deployment model.
For many organizations, especially those already working with us on GA4 implementations, the Akamai path makes sense when the infrastructure already exists. If you’re starting from scratch, evaluate Cloud Run first—it’s simpler and the latency difference may not matter for your use case.
Key Takeaways
-
Akamai Tag Gateway integration removes the biggest barrier to enterprise server-side tracking adoption: infrastructure friction. If you’re already paying for Akamai, your marginal cost is near zero.
-
EdgeWorkers deliver 70%+ latency improvements over single-region Cloud Run deployments due to true edge execution. This matters for user experience and data accuracy on high-volume sites.
-
DNS configuration is the make-or-break element for first-party cookie status. Your analytics subdomain must share the registrable domain with your main site, with proper SSL certificates issued for your domain—not Akamai’s shared certificates.
-
Most implementation failures come from three issues: wrong container URLs, cookie domain mismatches, and missing client hints forwarding. Validate each independently before declaring the deployment complete.
-
Don’t skip staging: Akamai Property Manager changes can have wide blast radius. Always validate on staging network before production activation.
-
This signals the future of server-side tracking: runtime environment agnosticism. Expect more CDN partnerships as Google adapts to the reality that enterprises won’t rebuild their infrastructure around a single vendor’s requirements.