Ein Blog über Code, Hardware und Co

Wordpress und Webentwicklung

Outbound-Traffic ohne Analytics tracken

Wie du auf jeder Seite mittels JavaScript und PHP auch ohne Google Analytics deinen ausgehenden Traffic (ausgehende Linkklicks) messen kannst.

Wenn man an Analyse von Nutzerverhalten auf Webseiten oder schlicht das Besuchertracking auf Webseiten denkt, kommt man in der Regel nicht an Analytics vorbei. Das gilt ebenso für so schlichte Anforderungen wie das Tracken von Klicks auf externe Links.

Aber google Analytics ist ein Monolith, die eierlegende Wollmilchsau, die ein absoluter Overkill für das simple Tracking von Linkklicks ist.

Zudem ist die Verwendung von google Analytics aus Datenschutzgründen und vor dem Hintergrund der DSGVO nicht ganz ohne.

Daher wollen wir in diesem Beitrag unseren eigenen kleinen Link-Klick-Tracker bauen, der ohne Cookies oder datenschutzrechtlich problematische Libraries auskommt.

Erste Überlegungen: Verwendete Technologien

Wir werden für unseren Linktracker zwei der wohl am weitesten verbreiteten Technologien im WWW nutzen: JavaScript und PHP.

JavaScript wird clientseitig ausgeführt und ruft bei jedem Linkklick ein PHP-Skript auf, das nun serverseitig die übermittelten Daten verarbeitet.

Die Daten speichern wir der Einfachheit halber in einer SQLite-Datenbank und machen sie damit persistent. Bei größeren Webseiten kann diese Lösung schnell ineffizient werden, dort sollte man dann auf ein Datenbanksystem mit DBMS, wie beispielsweise MySQL zurückgreifen.

Was wollen wir tracken?

Ebenfalls essenziell sind die Überlegungen, was soll unsere Lösung eigentlich leisten? Ich möchte mit meiner Lösung folgende Werte/Kennzahlen erfassen, wie oft welche externen Links in einem bestimmten Zeitfenster und auf welcher Seite geklickt wurden.

Also z.B.: “Im Monat Januar wurde der externe Link zu Wikipedia auf meiner Unterseite XY 32 mal aufgerufen.”

Dafür muss ich zu jedem Linkklick folgende Werte speichern:

  • Die Seite, auf der geklickt worden ist (“REFERRER”)
  • Das Ziel des externen Links (“URL”)
  • Den Zeitpunkt des Linkklicks (“TIMESTAMP”)
  • Optional: Die Beschreibung des Links/Buttons (“TEXT”)

Interne Linkklicks sind für mich eigentlich nicht so interessant, ggf. werden wir diese später herausfiltern.

Die ersten Schritte: Das JavaScript-Snippet

Wir brauchen zunächst ein JavaScript-Snippet, dass beim Kick auf einen Link ausgelöst wird.
Dieses Script muss alle relevanten, oben aufgeführten Daten (bis auf den Timestamp) aus dem DOM (also der Webseite) auslesen und an das serverseitig verarbeitende PHP-Skript weitergeben.

Das geht wie folgt.

Wir erstellen zunächst einmal eine JavaScript-Funktion, die beim OnClick-Event bei einem Link aufgerufen werden soll. Diese Funktion kriegt später bei einem Click, das entsprechende Event als Objekt übergeben (evt).

<script>
function external_click(evt){
    let obj = evt.target;
    
    var page = window.location.href;
    var linktext = obj.innerHTML;
    var url = obj.getAttribute("href");
    
    console.log(page);
    console.log(linktext);
    console.log(url);

    $.ajax({
         url: '/external-click.php',
         type: 'POST',
         data: {
             'page': page,
             'url': url,
             'linktext': linktext
         },
         success: function (data) {
                console.log(data);   
         },
         error: function(jqxhr, status, exception) {
             console.log('Exception:', exception);
         }
     })
}
</script>

Die Datenweitergabe erfolgt dann per Ajax im JSON-Format (der Abschnitt hinter $.post). So könnte die Belegung der Variablen beispielhaft aussehen:

{
"page":"https://addictedtocode.de/unterseitexy/",
"url":"https://wikipedia.de",
"linktext":"Hier gehts zu Wikipedia"
}
Was ist eigentlich Ajax?
Ajax steht für "Asynchronous JavaScript and XML" und ermöglicht es einer Webseite asynchrone Requests abzusetzen. So können Daten nachgeladen oder an den Server geschickt werden, ohne dass ein sichtbarer Seitenreload notwendig wäre.
Webseiten können so wesentlich dynamischer gestaltet werden. 

Speichern der Daten in einer SQLite-Datenbank

Der große Vorteil von SQLite ist, dass die ganze Datenbank in einem File im Dateisystem, liegt und wir kein zusätzliches DBMS installieren müssen, wo wir uns zunächst mir einer Datenbank verbinden müssen usw.

Tipp: Dieser Vorteil kann schnell zum Nachteil werden, vor allem wenn die gespeicherten Daten zu groß werden oder komplexe Operationen auf der Datenbasis durchgeführt werden sollen. Dann sind Queries bei einer Datenbank mit DBMS (Datenbank Management System) wie MySQL WESENTLICH performanter.

Wie auch immer, wir bleiben bei der lean-Lösung. Trotzdem müssen wir unsere Datenbank zunächst erstellen. Dazu schreiben wir uns ein kleines Install-Skript:

install.php

<?php

#Datenbank im Document-Root erstellen
$db_handle = new SQLite3("externalclicks.db");

#Tabelle zum Speichern der Éxternen Klicks erstellen
$sqlCreateTable = "CREATE TABLE IF NOT EXISTS clicks(page TEXT, url TEXT, linktext TEXT, time TEXT)";

# Go for it: Ausführen
$db_handle->exec($sqlCreateTable);

# Print that we are done
echo 'Datenbank unter folgendem Pfad erstellt:<br>';
echo $_SERVER['DOCUMENT_ROOT'];

?>

Die Datei führen wir nun einmal aus, indem wir sie über den Browser aufrufen. Die Ausgabe sieht im Optimalfall wie folgt aus:

Bild: Erfolgsmeldung für die Erstellung einer SQLite Datenbank.

Jetzt erstellen wir unsere PHP-Datei, die bei jedem Klick einen entsprechenden Datensatz in die Datenbank schreibt:

external-click.php

<?php

#Wir wollen keine Cross-Site-Scripting Attacken zulassen (XSS), daher lassen wir nur Abfragen/Einträge von der eigenen Domain zu.
if( strpos( $_SERVER['HTTP_REFERER'], 'https://addictedtocode.de' ) !== 0 ) {
die( "Dieses Skript darf nur von der eigenen Domain aufgerufen werden!" );
}

#Außerdem soll das Skript nur weiter ausgeführt werden, wenn die entsprechenden POST-Parameter gesetzt sind
if(!empty($_POST["page"]) && !empty($_POST["url"]) && !empty($_POST["linktext"])){

#Zur Datenbank verbinden
$db_handle = new SQLite3('externalclicks.db');

#Jetzt lesen wir die entsprechend übermittelten Daten aus dem $_POST-Array aus. 
$page = SQLite3::escapeString($_POST["page"]);
$url = SQLite3::escapeString($_POST["url"]);
$linktext = SQLite3::escapeString($_POST["linktext"]);
#$url = "test";
#$linktext = "test";

#Datensatz in die Datenbank eintragen
#Nur eintragen, wenn Linktext ohne https://addictedtocode.de, also extern
$search = "https://addictedtocode.de";
$pos = strpos($url,$search);
if($pos === false){
        $db_handle->exec("INSERT INTO clicks(page, url, linktext, time) VALUES('$page','$url','$linktext',datetime('now','localtime'))");
}

}

?>

Jetzt müssen wir noch dafür sorgen, dass unsere JavaScript-Funktion als EventListener an jeden Link auf einer Webseite (also jedes a-Tag) angehangen wird.

Dafür bedienen wir uns wieder JavaScripts und der dort vorhandenen Funktion “getElementsByTagName”:

jQuery(document).ready(function(){
   var elements = document.getElementsByTagName('a');
   for(var i = 0, len = elements.length; i < len; i++) {
       elements[i].addEventListener("click", external_click);
   }
});

Fertig!

Ab sofort wird jeder Link auf der Webseite mit einem zusätzlichen EventListener versehen, der beim Linkklick unsere Funktion auslöst, die dann die jeweiligen Werte per AJAX an das PHP-Skript weitergibt, das dann wiederum die Werte in unsere Datenbank schreibt.

Auslesen und auswerten

Wir können schauen, ob das Script funktioniert, indem wir den Inhalt der Datenbank auf der Konsole ausgeben:

sqlite3 external_clicks.db "SELECT * FROM clicks;"

Das Ergebnis sieht dann z.B. so aus:

https://Addictedtocode.de|https://wikipedia.de|Linktext|2022-01-15 01:13:40

Natürlich kann man sich auch ein PHP-Skript bauen, dass die Auswertung etwas besser leserlich macht 😉

Was ist eigentlich JSON? 
JSON steht für "JavaSctipt Object Notation". Es handelt sich dabei um ein Format zur Übertragung von Daten.
Die Daten werden in JavaScript als Objekt verpackt und in einer standardisierten Notation aufgeschrieben. Mit dieser Notation können die Daten dann an andere Schnittstellen übergeben werden, dort aus der Notation gelesen und weiterverarbeitet werden.

JSON ist weit verbreitet zur Konfiguration von Diensten oder zur Kommunikation mit APIs.

Schreibe eine Antwort