Matomos Screenshot-Erfassung läuft in zwei Schritten ab, und genau zwischen den beiden geht es schief.
Beim Seitenaufruf serialisiert Matomos Tracking-JavaScript das DOM in einen HTML-String (über eine Bibliothek namens TreeMirror) und schickt ihn an deinen Matomo-Server. Der rendert dann dieses HTML, um das Hintergrundbild zu erzeugen, das du in der Heatmap-Ansicht siehst.
Das Kernproblem: Deine Seite wird dabei in einem komplett anderen Kontext neu aufgebaut. Der Matomo-Server hat keine Cookies, keine Session, einen anderen Origin, und weiß nichts davon, was deine JavaScript-Frameworks nach dem Laden an der Seite verändert haben. Alles, was nur deshalb funktioniert hat, weil es in einem echten Browser auf deiner Domain lief, kann kaputtgehen, wenn dasselbe HTML dann kalt auf einem fremden Server gerendert wird.
Wenn man das einmal verinnerlicht hat, ergeben die meisten Heatmap-Screenshot-Fehler auf einmal Sinn.
Wie sehen fehlerhafte Heatmap-Screenshots aus?
Typische Probleme, die immer wieder auftauchen:
- Das Hero-Bild lädt im Browser ohne Probleme, taucht aber in der Heatmap als kaputtes Symbol auf
- Ein scrollbares Produktraster zeigt nur die erste Zeile, der Rest ist abgeschnitten
- Eine fixierte Navigation liegt im Screenshot über dem eigentlichen Inhalt
- Markenschriftarten sind durch generische Systemschriften ersetzt
- Assets mit relativen Pfaden wie
/assets/banner.webpladen gar nicht - SPA-Seiten werden mitten im Rendering erfasst, und die Hälfte des Inhalts fehlt
Jedes dieser Probleme hat eine konkrete Ursache. Schauen wir uns die einzeln an.
CORS blockiert deine Bilder und Schriftarten
Das ist mit Abstand das häufigste Problem. Dein Hero-Bild, Produktfotos oder Hintergrundbilder tauchen im Heatmap-Screenshot als leere Boxen oder kaputte Symbole auf.
Warum? Weil deine Bilder im Browser problemlos laden, da der Browser deine Cookies und den Session-Kontext hat. Wenn aber Matomos Server versucht, https://cdn.yoursite.com/hero.jpg abzurufen, sieht das CDN einen fremden Origin und blockt die Anfrage. Klassisches CORS-Problem.
Serverseitig ist die Lösung simpel: Access-Control-Allow-Origin: * in die Response-Header deines CDNs packen. Matomos Dokumentation beschreibt das in ihrem Heatmap-Setup-Guide.
Falls du keinen Zugriff auf das CDN hast oder die Serverkonfiguration nicht anfassen willst, gibt es noch einen anderen Weg: Ressourcen direkt als Base64-Data-URIs ins DOM einbetten, bevor Matomo die Seite erfasst. Dann enthält das serialisierte HTML jedes Bild inline und der Server muss nichts mehr nachladen. Das betrifft src, srcset, CSS-Hintergrundbilder, SVG-Referenzen und Video-Poster-Bilder.
Scroll-Container schneiden deinen Inhalt ab
Du hast einen Bereich mit fester Höhe und Scrollbalken. Im Heatmap-Screenshot wird aber nur der sichtbare Teil gerendert, alles darunter fehlt.
Elemente mit overflow: hidden oder overflow: auto schneiden den Inhalt auf ihre gerenderte Höhe ab. Matomo serialisiert das DOM so, wie es gerade aussieht. Das erfasste HTML spiegelt also die clientHeight wider, nicht die volle scrollHeight.
Abhilfe: Vermeide feste Höhen bei Content-Containern. Nimm min-height statt height und setz kein overflow: hidden auf Elemente, die scrollbaren Inhalt enthalten.
Fixierte und klebende Header überlagern die Seite
Deine fixierte Navigation funktioniert im Browser wunderbar, aber im Screenshot liegt sie einfach auf dem Inhalt und verdeckt alles darunter.
Elemente mit position: fixed und position: sticky werden relativ zum Viewport positioniert. Serverseitig gibt es keinen Viewport, also kollabieren sie auf den darunterliegenden Inhalt.
Matomo fügt dem <html>-Element beim serverseitigen Screenshot-Rendering die Klasse matomoHeatmap hinzu. Die kannst du nutzen, um CSS-Regeln zu schreiben, die nur während der Erfassung greifen:
html.matomoHeatmap .your-sticky-header {
position: relative;
top: auto;
}Damit wird dein fixierter Header im Screenshot in den normalen Dokumentenfluss eingereiht, ohne dass sich für echte Nutzer irgendwas ändert. Matomos Dokumentation geht darauf ein im FAQ zum Beheben überlappender Header in Heatmaps und zum Anwenden benutzerdefinierter Stylesheets während der Erfassung.
Wenn du keine Lust hast, extra CSS-Regeln dafür zu pflegen: Der generelle Ansatz ist, Header- und Navigationselemente mit fixierter oder klebriger Positionierung zu finden, sie auf position: relative umzustellen, ihre top/bottom/left/right-Werte rauszuwerfen und bei fixierten Elementen ein Platzhalter-Div einzufügen, damit das Layout nicht springt. Nach der Erfassung wird alles zurückgesetzt.
Relative URLs, die ins Leere laufen
Manche Bilder und Stylesheets laden auf deiner Seite ganz normal, fehlen aber im Matomo-Screenshot, obwohl sie nicht Cross-Origin sind. Auf den ersten Blick verwirrend, bis man sich anschaut, was da eigentlich passiert.
Deine Seite nutzt relative URLs wie /images/banner.jpg. Im Browser wird das gegen deine Domain aufgelöst. In Matomos Rendering-Kontext wird /images/banner.jpg aber gegen den Matomo-Server aufgelöst, und die Datei existiert dort schlicht nicht.
Der Fix: Entweder überall absolute URLs verwenden oder ein <base href="https://yoursite.com/">-Tag in den <head> packen. Wenn beides nicht geht, kann ein Pre-Capture-Skript das Dokument nach relativen URLs in src-, href-, srcset- und CSS-background-image-Attributen durchgehen und sie anhand des aktuellen Origins in absolute URLs umschreiben.
Benutzerdefinierte Schriftarten werden als Systemschriften angezeigt
Deine Markenschriftarten sind weg. Der Screenshot zeigt die Systemschrift des Servers, und die sieht in der Regel nicht besonders gut aus.
@font-face-Regeln verweisen auf Schriftdateien, die auf CDNs oder deinem Server liegen. Wenn Matomos Server versucht, die abzurufen, wird er von CORS geblockt, oder das CDN erwartet einen Browser-User-Agent. Der Server greift dann auf eine Fallback-Schrift zurück.
Was hilft: Schriftarten auf einem Server mit offenen CORS-Headern hosten. Google Fonts macht das von Haus aus, aber viele selbst gehostete Schriftarten nicht. Wenn du die Header nicht anpassen kannst, bleibt noch die Möglichkeit, Schriftarten direkt in die Seite einzubetten: Schriftdateien abrufen, in Base64-Data-URIs umwandeln und als @font-face-Regeln in <style>-Tags im <head> einfügen. So trägt das serialisierte HTML seine eigenen Schriftdefinitionen mit sich und rendert überall korrekt.
Iframes, Videos und SPAs
Ein paar Sonderfälle, die man auf dem Schirm haben sollte.
Iframes haben oft feste CSS-Abmessungen, die nicht zum tatsächlichen Inhalt passen. Bei Same-Origin-Iframes kannst du die echte Inhaltshöhe über contentDocument.body.scrollHeight auslesen und anpassen. Bei Cross-Origin-Iframes brauchst du eine großzügige Fallback-Höhe.
Automatisch abspielende Videos werden mitten in der Wiedergabe erfasst und zeigen ein zufälliges Frame. Pausier sie und spring vor der Erfassung zu Frame 0, damit der Screenshot das erste Frame zeigt.
Single Page Applications sind der schwierigste Fall. React-, Vue- und Angular-Apps laden Inhalte dynamisch, und Matomo erfasst das DOM möglicherweise, bevor dein Framework fertig gerendert hat. Die URL stimmt vielleicht auch nicht mit dem überein, was dein Router anzeigt. Eine Patentlösung gibt es da nicht. Am ehesten hilft es, Matomos URL-Matching-Regeln für deine SPA-Routen zu konfigurieren und Matomos JS-API zu nutzen, um die Aufnahme erst nach Abschluss des Renderings auszulösen.
Alles auf einmal beheben mit dem Matomo Heatmap Helper
Die meisten Websites in der Praxis haben gleich mehrere dieser Probleme auf einmal. Die alle manuell zu fixen bedeutet: CDN-Konfigurationen anpassen, URLs umschreiben, CSS umbauen und eigene Capture-Skripte schreiben.
Matomo Heatmap Helper ist eine kostenlose Open-Source-Erweiterung für Chrome und Firefox, die das alles übernimmt. Quellcode auf GitHub.
In der Praxis sieht das so aus: Du installierst die Erweiterung, gibst deine Matomo-URL und dein API-Token ein und wählst aus, welche Seiten aktiviert werden sollen. Auf passenden Seiten erscheint eine Toolbar. Klick auf "Interactive" und dann auf die Elemente, die repariert werden müssen: Scroll-Container, fixierte Header, Bereiche mit fehlenden Bildern. Die bekommen ein Schloss-Symbol, das anzeigt, dass sie verarbeitet werden.
Wenn du den Screenshot-Button drückst, läuft die Erweiterung eine Abfolge durch. Zuerst werden Cross-Origin-Bilder und -Schriftarten abgerufen und eingebettet, dann eingeschränkte Elemente erweitert und Header entfixiert, Iframes und Videos behandelt, relative URLs in absolute umgewandelt und Matomos Screenshot-API ausgelöst. Danach wird jede Änderung rückgängig gemacht und deine Seite kehrt in ihren ursprünglichen Zustand zurück.
Bevor du einen Screenshot machst
Kurze Checkliste:
- Sicherstellen, dass die Seite komplett gerendert ist, vor allem SPA-Inhalte und Lazy-Loading-Bereiche
- Container sperren, die Inhalte abschneiden oder erweitert werden müssen
- Auf fixierte oder klebende Header prüfen, die Inhalte überlagern könnten
- Kontrollieren, ob die wichtigsten Bilder und Schriftarten sichtbar sind
- Screenshot machen und bestätigen, dass die Verifizierung durchgeht
- Heatmap-Ansicht öffnen und das Ergebnis prüfen, bevor du mit der Analyse loslegst
Zwei Wege nach vorn
Diese Screenshot-Probleme sind keine Bugs auf deiner Website. Sie sind Nebeneffekte davon, wie Matomo deine Seite serialisiert und woanders neu rendert. Jede Website, die CDNs, Webfonts, Scroll-Container oder fixierte Header nutzt, wird auf irgendeine Kombination davon stoßen.
Du kannst jedes Problem einzeln auf Infrastrukturebene lösen: CORS-Header setzen, absolute URLs verwenden, Overflow-Container umbauen, fixierte Positionierung während der Erfassung umschalten. Das ist der richtige Weg, wenn du die Kontrolle über den Server hast, aber es kostet Zeit und nicht jedes Problem hat eine saubere serverseitige Lösung.
Oder du behebst alles zum Zeitpunkt der Erfassung mit dem Matomo Heatmap Helper. Nutz den interaktiven Modus, um anzugeben, welche Teile deiner Seite Hilfe brauchen, und hol dir saubere Screenshots, ohne Produktionscode anfassen zu müssen.