Unsere Analyse zählte US-Besucher jeden Abend doppelt
Ein Tester in den USA sah mehr Besuche, als es sein dürften. Die Ursache war eine Annahme darüber, was ein Tag ist, und sie steckt in mehr Software als nur Analytics.
Veröffentlicht am
Wir bauen Privatrak, ein cookieloses Analyse-Tool. Im September sagte uns einer unserer Tester, der in den USA lebt, dass etwas nicht stimmt. Seine Daten sahen merkwürdig aus: Es gab jeden Tag mehr Besuche, als es hätten sein dürfen.
Er hatte recht. Bei Besuchern in den USA zählten wir manche Menschen doppelt, jeden Tag, rund um die Abendessenszeit. Im Nachhinein ist er offensichtlich, vorher war er unsichtbar: Wir hatten nie entschieden, was ein „Tag“ ist.

Wie wir Menschen ohne Cookie zählen
Ein Cookie ist ein Etikett am Browser. Jeder Seitenaufruf trägt es, also ist das Zählen eindeutiger Besucher einfach.
Wir speichern nichts auf dem Gerät des Besuchers. Stattdessen berechnen wir auf dem Server eine Kennung aus Angaben, die jede Anfrage ohnehin mitbringt:
besucher_id = HMAC(tagesschluessel, IP-Adresse + Browser + Website)
Dieselbe Person auf demselben Gerät erzeugt bei jedem Seitenaufruf dieselbe Kennung, also zählen wir sie einmal. Die rohe IP-Adresse und die Browser-Kennung speichern wir nie, nur den Hash.
Der tagesschluessel sorgt für den Datenschutz. Würde er sich nie ändern, wäre die Kennung ein stabiler Fingerabdruck, der jemanden monatelang begleitet, und genau das sollen die Cookie-Regeln verhindern. Deshalb wechselt der Schlüssel einmal am Tag, und danach lassen sich die Kennungen von gestern nicht mehr denen von heute zuordnen.
Woran wir nicht gedacht hatten: „Einmal am Tag“ heißt „zu einer bestimmten Uhrzeit“. Wir hatten Mitternacht UTC genommen, ohne zu merken, dass das eine Entscheidung ist.
Mitternacht UTC ist keine Mitternacht
Mitternacht UTC trifft je nach Standort Ihrer Besucher auf ganz verschiedene Tageszeiten:
| Ihre Besucher sitzen in | Mitternacht UTC ist für sie |
|---|---|
| Los Angeles | 16–17 Uhr |
| New York | 19–20 Uhr |
| São Paulo | 21 Uhr |
| London | 0–1 Uhr |
| Berlin | 1–2 Uhr |
| Dubai | 4 Uhr |
| Mumbai | 5:30 Uhr |
| Singapur | 8 Uhr |
| Tokio | 9 Uhr |
| Sydney | 10–11 Uhr |
Los Angeles
- Mitternacht UTC ist für sie
- 16–17 Uhr
New York
- Mitternacht UTC ist für sie
- 19–20 Uhr
São Paulo
- Mitternacht UTC ist für sie
- 21 Uhr
London
- Mitternacht UTC ist für sie
- 0–1 Uhr
Berlin
- Mitternacht UTC ist für sie
- 1–2 Uhr
Dubai
- Mitternacht UTC ist für sie
- 4 Uhr
Mumbai
- Mitternacht UTC ist für sie
- 5:30 Uhr
Singapur
- Mitternacht UTC ist für sie
- 8 Uhr
Tokio
- Mitternacht UTC ist für sie
- 9 Uhr
Sydney
- Mitternacht UTC ist für sie
- 10–11 Uhr
Die Spannen sind die beiden Seiten der Sommerzeit.
Für ein europäisches Publikum ist das mitten in der Nacht, also surft kaum jemand und wird kaum jemand zerteilt. Für ein US-Publikum fällt der Moment auf den frühen Abend. Jemand liest um 19:50 Uhr Ihre Preisseite, geht essen und kommt um 20:10 Uhr zurück. Um 20:00 Uhr hat der Schlüssel gewechselt (im Winter ist es 19:00 Uhr). Dieselbe Person, neue Kennung, zwei Besucher.

Deshalb sah ein Tester in den USA mehr Besuche als erwartet, und deshalb hätte ein Tester in Europa es nie bemerkt. Eine Prozentzahl können wir nicht nennen. Sie hängt davon ab, wie lange Ihre Besucher bleiben, wie viele am selben Abend wiederkommen und wann Ihr Verkehr seinen Höhepunkt hat. Was wir sagen können, ist, was nach der Korrektur passiert ist: Der Unterschied war groß, und auch seine Trichter wurden besser.
Bei den Trichtern leuchtet es ein, sobald man es sieht. Ein Trichter verfolgt einen Besucher von Schritt zu Schritt. Wer um 19:50 Uhr die Preisseite ansah und um 20:10 Uhr ein Konto anlegte, war also zwei Besucher, und keiner von beiden hat den Trichter je abgeschlossen. Seit der Tag am richtigen Ort getrennt wird, stimmten seine Trichterzahlen auch mit dem überein, was die Insights im Dashboard zeigten.
Wen das betrifft
Nicht jeden. Es braucht Entfernung: Leben Ihre Besucher nah an der Zeitzone, in der der Tag geschnitten wird, surft beim Wechsel fast niemand, und niemand wird zerteilt. Es trifft, wenn die Besucher weit von dieser Grenze entfernt sind. Bei einem Produkt wie unserem, bei dem Kunden und Besucher in jeder Zeitzone sitzen können, kann jede einzelne feste Grenze für irgendwen auf den Abend fallen, also kann eine Grenze für alle nicht stimmen.
Eine Website, deren Besucher überwiegend in einer Region sitzen, kann das beheben, indem sie die Zeitzone dieser Region wählt. Eine Website mit wirklich weltweitem Publikum wird das Problem nicht los, denn irgendwo auf der Welt ist beim Tageswechsel immer Abend. Am besten schneiden Sie den Tag dort, wo Ihr eigener Verkehr am geringsten ist.
Es ging nicht nur um Besucher
Als wir nachsahen, war der Besucherschlüssel nur eine von zwei Stellen, die den UTC-Tag benutzten. Die andere war jeder Tageswert in den Auswertungen. Wir hatten zwei getrennte Stellen im Code, die jeweils für sich festlegten, dass ein Tag um Mitternacht UTC beginnt. Sie stimmten zufällig miteinander überein, also fiel der Fehler nirgends als Widerspruch auf.
Bei einem Projekt in New York enthielt der Balken „Dienstag“ in Wirklichkeit Montag 20 Uhr bis Dienstag 20 Uhr. Es ging also nicht nur um ein paar zusätzliche Besucher. Jeder Tag in der Auswertung war verschoben, und ein Newsletter, den Sie montags um 21 Uhr verschickt haben, wäre erst am Dienstag aufgefallen.
Die Lösung: einmal entscheiden, an einer Stelle
Wir gaben jedem Projekt eine Zeitzone und ließen sie beides bestimmen: den Moment des Schlüsselwechsels und die Ränder jedes Tageswerts. Es gibt nur noch einen Wert, also können die beiden nicht mehr voneinander abweichen.
Das sah nach einer kleinen Änderung aus. Das war es nicht.
- Ein gezählter Tag ist eingefroren. Wir löschen die Rohdaten eines Tages, sobald wir ihn gezählt haben, aus Datenschutzgründen. Ändert jemand die Zeitzone eines Projekts, können wir alte Tage nicht auf der neuen Grenze neu zählen, denn die Zeilen, die das beantworten würden, sind weg. Eine Zeitzonenänderung gilt ab dann, und der erste Tag danach ist länger oder kürzer als 24 Stunden.
- Die Sommerzeit macht Tage 23 oder 25 Stunden lang. Ein Stundendiagramm hat 25 Balken an dem Tag, an dem die Uhren zurückgestellt werden, und 23, wenn sie vorgestellt werden. Wir beschriften jeden Balken mit dem UTC-Versatz in diesem Moment, sodass es einen Balken pro echter Stunde gibt.
Das ist nicht nur ein Analytics-Fehler
Seit wir es gesehen haben, entdecken wir denselben Fehler auch anderswo. Viel Software legt nie fest, wessen Tag gemeint ist und wann zurückgesetzt wird, und nimmt einfach die Uhr des Servers. Hier würden wir nachsehen:
- Tageskontingente und Ratenlimits, die um Mitternacht UTC zurückgesetzt werden, sodass Nutzer woanders ihr frisches Kontingent zu einer seltsamen Uhrzeit bekommen.
- Serien und Tagesziele. Eine Serie, die reißt, weil die Mitternacht des Servers mitten am Abend kam, ist ein Klassiker.
- „Heute“ in Dashboards und Berichten, besonders wenn man es mit dem Tag eines anderen Systems vergleicht, etwa dem Ihres Zahlungsanbieters.
- Tagesbudgets und Abrechnungszeiträume, die nach dem Tag eines Kontos verteilt oder zurückgesetzt werden.
- Geplante Zusammenfassungen und Cron-Jobs. „Jeden Tag um 9 Uhr“ nach wessen Uhr?
- Alles, was eine Kennung nach Zeitplan wechselt: Sitzungs-IDs, Ratenlimit-Zähler, Startwerte für A/B-Test-Gruppen. Was zu einer festen Zeit wechselt, zerteilt jeden, der gerade mittendrin ist, genau wie bei uns.
- Die Sommerzeit, für alles, was annimmt, ein Tag habe 24 Stunden.
Was wir anders machen würden
Sobald zum ersten Mal DATE(timestamp) oder „um Mitternacht zurücksetzen“ im Code auftaucht, fragen Sie, wessen Mitternacht das ist. Wir haben das nicht getan und es erst gemerkt, als ein Tester in einer anderen Zeitzone es bemerkt hat.