Nach ein paar Monaten Server Side Google Tag Manager Erfahrung zeigen sich die Bedürfnisse zur Nutzung der serverseitigen Lösung (ggf. In Kombination mit dem clientseitigen GTM) gegenüber der clientseitigen Lösung deutlich. Ein großer Vorteil ist die Kontrolle über die Weiterleitung von IP-Adressen vom serverseitigen Google Tag Manager zu den einzelnen Tools, die Daten erhalten. Um das zu demonstrieren, sehen wir uns den Outgoing Request eines Universal Analytics Tags im serverseitigen GTM an:
Bei diesem Request wird die IP des Users (IPv6) an den Request für Universal Analytics angehängt. In der Universal Analytics Real Time Ansicht erhalten wir die gewohnte Ansicht:
Um die Vorteile des serverseitigen Google Tag Manager hinsichtlich Datenschutz auszuspielen, kann die IP aus dem Request entfernt werden, indem der Parameter überschrieben wird. Seit kurzem ist dies auch direkt im Tag möglich:
Die IP Adresse ist dann nicht mehr im ausgehenden Request vorhanden:
Im Universal Analytics Real Time View wird nun keine Location mehr für den Hit angezeigt.
Geographische Informationen sind mit dem Entfernen der IP Adresse in Universal Analytics nicht mehr verfügbar, sofern diese nicht direkt im Request ergänzt werden. Universal Analytics nutzt hierfür Criteria IDs, die den Standort identifizieren und im Request mit dem Parameter “geoid” mitgegeben werden können. Die komplette Liste der Criteria IDs findet sich hier: http://developers.google.com/analytics/devguides/collection/protocol/v1/geoid.
Schicken wir nun eine Criteria ID (hier 1004234) im Hit mit:
Das Ergebnis im Real Time View:
Wir erhalten nun die Location auf Basis der Criteria ID.
Kurzer Exkurs:
Der Parameter geoid kann auch ISO 3166 ALPHA-2 Country Codes verarbeiten, also dem User das passende Land zuordnen. Im serverseitigen GTM kann dies im Header mit X-Appengine-Country ausgelesen werden:
Im Tag:
Im Request:
Im Universal Analytics Real Time View sieht es dann wie folgt aus:
Die Geo-Information zum Land ist also vorhanden, allerdings keine genaue Location.
Um die passende Criteria ID zu finden, wird nun als erstes das Sheet mit Latitude und Longitude versehen. Für den praktischen Einsatz ist es sinnvoll, Locations zu streichen wenn diese zu nah zusammen liegen (bspw. München und Taufkirchen) oder nicht gebraucht werden.
Mit den folgenden App-Script wird automatisiert der Canonical Name in Latitude und Longitude unter Nutzung der Google Maps API aufgelöst. Die Google Maps API über App Scripts hat ein striktes Limit von 1.000 Calls / 24h (G Workspace: 10.000 Calls / 24h):
function getLatLng() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var cells = range.getValues();
var latitudes = [];
var longitudes = [];
for (var i = 1; i < cells.length; i++) {
var address = cells[i][1];
var geocoder = Maps.newGeocoder().geocode(address);
var res = geocoder.results[0];
var lat = lng = 0;
if (res) {
lat = res.geometry.location.lat;
lng = res.geometry.location.lng;
}
latitudes.push([lat]);
longitudes.push([lng]);
console.log(i);
console.log(address);
console.log(res);
}
sheet.getRange('C2')
.offset(0, 0, latitudes.length)
.setValues(latitudes);
sheet.getRange('D2')
.offset(0, 0, longitudes.length)
.setValues(longitudes);
}
Das Ergebnis:
Nun muss nur noch die korrekte Criteria ID für den einzelnen User gefunden werden. Hierfür wird aus dem Request-Header im serverseitigen GTM Latitude und Longitude des Users ausgelesen und in X-AppengineCity-latlong (Beispielwert “48.135125,11.581981”) gespeichert.
In einem Variablen Template werden nun Criteria ID, Latitude und Longitude aus dem Sheet als einzelne Arrays hinterlegt, so das der Array-Index über die 3 Arrays Latitude, Longitude und Criteria ID abbildet. Das Ergebnis der Variable ist die Crieria ID, die die geringste Distanz von Latitude und Longitude zu den Werten in X-AppengineCity-latlong aufweist. Der serverseitige GTM unterstützt keine (noch nicht?) Sinus und Cosinus Funktionen, so das die Haversine Formel nicht einfach umgesetzt werden kann. Stattdessen wird einfach die absolute Distanz von Latitude mit der absoluten Distanz von Longitude addiert und unter allen Werte in Arrays vergleichen. Für den niedrigsten Wert wird der Array-Index festgehalten und somit entspricht dieser im Array aller Criteria ID der naheliegendsten Location.
Im Template Editor wird ein Feld „coords“ angelegt, das als Eingabe den Wert von X-AppengineCity-latlong erwartet:
Folgender Code, entsprechend dem o.g. Vorgehen, wird verwendet:
// Enter your template code here.
const log= require('logToConsole');
const Math= require('Math');
// Init Arrays
const geoid=["9048497","1004576","1004653","9048363","1004646","9048808","1004673","1004770","1004633","1004580",....];
const lat=["51.7864824","50.7753455","50.8649918","50.967168","51.0600381","50.919128","51.786726","50.8216502","51.679984","50.8715885",....];
const lng=["6.0098603","6.0838868","6.091241","6.1174584","6.1183729","6.1186928","6.12954","6.1320672","6.1565522","6.1648392",....];
//Split coords
const hitlat=data.coords.split(",")[0];
const hitlng=data.coords.split(",")[1];
// Init vars
var dist=9999999999;
var lata=9999999999;
var lnga=9999999999;
var len=geoid.length;
var j=false;
// find minimum
for(var x=0; x<len; x++)
{
if ((Math.abs(lat[x]-hitlat) + (Math.abs(lng[x]-hitlng)))<dist)
{
j=x;
dist=Math.abs(lat[x]-hitlat) + Math.abs(lng[x]-hitlng);
}
}
return geoid[j];
Nun wird mit diesem Template eine Variable erstellt.
Der Wert der Variable kann dann im Universal Analytics Tag genutzt werden.
Die Variable bei einem eingehenden Request:
Das Ergebnis in Google Analytics Real Time View:
Hinweise:
Da das Berechnen der Criteria ID Ressourcen im serverseitigen GTM bindet, ist es ratsam:
- Eine kurze Liste von Locations in den Arrays zu nutzen
- Häufige Locations bereits im voraus zu berechnen, anstatt durch da komplette Array zu iterieren. Array mit Top 50 Standorten zuerst durchsuchen und nur falls keiner davon eine Maximum-Abweichung unterschreitet, weitere Elemente berechnen
- Länder, in denen die Location-Ebene nicht interessiert, aus der Liste entfernen und den Country Code zurück liefert bevor das Array initialisiert wird.
- Offsets benutzen. Beim Durchsuchen des Arrays muss nicht am Anfang begonnen werden, wenn klar ist, das die relevanten Latitude / Longitude Werte erst bei späteren Elementen beginnen. Ebenso kann bei nicht mehr relevanten Werten die Suche abgebrochen werden. Hierfür ist eine auf die Locations angepasste Sortierung der Arrays ratsam.
- Am Anfang des Codes sollte geprüft werden, ob die Variable für den Request nicht benötigt wird. Falls nicht, kann einfach false zurückgegeben werden.
Hallo Marcus,
richtig guter Ratgeber!
Zum Verständnis nochmal:
1) Im eingehenden Requests reichert ja die App Engine die Daten neben „X-Appengine-Country“ auch mit „X-Appengine-City“ an.
2) „X-Appengine-Country“ könnte ich also benutzen, um das Land in GA zu sehen, da der Wert den ISO 3166 ALPHA-2 Country Codes entspricht und somit verarbeitet werden kann.
3) Über „X-Appengine-City“ bekomme ich ja die Stadt, die aber GA nichts bringt, da hier der umgekehrte Weg gegangen werden muss. Sprich geoid braucht die Criteria ID, mit der dann GA die Stadt, das Bundesland und das Land aufgelöst werden kann?
Worauf ich hinaus will: „X-Appengine-City“ über die geoid rüberzuschieben bringt keinen Nutzen?
VG
Demir
Hallo Demir,
genau. Universal Analytics akzeptiert als geoid entweder das Land im ISO 3166 ALPHA-2 Country Code Format oder die passende Criteria ID. Leider nicht direkt die Stadt, In GA4 können die Daten aus X-Appengine-City, Country, etc. direkt übergeben werden.
Viele Grüße
Hallo David,
die Lösung mit X-Headern wird vrstl. nur bei einem Hosting in der Cloud funktionieren. Die beste Option, meiner Meinung nach, ist es, die IP am Server per Datenbank aufzulösen und dann die Werte im GA4 Tag zu setzen. Datenbanken für IP zu Location sind bspw. https://www.ip2location.com/ oder https://www.maxmind.com/en/geoip2-services-and-databases.
Hallo Marcus,
das Auflösen der IP Adresse, etc. stellt für uns kein Problem dar. Was für uns gerade nicht nachvollziehbar ist, ist die Übermittlung des Standorts über den GTM z.B. als Criteria ID an Google Analytics 4. In deinem Beispiel übermittelst du die Daten an Universal Analytics mit dem Feld „geoid“. Das scheint bei der GA4 nicht mehr zu funktionieren. Wenn ich testweise ein neues Feld in meiner GA Config anlege mit dem Namen „geoid“ und einem festen Value (z.B. 1004234 wie in deinem Beispiel), erhalte ich in Analytics 4 keinen Standort für die Nutzer. Weist du ob sich in der Benennung von dem Feld „geoid“ eventuell etwas mit der GA4 geändert hat?
Viele Grüße, David