Skip to content

Releases: oliweb-ch/statamic-privacy-analytics

v4.11.0 — CP interface fully translated

Choose a tag to compare

@oli217 oli217 released this 21 Oct 08:32
c235f1e

What's new

All remaining hard-coded strings in the Control Panel are now routed through statamic-analytics::messages, making every label locale-aware.

Translated strings

  • Dashboard widget (analytics-overview.blade.php): title, "View all" link, "Last 7 days" label, "Today" / "Page Views" / "Unique Visitors" stat captions, and the widget load error message.
  • MaxMind credentials warning (Dashboard.vue): the entire notice (title, body, sign-up link label, disable hint).
  • Heatmap day labels (HeatmapWidget.vue): Mon…Sun → day_mon…day_sun.
  • Real-time badge (RealTimeWidget.vue): LIVE → locale key.

New keys added to both en and fr with identical key sets. French values match the previously hard-coded strings exactly — French control panels look the same.

Upgrade

No migrations, no config changes. Drop-in upgrade.

composer require oliweb/statamic-privacy-analytics:^4.11

For maintainers forking this addon: run npm run build after pulling, then commit resources/dist/ before tagging.

Full changelog

See UPGRADE.md for details.


Thanks @trampish for the contribution.

v4.10.0

Choose a tag to compare

@oli217 oli217 released this 17 Sep 08:35
fc178b9

What's changed

Tracker JS — source unique via pipeline Vite

Le script de tracking injecté par {{ statamic_analytics:tracker }} est désormais compilé depuis une seule source (resources/js/tracker.js) via Vite/Rollup. Le heredoc PHP qui dupliquait la logique tracker dans ConsentBanner a été supprimé.

Pour les utilisateurs de l'addon (Composer) : rien à faire. Le bundle compilé (resources/dist/tracker.js) est livré dans le package. Comportement identique à v4.9.

Architecture :

resources/js/tracker.js        ← source unique, spec Vitest
    ↓
resources/js/tracker-bundle.js ← point d'entrée IIFE, lit window.__anl
    ↓
Vite/Rollup build
    ↓
resources/dist/tracker.js      ← bundle IIFE livré dans le package
    ↓
ConsentBanner::tracker()       ← file_get_contents + injection window.__anl
    ↓
<script> inline dans le HTML

Tests

  • ConsentBannerTrackerTest — réécriture des tests de pattern-matching en tests comportementaux réels sur tracker()
  • ConsentBannerDisplayTest (nouveau) — premiers tests sur le rendu de la bannière de consentement : position (bottom/top/center), textes configurables, structure Alpine
  • tracker-bundle.test.js (nouveau) — smoke test Vitest qui exécute le bundle IIFE compilé dans jsdom et vérifie le comportement end-to-end

Résultats : 146 tests PHPUnit · 46 tests Vitest

No breaking changes

Mise à jour compatible depuis v4.9. Voir UPGRADE.md pour le détail.

v4.9.0

Choose a tag to compare

@oli217 oli217 released this 16 Sep 17:00
a652883

Privacy fixes

Server-side consent enforcement (full static mode)

Previously, when tracking.consent.enabled was true, consent was enforced only by the JS tracker. A direct call to GET /statamic-analytics/track bypassed the check entirely.

The beacon endpoint now verifies session('analytics_consent') server-side. A beacon is silently dropped (HTTP 204) if the visitor has not consented.

When consent.enabled is active, the beacon participates in the site's existing Laravel session — no additional cookie is set.

Granular geolocation opt-out now enforced server-side

The geolocation toggle in the consent banner was stored in the session but never read by the server. IP geolocation was performed regardless of the visitor's choice.

From v4.9, declining geolocation skips GeolocationService::lookup() entirely — country_code, country_name, city are stored as NULL. The flag is serialised in the job payload so it survives the async queue path.

Analytics metric corrections

Bounce rate

The previous bounce rate was incorrect (ratio of new page URLs per session, not single-page sessions).

Corrected formula: sessions with exactly 1 page view / total sessions

Your dashboard will show different values from v4.9 onward — the new figures are analytically meaningful; the previous ones were not.

Entry pages

Entry pages now uses MIN(id) per session to identify the single first page view. Concurrent beacons in the same second are resolved deterministically by insertion order.

Your entry pages data will show different (more accurate) values from v4.9 onward.

Other fixes

  • JS tracker date consistency — Inline tracker used toISOString() (UTC date) with getHours() (local time), causing incorrect new-day detection around midnight in non-UTC timezones. Both now use local time.
  • analytics:health cache check — Now performs a full read/write/delete cycle and fails if the read returns an unexpected value.

Upgrade

No migrations, no config changes required. See UPGRADE.md for details.

composer require oliweb/statamic-privacy-analytics:^4.9

v4.8.0 — PostgreSQL support & configurable DB connection

Choose a tag to compare

@oli217 oli217 released this 14 Sep 06:08
e685317

Fixed

  • PostgreSQL compatibility: boolean columns (is_new_visitor, is_new_page_visit) were compared with = 1/= 0 in raw SQL — MySQL/MariaDB/SQLite accept this, Postgres does not. Fixed with portable CASE WHEN column THEN 1 ELSE 0 END syntax.
  • PostgreSQL: division by zero on bounce_rate in getTopPages() when no row has is_new_page_visit = true. Protected with NULLIF.
  • Heatmap: missing pgsql branch was falling through to MySQL-only HOUR()/DAYOFWEEK() functions. Fixed with EXTRACT() for Postgres.

Added

  • Configurable database connection via statamic-analytics.database_connection (env: ANALYTICS_DB_CONNECTION). Defaults to null (no behavior change for existing installs). Useful when analytics data must live on a specific connection regardless of the app default.
  • CI: added test-postgres job (PostgreSQL 16) mirroring the existing MySQL/MariaDB jobs.

Thanks @trampish (#1)

v4.7.4

Choose a tag to compare

@oli217 oli217 released this 03 Sep 14:39

Tests

PHP (PHPUnit)

  • TrackControllerTest — 13 tests HTTP du beacon GET /statamic-analytics/track : validation des paramètres, filtrage IP, dérivation page_url depuis le header Referer, détection bot
  • HealthCheckTest — 13 tests de la commande analytics:health : exit codes, queue, géolocalisation, compatibilité static cache
  • TrackPageVisitFilteringTest — test supplémentaire : le middleware se désactive bien en strategy=full sans déclencher de tracking

JS (Vitest)

  • resources/js/tracker.js — extraction lisible du script inline de ConsentBanner::tracker(), mêmes clés de stockage (_anl_vid, _anl_sid…), toutes les fonctions exportées
  • resources/js/tracker.test.js — 42 tests : UUID, flags de visite, consentement, construction des params beacon, init() avec fake timers et mock fetch
  • vitest.config.js — environnement jsdom, nettoyage automatique entre tests

CI

  • Job test-js ajouté dans le workflow GitHub Actions (Node 22, npm ci, vitest run)

Aucun changement de comportement en production — release exclusivement dédiée à la couverture de tests.

v4.7.3

Choose a tag to compare

@oli217 oli217 released this 02 Sep 15:13

Bug fix

Double-tracking en strategy=full (static caching)

En static caching full, PHP est appelé sur les cache miss (première requête par URL). Le middleware TrackPageVisit trackait la visite, puis le beacon JS la trackait également — résultat : chaque URL était comptée deux fois à sa première mise en cache.

Changements

  • TrackPageVisit : early return immédiat si strategy=full — le middleware ne track plus rien, le beacon JS reste le seul chemin de tracking
  • analytics:health : le check static cache passe de ⚠ à ✓ pour strategy=full (comportement désormais attendu et correct)
  • README : corrections des descriptions concernant le comportement sur cache miss

v4.7.2 — Fix check beacon endpoint dans analytics:health

Choose a tag to compare

@oli217 oli217 released this 02 Sep 14:26

Correctif

analytics:health signalait toujours ✗ Beacon endpoint à tort.

La route GET /statamic-analytics/track n'avait pas de nom explicite — Statamic lui assignait un nom auto-généré (generated::...). Route::has('statamic-analytics.track') retournait donc toujours false.

Correction : ajout de ->name('statamic-analytics.track') sur la route. Aucun impact fonctionnel — le tracker JS et le contrôleur utilisent l'URL en dur, pas le nom de route.

v4.7.1 — Fix fatal error Command::fail() / alert()

Choose a tag to compare

@oli217 oli217 released this 02 Sep 13:51

Correctif

PHP Fatal error au chargement de HealthCheck (introduit en v4.7.0)

Illuminate\Console\Command expose public function fail() et public function alert() dans Laravel récent. Les méthodes privées homonymes de HealthCheck réduisaient la visibilité, ce qui est interdit par PHP et provoquait un fatal error à l'autoload — faisant échouer tous les tests (exit code 2).

Renommage : pass/alert/fail → printOk/printWarn/printFail.

Aucun autre changement. La commande analytics:health fonctionne identiquement.

v4.7.0 — Commande analytics:health

Choose a tag to compare

@oli217 oli217 released this 02 Sep 13:44

Nouvelle commande : analytics:health

php artisan analytics:health

Diagnostic complet de l'addon en une passe. 11 vérifications, sortie colorée ✓/⚠/✗ avec suggestion d'action pour chaque problème détecté.

Checks

Check Ce qui est vérifié
Configuration Config chargée
Database Connexion + tables présentes + comptage événements
Cache Cycle écriture / lecture / suppression
Encryption APP_KEY définie (requis pour les jobs chiffrés)
Queue Connexion configurée et présente dans queue.connections ; synchrone si null
Geolocation Provider configuré ; disabled → avertissement
MaxMind Credentials présents, fichier .mmdb existant et lisible, âge ≤ 30 jours
Storage permissions Répertoires cache, logs et geoip accessibles en écriture
Scheduler analytics-scheduler.log modifié dans les 25 dernières heures
Failed jobs Nombre d'entrées TrackPageViewJob dans failed_jobs
Static cache Stratégie full détectée → rappel d'ajouter {{ statamic_analytics:tracker }}
Beacon endpoint Route statamic-analytics.track enregistrée

Le code de retour est 1 si au moins un check échoue — utilisable dans un script de déploiement ou un pipeline CI.

Aucun breaking change

v4.7.0 est entièrement rétrocompatible.

v4.6.2 — Hardening beacon trust model + corrections docs privacy

Choose a tag to compare

@oli217 oli217 released this 02 Sep 13:22

Corrections suite à audit de sécurité/privacy

P2 — Endpoint beacon : dérivation de page_url depuis le header Referer

Le contrôleur de tracking ne fait plus confiance à la valeur page_url fournie par le query string du beacon. Il dérive désormais la page trackée depuis le header HTTP Referer du beacon, que le navigateur positionne automatiquement sur la page ayant déclenché la requête — et qui ne peut pas être falsifié par simple manipulation de l'URL.

Fallback sur la valeur client uniquement si le header Referer est absent (navigateurs avec Referrer-Policy stricte ou extensions bloquant ce header).

referrer_url (page précédente, lue via document.referrer côté JS) reste fournie par le client — le serveur ne peut pas la dériver autrement. Elle est sanitisée (scheme + host + path uniquement).

Documentation privacy

README — ajout d'une note explicite sur _anl_vid :

  • identifiant localStorage persistant, sans expiry, spécifique au mode strategy=full
  • distinction avec le mode standard (session Laravel, non-persistant)
  • recommandation de mention en politique de confidentialité si le contexte légal l'exige

docs/data-processing-overview.md + .fr.md — deux corrections :

  1. Referrer : « domaine uniquement » → « schéma + domaine + chemin » (alignement avec le code réel)
  2. Transfert de données : la formule « aucun transfert hors Suisse » est maintenant conditionnelle à la configuration MaxMind par défaut — la note précise qu'avec ip-api activé, les IP sont transmises à un service externe

La section Cookies est renommée Cookies et stockage navigateur et documente le localStorage persistant en mode full static caching.

Aucun breaking change