Skip to content

Instantly share code, notes, and snippets.

@mbaersch
Last active November 21, 2022 22:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mbaersch/e492ecfa1802b9736fefcc983b8b557f to your computer and use it in GitHub Desktop.
Save mbaersch/e492ecfa1802b9736fefcc983b8b557f to your computer and use it in GitHub Desktop.
Codebeispiele zu "cookielosem" Tracking mit Google Analytics
<?php
//Einfachster Fall: Es existiert schon eine Session, weil das System sie braucht. Dann reicht statt der folgenden Zeile ein einfaches
//session_start();
//Im anderen Fall steuern wir diue Optionen des Session Cookies selbst und können wahlweise
//"All In" gehen, wenn es um Schutz des Cookies vor ITP oder Lesen des Werts im Browser geht:
session_start(['cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => true]);
//Rückgabe der Session Id. Das war tatsächlich schon alles
echo session_id();
?>
<?php
//Erstellung eines Fingerprints und Rückgabe als Id. Siehe Hinweise am Ende des Beispiels
function anonymizeIp($ip) {
//IPV4/IPV6
return preg_replace(['/\.\d*$/','/[\da-f]*:[\da-f]*$/'],['.0','0000:0000'],$ip);
}
function get_fingerprint($i, $l, $a) {
//nicht nachvollziehbarer Hash aus anonymer IP, Sprache und User Agent
$in = $i . 'k1|' . $l . 'k2|' . $a . 's|';
$salt = 'S&6!l%aV<*MFy;~Uy9)t#^ygl';
return hash('md5', $in.$salt);
}
$lng = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if ($lng != "") $lng = explode(',', $lng)[0];
$agent = urlencode($_SERVER['HTTP_USER_AGENT']);
if (! isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$clientIp = anonymizeIp($_SERVER['REMOTE_ADDR']);
else
$clientIp = anonymizeIp($_SERVER['HTTP_X_FORWARDED_FOR']);
//Client Id als Fingerprint berechnen
$cid = urlencode(get_fingerprint($clientIp, $lng, $agent));
echo $cid;
/*
Zur Erklärung: Man kann verschiedenste Methoden einsetzen, um aus den hier verwendeten Merkmalen eine Kennung
zu generieren. Nicht alle sind gleich schnell oder erzeugen einen Schlüssel mit kontrollierbarer Länge. Hier erstellen
wir einen einfachen Hash, der aus den verketteten gewählten Merkmalen gebildet wird und eine konstante
Länge aufweist, was sich für eine ID gut eignet. Die Reihenfolge und Form der Verkettung ist ebenso willkürlich wie
veränderbar. Ob das die beste und "sicherste" Methode ist, um aus den Angaben eine Id zu bilden, kann ich nicht sagen -
dazu habe ich vom dem Thema zu wenig Ahnung, ganz ehrlich. Also dient dieser ganze Aufwand eigentlich eher der
Demonstration, dass man aus den gewählten Angaben eine Id erzeugen kann. Und ja: Das "Salt" ist als dem Server
bekannte Konstante eigentlich eher ein "Pepper". Geschenkt :)
*/
?>
//Beispielcode zum Blogbeitrag unter https://www.markus-baersch.de/blog/cookieloses-tracking-mit-google-analytics
/********************************************************************************************************************/
//Variante 1: SessionStorage verwenden, um zumindest eine Sitzung zur Zusammenfassung der Hits zu haben.
//localStorage ginge exakt genau so, würde aber nur technisch einen Unterschied zu einem Cookie mit nennenswerter
//Laufzeit bedeuten.
/********************************************************************************************************************/
function getNewSession() {
function getUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & amp; 0x3 | 0x8);
return v.toString(16);
});
}
var id = getUuid();
if (window.sessionStorage) sessionStorage.setItem('SESSID', id);
return id;
}
//Als Id generiert und speichert dieses Beispiel eine UUID, es geht aber natürlich auch jedes
//andere Verfahren zur Erstellung einer ausreichend eindeutigen Kennung.
window._clientId = (window.sessionStorage && sessionStorage.getItem('SESSID')) || getNewSession();
//Hier folgt der angepasste GA-Trackingcode, der die generierte ClientId verwendet und Cookies deaktiviert
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)}, i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-12345678-1', 'auto',
{'storage':'none',
'storeGac' : false,
'clientId': window._clientId
}
);
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
/********************************************************************************************************************/
//Variante 2: Serverseitige Verwaltung der Id bzw. Nutzung eines Session-Cookies, das für JS im Browser unsichtbar ist
/********************************************************************************************************************/
//Hinweis: Der folgende Code könnte auch kürzer sein, hat aber zwei Vorteile. Erstens wird bei evtl. Problemen mit dem
//Abruf der Client ID nur ein Versuch vorgenommen. Im Fehlerfall kann zudem wahlweise kein Tracking erfolgen oder alle
//Aufrufe mit solchen Problemen werden auf einer "Müllsammler-ID" gesammelt. Dazu dient eine Funktion, die sich im
//Bedarfsfall selbst aufruft, um erst die ID abzurufen und dann zu übertragen (siehe Kommentare im Code). An die Stelle
//eines normalen Trackingcodes kann also diese Konstruktion gesetzt werden - nicht die einzige, aber eine mögliche Lösung.
//Er ersetzt den kompletten Codeblock eines normalen Trackingcodes, deshalb wird auch am Ende ein Aufruf dieser Funktion
//angefügt, um die Funktion auszuführen und den akt. Seitenaufruf zu vermessen.
function initTracking() {
if (window.XMLHttpRequest) req = new XMLHttpRequest();
if (!req == null) return; //ist eine Client ID da? Sonst erst am Server anfordern
if (!window._clientId && !window._clientReq) {
req.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
window._clientReq = true;
window._clientId = this.responseText;
initTracking();
}
};
req.open("GET", "/getclient.php", true);
req.send();
} else if ((!window._clientId || (window._clientId == ""))
&& window._clientReq === true) {
//Es konnte keine Client ID bezogen werden.
window._clientId = "1138-42-0815";
//Ersatzhit mit Konstante als Client ID absetzen (oder folgende Zeile auskommentieren)
initTracking();
} else {
//Hier folgt wieder wahlweise der angepasste GA-Trackingcode, der die generierte ClientId
//verwendet und Cookies deaktiviert und oder ein Push in den dataLayer für den Tag Manager (s. u.)
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)}, i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-12345678-1', 'auto',
{'storage':'none',
'storeGac' : false,
'clientId': window._clientId
}
);
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
//optional - wenn kein direktes Tracking benötigt wird - kann die Id nun über den dataLayer bereitgestellt
//werden und der GTM nutzt diese Id und die Felder storage und storeGac analog zu obigem Trackingcode zum
//Tracking ohne (eigene) Cookies. Benennung von Variable und Event sind beliebig:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'clientIdReady',
'srvClientId': window._clientId
});
}
}
//Auslösen des gerade stattgefundenen Seitenaufrufs
initTracking();
@mbaersch
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment