Blog
sGTM has built-in geo headers from the request infrastructure. They are good enough for most use cases.
When you need country or region for an incoming request, the obvious instinct is to call MaxMind, IPStack, or another commercial geo-IP service. Before doing that, check the request headers; sGTM inherits geo data from its hosting infrastructure, and for most use cases it is accurate enough.
When sGTM runs on Google App Engine (the SprTags-managed setup), incoming requests include these headers automatically:
| Header | Example value |
|---|---|
| X-AppEngine-Country | FR, US, JP |
| X-AppEngine-Region | 75 (Paris department code) |
| X-AppEngine-City | paris (lowercase, ASCII) |
| X-AppEngine-CityLatLong | 48.864716,2.349014 |
return {
country: getRequestHeader('x-appengine-country'),
region: getRequestHeader('x-appengine-region'),
city: getRequestHeader('x-appengine-city'),
latlong: getRequestHeader('x-appengine-citylatlong')
};
Country: nearly always correct. Google's geo-IP database is well-maintained and updated regularly. Region: usually correct but with occasional misclassifications for VPN traffic. City: correct for major cities, less reliable for smaller ones. Lat/long: precision is approximate (city-level), not GPS-level.
For analytics use cases, country and region are accurate enough. For ad targeting that needs zip-code precision, you need a commercial service.
Geo data derived from IP is generally not considered PII at the country level, becomes more sensitive at city level, and is fully PII at the lat/long level. If you anonymise IP early, the geo data should be derived before anonymisation and stored separately.
Three triggers: you need ASN/ISP data (App Engine does not provide this), you need IPv6 accuracy that App Engine misses, or you have compliance requirements that demand a documented commercial geo provider with audit trails.
For everyone else, the built-in headers are free and sufficient. Save the integration cost for somewhere it actually matters.