Ich engagiere mich im Moment ehrenamtlich für die Webseite eines Vereins und stand in diesem Zusammenhang vor der Aufgabe das Webanalysetool Matomo Analytics datenschutzkonform in die bestehende WordPress Instanz einzufügen.

Über Matomo soll das Verhalten der Nutzer auf Basis anonymisierter Daten analysiert werden um die Verwendung der Seite besser zu verstehen und dann entsprechend Ansatzpunkte für eine Verbesserung der Website zu gewinnen.

Matomo bietet grundsätzlich zwei verschiedene Wege um abhängig vom Einverständnis des Nutzers das Tracking zu steuern: Opt-Out und Consent.

Doch was ist der Unterschied und welcher Weg ist der bessere?

Matomo Opt-Out

Beim Opt-Out Verfahren handelt es sich um eine “Widerspruchslösung”, d.h. Matomo erfasst die Aktionen des Besuchers, bis dieser aktiv der Erfassung widerspricht. Die Information hinsichtlich der Erfassung findet sich dabei in aller Regel in der Datenschutzerklärung. Teilweise nutzen Webseiten auch die Möglichkeit schon im Cookie-Layer auf die Erfassung hinzuweisen.

Zum Opt-Out bietet Matomo als Bordmittel eine iFrame-Lösung, die einfach über HTML eingebunden werden kann. Da bei der Vereinswebsite das WordPress Matomo Plugin im Einsatz ist, kann auch ein Shortcode genutzt werden: [matomo_opt_out].

Um das Styling des iFrames etwas an die eigene Website anzupassen, können Farben, Schriftarten und Dimensionen konfiguriert werden. Zudem kann die Sprache eingestellt werden. Hier ein Beispiel mit den verfügbaren Optionen:

[matomo_opt_out language=de background_color=red font_color=fff font_size=34 font_family=Arial width=500px height=100px]

Wer nicht das WordPress Plugin nutzt, kann auch im Matomo Backend den entsprechenden iFrame-Code konfigurieren und in die Website einfügen:

<iframe style="border: 0; height: 200px; width: 600px;" src="https://www.employeesforfuture.org/wp-content/plugins/matomo/app/index.php?module=CoreAdminHome&action=optOut&language=de&backgroundColor=e8ece6&fontColor=0f1b07&fontSize=15px&fontFamily=Segoe%20UI%2C%20Helvetica%2C%20sans-serif"></iframe>

Die Darstellung auf der Website erfolgt dann in folgender Weise:

Matomo Opt Out

Durch einen Klick auf die Checkbox kann man das Opt-Out auslösen und somit der Nutzung von Matomo widersprechen, woraufhin sich das iFrame neu lädt, mit entsprechendem Text, der zum erneuten Opt-In einlädt sowie passender Checkbox.

Die Texte sind hierbei vorgegeben, können aber bei Bedarf über die Matomo Extension Custom Opt Out angepasst werden.

Unschön an iFrames ist, dass diese schlecht mit responsiven Layouts funktionieren. Dafür gibt es verschiedene JavaScript-Lösungen, die die Größe des iFrames dynamisch an die Fenstergröße anpassen, zum Beispiel in dieser Weise:

<div>
<script type="text/javascript">
function makeIframeResponsive() {
  var iFrameID = document.getElementById('iframe-matomo');
  if (iFrameID) {
    iFrameID.height = "";
    iFrameID.height = (iFrameID.contentWindow.document.body.scrollHeight+24) + "px";
  }   
}
</script>
<iframe id="iframe-matomo" onload="makeIframeResponsive()" allowfullscreen="" style="border: none; min-height:200px; width:100%; margin: 0 0 0 1%;" src="https://www.employeesforfuture.org/wp-content/plugins/matomo/app/index.php?module=CoreAdminHome&action=optOut&language=de&backgroundColor=e8ece6&fontColor=0f1b07&fontSize=15px&fontFamily=Segoe%20UI%2C%20Helvetica%2C%20sans-serif"></iframe>
</div>

(Quelle: https://www.knothemedia.de/iframe-responsive-gestalten.html)

Insgesamt funktioniert diese Lösung zuverlässig, allerdings ist das iFrame etwas friemelig und die Integration in die Website nicht optimal. Es gibt natürlich auch die Möglichkeit ein eigenes Opt-Out mit JavaScript zu erstellen.

Problematischer ist da schon die Tatsache, dass die Lösung aus Datenschutz-Sicht nicht ideal ist, weil der Besucher ja getrackt wird, bevor das Opt-Out stattfindet. Es ist also nicht möglich dem Tracking vollständig zu entgehen. Das ist nicht verwunderlich, da es sich ja um eine Widerspruchsregelung handelt.

Aktuell ist – soweit ich das sagen kann – juristisch umstritten, ob dies mit der DSGVO im Einklang ist, konkreter ob es im legitimen Interesse des Seitenbetreibers ist Informationen zum Besuchsverhalten zu erheben oder ob eine explizite Zustimmung für diese Art der Datenverarbeitung erforderlich ist.

Matomo Consent: Opt-In

Um diesem Risiko aus dem Weg zu gehen, kann man Matomo so konfigurieren, dass ausschließlich Nutzer mit erteilter Einwilligung vom Tracking erfasst werden.

Mit dem sogenannten Consent bietet Matomo eine alternative Möglichkeit zur Steuerung an. Wichtig ist hierbei zu wissen, dass beide Funktionen vollständig unabhängig von einander arbeiten, sich also nicht beeinflussen. Für den Einsatz auf der Website sollte man sich daher für eine Variante entscheiden.

Da das Standard-Verhalten von Matomo auf Opt-Out ausgerichtet ist, ist für die Nutzung des Consents eine manuelle Erweiterung des Matomo-Script-Codes erforderlich. Dafür muss gleich zu Beginn (auf jeden Fall vor trackPageView) die Funktion _paq.push(['requireConsent']); eingefügt werden.

<!-- Matomo -->
<script type="text/javascript">
var _paq = window._paq || [];
_paq.push(['requireConsent']); // erfordert Zustimmung des Nutzers
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
_paq.push(['setTrackerUrl', "\/\/www.employeesforfuture.org\/wp-content\/plugins\/matomo\/app\/matomo.php"]);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src="\/\/www.employeesforfuture.org\/wp-content\/uploads\/matomo\/matomo.js"; s.parentNode.insertBefore(g,s);
</script>
<!-- END Matomo -->

Damit trackt Matomo nun zunächst gar nicht mehr, weil ja kein Nutzer sein Opt-In gegeben hat. Um dies zu erreichen, habe ich einen Cookie-Banner auf Basis der WordPress Erweiterung Cookie Notice implementiert.

Das Plugin ist relativ einfach aufgebaut. Es gibt die Möglichkeit einen Text sowie Buttons und die Position des Cookie-Layers zu konfigurieren. Das ganze funktioniert auch responsiv und bietet eine gute Grundlage für das Opt-In.

Zur Steuerung der Funktion gibt es einen sogenannten Script-Blocking Bereich, dh. die in diesem Bereich angegebenen Scripte werden erst nach dem Akzeptieren des Cookie-Layers ausgeführt. Das ist also genau die Stelle, an der nun das Matomo Consent gesetzt werden soll. Dafür ist es nur erforderlich beim Klick auf OK die Funktion _paq.push(['rememberConsentGiven']); aufzurufen.

Damit wird ein persistentes Cookie mtm_consent gesetzt und Matomo erkennt daran, dass die Erfassung freigegeben wurde. Zusammen mit dem Hinweis auf die Matomo Webanalyse im Cookie-Layer ist das Opt-In dann DSGVO-konform.

Wunderbar. Das war ja einfach. Oder hmm.. fehlt da noch was?

Matomo Consent: Opt-Out

Die DSGVO sieht auch vor, dass Benutzer der einmal gegebenen Einwilligung auch wieder widersprechen können. Wir brauchen also einen Weg sich bei Bedarf wieder abzumelden. Zum Glück hat Matomo auch hier vorgesorgt und bietet die Funktion _paq.push(['forgetConsentGiven']); an, mit der das Opt-In Cookie gelöscht wird. Außerdem wird dabei das Opt-Out im Cookie mtm_consent_removed dauerhaft gespeichert.

Um die Funktion auszulösen, kann diesmal nicht auf Bordmittel zugegriffen werden, daher bedarf es einer eigenen Implementierung. Dafür habe ich zum vermutlich ersten Mal eine Klasse in JavaScript geschrieben :)

Die Steuerung des Opt-Outs erfolgt hierbei über einen Infotext und einen Button, die in die Datenschutz-Seite integriert wird. Durch Klick auf den Button wird die Matomo Funktion aufgerufen und es erfolgt ein automatischer Reload der Seite. Auf gleichem Weg ist anschließend auch ein erneutes Opt-In möglich. Die Texte werden dabei entsprechend automatisch angepasst:

<div>
<p id="mtm-consent-state">(Matomo Consent Status)</p>
<a id="mtm-consent-button" class="cn-button bootstrap" onclick="">(Matomo Consent Status ändern)</a>
<script type="text/javascript">
class MatomoConsent {

constructor(dom_selector_text, dom_selector_button) {
  this.setConsentText(dom_selector_text);
  this.setConsentButtonText(dom_selector_button);
  this.setConsentButtonAction(dom_selector_button);
}

static getCookie(cname) {
  var name = cname + "=";
  var decodedCookie = decodeURIComponent(document.cookie);
  var ca = decodedCookie.split(';');
  for(var i = 0; i <ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

static getConsentState() {
// wenn mtm_consent gesetzt --> aktiv
if (MatomoConsent.getCookie('mtm_consent')) {
  return true;
}
// wenn mtm_consent_revoked gesetzt --> inaktiv
if (MatomoConsent.getCookie('mtm_consent_removed')) {
  return false;
}
// wenn nichts gesetzt ist, entscheidet der Status des Cookie-Layers
  return ("true" == MatomoConsent.getCookie('cookie_notice_accepted'));
}

setConsentText(dom_selector) {
  document.querySelector(dom_selector).innerText = MatomoConsent.getConsentState()
    ? 'Aktuell ist die Nutzung von Matomo für Sie aktiviert. Sie haben die Möglichkeit der Nutzung zu widersprechen, indem Sie diesen Button klicken:'
    : 'Aktuell ist die Nutzung von Matomo für Sie deaktiviert. Sie können uns helfen die Nutzung zu aktivieren und unsere Website zu verbessern, indem Sie diesen Button klicken:';
}

setConsentButtonText(dom_selector) {
  document.querySelector(dom_selector).innerText = MatomoConsent.getConsentState()
    ? 'Webanalyse deaktivieren'
    : 'Webanalyse aktivieren';
}

setConsentButtonAction(dom_selector) {
  document.querySelector(dom_selector).onclick = MatomoConsent.getConsentState()
    ? function() { MatomoConsent.revokeConsent() }
    : function() { MatomoConsent.giveConsent() }
}

static revokeConsent() {
  var _paq = window._paq || [];
  _paq.push(['forgetConsentGiven']);
  location.reload();
}

static giveConsent() {
  var _paq = window._paq || [];
  _paq.push(['rememberConsentGiven']);
  location.reload();
}

}

mc = new MatomoConsent('p[id=mtm-consent-state]', 'a[id=mtm-consent-button]');
</script>
</div>

Die Steuerung erfolgt hierbei über die jeweils gesetzten Cookies und der Reload sorgt dafür, dass die Änderungen sofort aktiv werden. Das funktioniert sehr gut und sieht auch besser aus als das iFrame des normalen Opt-Outs:

Mein Matomo Consent Opt-Out

Ok, das sieht alles sehr gut aus. Damit sollte meine Aufgabe doch erfüllt sein.

Matomo Consent: Opt-In Reloaded

Nun.. nicht ganz. Es gibt noch ein Problem, wenn der Nutzer das Cookie-Banner aktiviert hat und dann über das Consent Opt-Out seine Zustimmung widerruft. Da dann wird trotzdem noch der Script-Blocking Teil ausgeführt und das oben verwendete _paq.push(['rememberConsentGiven']); setzt ein neues Opt-In.

Demnach könnte man Matomo nur widersprechen, wenn dem Cookie-Layer insgesamt widersprochen wird. Das mag sinnvoll sein, wenn man nur einen Dienst über das Cookie-Banner steuern möchte. Möchte man jedoch perspektivisch mehrere Dienste über das Opt-In aktivieren und diese dann selektiv deaktivieren können, funktioniert es auf diesem Weg nicht.

Ich habe daher entschieden den Script-Blocking Bereich so anzupassen, dass er die persistenten Cookies berücksichtigt. Falls keine Consent Cookies existieren wird anhand des Status des Cookie-Banners über _paq.push(["setConsentGiven"]); nur der aktuelle Aufruf für das Tracking freigegeben:

<!-- Matomo -->
<script type="text/javascript">
function getCookie(cname) {
  var name = cname + "="; var decodedCookie = decodeURIComponent(document.cookie); var ca = decodedCookie.split(';');
  for(var i = 0; i <ca.length; i++) {
    var c = ca[i]; while (c.charAt(0) == " ") { c = c.substring(1); }
    if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); }
  }
  return "";
}
if ( (!getCookie("mtm_consent")) && (!getCookie("mtm_consent_removed")) ) {
  var _paq = window._paq || [];
  _paq.push(["setConsentGiven"]); 
}
</script>
<!-- END Matomo -->

Es gilt also, was der Besucher bewusst auf der Datenschutz-Seite ausgewählt hat. Hat er dort keine Wahl getroffen, gilt die Zustimmung im Cookie-Banner – sofern er sie erteilt hat. In allen Fällen wird der Nutzer vor dem Tracking also gefragt und kann sich aktiv für oder gegen die Nutzung von Matomo entscheiden.

Das sollte nun auch jeden noch so kritischen Datenschutzbeauftragten zufrieden stellen. Oder gibt es etwa noch mehr zu beachten? Hmm.. ein wenig :)

Weitere Datenschutz-Einstellungen

Unabhängig vom Opt-In/Opt-Out-Verhalten sind einige Einstellungen sinnvoll um Matomo datenschutzkonform einzusetzen. Vor allem die Anonymisierung der IP-Adresse ist wichtig, damit auf diesem Weg keine personenbezogenen Daten erfasst werden. Insgesamt habe ich folgende Konfigurationen vorgenommen:

  • alle IPs werden anonymisiert (2 Oktetts)
  • Anonymisierung auch bei die Ermittlung der Geolocation (dadurch wird die Standorterfassung leider deutlich ungenauer)
  • “Do not Track” wird berücksichtigt (als weiteres Opt-Out)
  • alte Rohdaten und Berichte werden nach bestimmtem Zeitablauf gelöscht

Sollte Matomo nicht auf einem selbst betriebenen Webserver gehostet sein, ist zudem ein Vertrag zur Auftragsdatenverarbeitung mit dem Hoster erforderlich.

Fazit

Wer Matomo zur Webanalyse auf seinem Server einzusetzen will, sollte sich gut überlegen, ob er auf die Widerspruchslösung setzt oder die Zustimmung seiner Nutzer bewusst einholt. In beiden Fällen gibt es einiges zu beachten.

Während die Widerspruchslösung durch das iFrame relativ einfach integriert ist, bedarf der Consent Ansatz einer eigenen Implementierung. Das ist für Betreiber ggf. eine höhere Hürde, dafür ist man damit aber rechtlich auf der sicheren Seite.

Im Zweifel sollte man hier professionellen Rat suchen, vor allem wenn man wirtschaftliche Ziele mit seiner Website verfolgt. Sonst könnte irgendwann eine Abmahnung für Verstöße gegen die DSGVO durch einen Wettbewerber die Folge sein.

Das betrifft die Vereinswebsite vermutlich nicht, trotzdem ist es gut auch hier alle Anforderungen zu erfüllen. Achso.. wenn ihr mal schauen wollt, die Seite und die beschriebene Lösung findet ihr hier: https://www.employeesforfuture.org/