statamic-privacy-analytics Icon

statamic-privacy-analytics

4.5.3

August 10th, 2026

What's changed

  • Translated the Upgrading to 4.5 section of UPGRADE.md from French to English, consistent with the rest of the document.
  • Fixed support.github URL in composer.json — now points to the repository instead of the organisation.

4.5.2

August 9th, 2026

Maintenance

  • Régénération du package-lock.json — suppression d'une référence extraneous (../ccmanoir/vendor/statamic/cms/resources/dist-package) présente depuis le développement initial. 3 packages fantômes et leurs dépendances transitives retirés (151 lignes).

4.5.1

August 9th, 2026

  • N/A Changelog not available.

4.5.0

August 8th, 2026

Breaking change (discontinuité de données)

La bibliothèque de détection d'appareil passe de jenssegers/agent (abandonnée, ne reconnaît plus les mobiles récents depuis 2020) à matomo/device-detector 6.5.1 (activement maintenue par Matomo).

Ce qui ne change pas

  • Les valeurs de device_type (tablet / mobile / desktop) sont strictement identiques.
  • Aucun changement de configuration, de commande ou de schéma de base de données.

Ce qui peut différer

Les libellés browser et platform peuvent être formulés différemment par la nouvelle bibliothèque autour de la date de mise à jour. Les widgets Browser usage et Platforms / OS peuvent afficher temporairement des entrées séparées pour un même navigateur/OS réel. C'est un changement assumé — voir UPGRADE.md pour les détails.

Changements internes

  • Constructeur de TrackPageVisit désormais injectable (?DeviceDetector $deviceDetector)
  • Tests : réflexion supprimée, injection directe via le constructeur
  • 3 paquets supprimés : jenssegers/agent, mobiledetect/mobiledetectlib, jaybizzle/crawler-detect

4.4.8

August 7th, 2026

Correctifs audit P4

  • Rate limiter ip-api atomique : remplacement du pattern non-atomique get → test → put par Cache::lock()->block() dans lookupViaIpApi() — même mécanisme que trackLookup(). LockTimeoutException remonte volontairement (protège un service tiers).
  • Permissions dossier MaxMind : 0775 hardcodé → config('statamic-analytics.cache.file.permissions.directory', 0755), cohérent avec le reste de la configuration.
  • Throttle route consentement : throttle:10,1 ajouté sur POST /statamic-analytics/consent.
  • Export CSV : ->get() remplacé par ->cursor() pour éviter le chargement de toute la période en mémoire.
  • Confirmation RGPD avant export : window.confirm() affiché avant le téléchargement CSV (clé export_gdpr_warning ajoutée en/fr).

4.4.7

August 7th, 2026

Rebuild des assets compilés

Les fichiers dans resources/dist/ n'avaient pas été recompilés depuis le commit 6cdf6bd (v3.0.x). Le bundle JS ne reflétait pas le v-if=\"config.canManage\" introduit en v4.4.0 sur les boutons Export CSV et Reset geo stats.

Ce qui change

  • Bundle JS : statamic-analytics-HATjrHgH.jsstatamic-analytics-C0DH1Uv5.js
  • config.canManage présent × 2 dans le nouveau bundle (confirmé par grep)
  • Manifest resources/dist/build/manifest.json mis à jour

Ce qui ne change pas

  • CSS (statamic-analytics--r3RbQkV.css) — hash stable, contenu identique
  • Consent banner (consent-banner-CJh1zk-q.js) — hash stable, contenu identique

Aucun changement de code source.

4.4.6

August 7th, 2026

Documentation

README.md

  • Section «Configuration notes» (ex «Notes de configuration») — traduite en anglais avec la formulation juridique ip_retention_days déjà normalisée en v4.4.3 (not recommended, and unlimited retention may be difficult to justify…).
  • Bloc Important analytics:update-geoip — traduit (était resté en français).
  • Message de log safety net — traduit (échec du dispatch…queue dispatch failed, falling back to synchronous recording).
  • Diagramme d'architecture — ajout des deux commandes planifiées manquantes : analytics:purge-raw-events (v4.0) et analytics:purge-failed-jobs (v4.2), absentes du schéma malgré leur ancienneté.

UPGRADE.md

  • § Upgrading to 3.0 — traduit intégralement (était 100 % en français).
  • § Upgrading to 4.0 — traduit intégralement (était 100 % en français).

Aucun changement de code.

4.4.5

August 7th, 2026

Correctif cosmétique

Problème

Les permissions analytics.view et analytics.manage apparaissaient sous la rubrique «Divers» (groupe par défaut Statamic) dans l'éditeur de rôles CP, sans identification de leur origine.

Correctif

Remplacement des deux Permission::register() individuels avec ->group('analytics') par un bloc Permission::group() déclaratif :

#676E95;">// Avant
Permission#89DDFF;">::#82AAFF;">register#89DDFF;">(#89DDFF;">'analytics.view#89DDFF;">'#89DDFF;">, fn #89DDFF;">($p#89DDFF;">) #89DDFF;">=> #89DDFF;">$p
#89DDFF;">->#82AAFF;">label#89DDFF;">(#89DDFF;">'View analytics dashboard#89DDFF;">'#89DDFF;">)
#89DDFF;">->#82AAFF;">group#89DDFF;">(#89DDFF;">'analytics#89DDFF;">'#89DDFF;">)
#89DDFF;">);
 
#676E95;">// Après
Permission#89DDFF;">::#82AAFF;">group#89DDFF;">(#89DDFF;">'statamic-analytics#89DDFF;">'#89DDFF;">, #82AAFF;">__#89DDFF;">(#89DDFF;">'statamic-analytics::messages.permission_group#89DDFF;">'#89DDFF;">), function #89DDFF;">() #89DDFF;">{
Permission#89DDFF;">::#82AAFF;">register#89DDFF;">(#89DDFF;">'analytics.view#89DDFF;">'#89DDFF;">, fn #89DDFF;">($p#89DDFF;">) #89DDFF;">=> #89DDFF;">$p#89DDFF;">->#82AAFF;">label#89DDFF;">(#89DDFF;">'View analytics dashboard#89DDFF;">'#89DDFF;">));
Permission#89DDFF;">::#82AAFF;">register#89DDFF;">(#89DDFF;">'analytics.manage#89DDFF;">'#89DDFF;">, fn #89DDFF;">($p#89DDFF;">) #89DDFF;">=> #89DDFF;">$p#89DDFF;">->#82AAFF;">label#89DDFF;">(#89DDFF;">'Export and manage analytics data#89DDFF;">'#89DDFF;">));
#89DDFF;">});

Les permissions apparaissent désormais sous «Privacy Analytics» dans l'éditeur de rôles.

Notes techniques

  • Signature vérifiée contre le code source de statamic/cms installé : Permission::group(string $name, string $label, callable $permissions) — aucun écart avec la signature documentée.
  • Label traduit via __('statamic-analytics::messages.permission_group'), cohérent avec le reste de l'addon. Clé ajoutée dans lang/en/ et lang/fr/ ('Privacy Analytics', nom propre identique dans les deux langues).
  • Aucune modification de la logique d'accès (routes, widget, middleware).

4.4.4

August 7th, 2026

Correctif de sécurité — Finding P2 de l'audit v4.4.3

Problème

Le widget CP AnalyticsOverviewWidget était affiché à tout utilisateur CP quelle que soit sa permission analytics, révélant silencieusement l'existence de la fonctionnalité à des utilisateurs non autorisés.

Correctif — défense en profondeur (deux niveaux)

1. Garde explicite dans html() — protection de référence

#89DDFF;">if #89DDFF;">(!#82AAFF;">auth#89DDFF;">()->#82AAFF;">user#89DDFF;">()?->#82AAFF;">can#89DDFF;">(#89DDFF;">'analytics.view#89DDFF;">'#89DDFF;">)) #89DDFF;">{
#89DDFF;">return #89DDFF;">''#89DDFF;">;
#89DDFF;">}

Retourne une chaîne vide plutôt qu'un message d'erreur (principe de moindre privilège — l'absence silencieuse ne révèle pas l'existence de la fonctionnalité).

2. Clé can dans l'injection automatique — mécanisme natif Statamic

#89DDFF;">[#89DDFF;">'type#89DDFF;">' #89DDFF;">=> #89DDFF;">'analytics_overview#89DDFF;">'#89DDFF;">, #89DDFF;">'width#89DDFF;">' #89DDFF;">=> 50#89DDFF;">, #89DDFF;">'can#89DDFF;">' #89DDFF;">=> #89DDFF;">[#89DDFF;">'analytics.view#89DDFF;">'#89DDFF;">]]

DashboardController::getDisplayableWidgets() filtre les widgets sur can/permissions avant même d'appeler html(). Confirmé sur le code source de la version Statamic installée.

Note sur l'investigation préalable

Avant implémentation : lecture du code source de Statamic\Widgets\Widget (classe de base — aucun mécanisme d'autorisation natif) et de DashboardController::getDisplayableWidgets() (filtre can/permissions présent). Les deux niveaux de protection sont complémentaires.

Tests

3 nouveaux tests dans AnalyticsOverviewWidgetTest (81 total) :

  • test_widget_absent_sans_permission_analytics_view
  • test_widget_visible_avec_permission_analytics_view
  • test_super_admin_voit_le_widget_sans_permission_explicite

4.4.3

August 7th, 2026

Lot P3 de l'audit de sécurité/qualité

Corrections et améliorations

Protection CSV contre l'injection de formule

AnalyticsDashboardController::export() sanitise désormais chaque champ avant l'écriture CSV : toute valeur commençant par =, +, -, @, tabulation ou retour chariot est préfixée d'une apostrophe. Protection uniforme sur tous les champs (pas sélective).

Option --days pour analytics:process

Permet de rattraper des agrégats manqués si le scheduler a été interrompu plusieurs jours :

php artisan analytics:process --days=7

Le comportement par défaut (--days=2, aujourd'hui + hier) est inchangé — le scheduling automatique n'est pas affecté.

Formulations de documentation nuancées

README.md et UPGRADE.md : la mention null pour ip_retention_days est désormais décrite comme non recommandée, difficile à justifier selon les exigences applicables, sans conclusion juridique catégorique.

Tests

2 nouveaux tests (78 total) :

  • test_export_neutralise_les_valeurs_de_type_formule
  • test_option_days_recalcule_plusieurs_jours_en_arriere

4.4.2

August 7th, 2026

v4.4.2

Correctif

  • Race condition dans GeolocationService::trackLookup() (audit v4.3.0, point 18, P2)
    • Le bloc get→mutate→put sur la clé de statistiques journalières de géolocalisation est désormais protégé par Cache::lock() (TTL verrou : 5 s, attente max : 2 s).
    • En cas de contention (verrou non acquis dans le délai), la mise à jour des stats est ignorée en best-effort et journalisée en info — le géo-lookup lui-même n'est pas affecté.
    • Clé de verrou : statamic-analytics:geo-stats-lock:Y-m-d (granularité journalière, cohérente avec la clé de stats).

Tests

  • Ajout de deux tests dans GeolocationServiceTest (section 9) :
    • Non-régression : deux lookups avec des IP distinctes → total_lookups=2, unique_ips contient bien 2 entrées.
    • Dégradation propre : verrou pré-acquis manuellement → lookup() retourne le résultat géo attendu sans exception, les statistiques ne sont pas mises à jour.

4.4.1

August 7th, 2026

v4.4.1

Tests

  • Ajout de CpPermissionsTest : 6 tests d'intégration HTTP vérifiant le middleware can: sur les routes CP introduites en v4.4.0.
    • Aucune permission → redirect (302)
    • analytics.view → 200 sur index, data, geo-stats, realtime ; redirect sur export et reset-stats
    • analytics.manage → 200 sur export et reset-stats ; redirect sur index et data
    • Super-admin → 200 sur toutes les routes
    • Non authentifié → redirect vers login

Aucun changement de comportement applicatif. Couverture uniquement.

4.4.0

August 7th, 2026

Permissions CP granulaires

Deux permissions Statamic permettent de contrôler l'accès au tableau de bord analytics pour les utilisateurs CP non-super-admin.

Permission Slug Accès
View analytics dashboard analytics.view Dashboard, données agrégées, géolocalisation, temps réel
Export and manage analytics data analytics.manage Export CSV, réinitialisation des stats de géolocalisation

Les super administrateurs contournent automatiquement ces permissions.

⚠️ Breaking change pour les utilisateurs non-super-admin

Les utilisateurs CP non-super-admin qui avaient accès aux routes analytics devront se voir attribuer explicitement analytics.view et/ou analytics.manage après la mise à jour. Voir UPGRADE.md pour la procédure.

Changements

  • ServiceProvider : enregistrement des deux permissions, lien de nav conditionné par analytics.view
  • routes/cp.php : deux sous-groupes middleware can:analytics.view / can:analytics.manage
  • Dashboard.vue : boutons Export CSV et Reset stats masqués si analytics.manage absent (protection réelle côté serveur)

4.3.1

August 6th, 2026

Full Changelog: https://github.com/oliweb-ch/statamic-privacy-analytics/compare/v4.3.0...v4.3.1

4.3.0

August 6th, 2026

Full Changelog: https://github.com/oliweb-ch/statamic-privacy-analytics/compare/v4.2.0...v4.3.0

4.2.0

August 6th, 2026

Full Changelog: https://github.com/oliweb-ch/statamic-privacy-analytics/compare/v4.1.0...v4.2.0

4.1.0

August 6th, 2026

What's new

Opt-in asynchronous tracking via Laravel queues, for high-traffic sites where synchronous DB writes or geolocation resolution become a measured bottleneck.

The default behaviour (synchronous, no worker needed) is strictly unchanged.

Changes

  • PageViewRecorder service — geolocation lookup + DB INSERT extracted into a reusable class
  • TrackPageViewJobShouldQueue job with 3 attempts and 10/30/60 s backoff
  • TrackPageVisit middleware — conditionally dispatches the job or writes synchronously based on queue_connection
  • Config — two new optional keys: ANALYTICS_QUEUE_CONNECTION / ANALYTICS_QUEUE_NAME
  • Tests — queue dispatch / no-dispatch assertions
  • README — "Asynchronous tracking (opt-in)" section

Upgrade

No migration required. This is a purely additive change.

To enable async tracking, add to .env:

ANALYTICS_QUEUE_CONNECTION=redis
ANALYTICS_QUEUE_NAME=analytics

Then run a queue worker:

php artisan queue:work --queue=analytics

4.0.0

August 6th, 2026

Breaking changes

Purge définitive des événements bruts (nouveau)

analytics:purge-raw-events s'exécute quotidiennement et supprime définitivement les lignes de statamic_analytics_page_views de plus de 180 jours (configurable via ANALYTICS_RAW_RETENTION_DAYS). Contrairement à analytics:anonymize-ips qui anonymise sans supprimer, cette commande supprime les lignes.

Avant de mettre à jour sur une installation existante avec des données anciennes :

php artisan analytics:purge-raw-events --dry-run

Voir UPGRADE.md pour les options de configuration et la liste détaillée de ce qui survit vs disparaît.


Nouveautés

Agrégat _overview quotidien

analytics:process écrit désormais une ligne dimension='_overview' / dimension_value='_all' dans les agrégats pour chaque journée, préservant indéfiniment : visites totales, visiteurs uniques, pages vues uniques, visiteurs récurrents.

analytics:purge-raw-events

Nouvelle commande avec --dry-run, garde défensive sur la valeur de config, et suppression par chunks (chunkById). Planifiée quotidiennement avec withoutOverlapping().

Configuration raw_retention_days

#89DDFF;">'privacy#89DDFF;">' #89DDFF;">=> #89DDFF;">[
#89DDFF;">'ip_retention_days#89DDFF;">' #89DDFF;">=> #82AAFF;">env#89DDFF;">(#89DDFF;">'ANALYTICS_IP_RETENTION_DAYS#89DDFF;">'#89DDFF;">, 90#89DDFF;">),
#89DDFF;">'raw_retention_days#89DDFF;">' #89DDFF;">=> #82AAFF;">env#89DDFF;">(#89DDFF;">'ANALYTICS_RAW_RETENTION_DAYS#89DDFF;">'#89DDFF;">, 180#89DDFF;">), #676E95;">// nouveau
#89DDFF;">],

Corrections & nettoyages

  • ip-api : file_get_contents remplacé par Http::timeout(2)->connectTimeout(1) — timeout explicite, ConnectionException catchée séparément, $data === null géré proprement.
  • ProcessAnalytics : whereDate('visited_at')where >= startOfDay / < addDay()->startOfDay() pour exploiter l'index sur visited_at.
  • Session visited_pages : bornée à 20 entrées maximum (array_slice(-20)).
  • AnalyticsSettingsController supprimé : aucune route ni vue, résidu du fork d'origine.

3.2.2

August 6th, 2026

Fix

  • tests/TestCase.php : import corrigé — Mohammedshuaau\EnhancedAnalytics\ServiceProviderOliweb\StatamicAnalytics\ServiceProvider (résidu du fork, les tests ne pouvaient pas bootstrapper)
  • tests/ExampleTest.php : supprimé — scaffolding Laravel sans valeur (assertTrue(true))

Aucun changement fonctionnel.

3.2.1

August 6th, 2026

Fix

Correction du namespace résiduel du fork d'origine dans les fichiers de tests :

  • tests/ExampleTest.php
  • tests/TestCase.php
  • tests/TrackPageVisitSessionTest.php

Mohammedshuaau\EnhancedAnalytics\TestsOliweb\StatamicAnalytics\Tests

Aucun changement fonctionnel.

3.2.0

August 6th, 2026

Nouveautés

Anonymisation user_id à l'expiration de la rétention

Le champ user_id est désormais mis à NULL en même temps que ip_address et user_agent lors de l'exécution de analytics:anonymize-ips. Même seuil (ip_retention_days), aucune clé de config supplémentaire. track_authenticated_users reste actif par défaut, mais l'association utilisateur est automatiquement rompue à l'expiration — ce n'est pas un lien permanent.

Sanitisation du referrer

Le header Referer est désormais stocké sans sa query string (scheme://host/path uniquement), comme c'est déjà le cas pour page_url. Les URLs malformées ou sans host sont stockées null.

Hash SHA-256 dans les stats de géolocalisation

unique_ips dans les clés de cache de stats ne stocke plus les IPs en clair mais leur hash sha256. La déduplication reste exacte ; aucune UI ne consommait cette donnée.

resetStats() honnête en lieu et place du clearCache() no-op

  • GeolocationService::clearCache() était un no-op depuis v3.0.1 — renommé resetStats() avec une implémentation réelle qui vide les 32 clés de stats datées.
  • Route CP : /clear-cache/reset-stats (statamic-analytics.reset-stats)
  • Bouton dashboard : « Clear Geo Cache » → « Reset Statistics » / « Réinitialiser les statistiques »
  • Message JSON : précise que les entrées de cache géo par IP expirent naturellement et ne peuvent pas être vidées de force sur tous les drivers.

Fichiers modifiés

src/Commands/AnonymizeIps.php · src/Middleware/TrackPageVisit.php · src/Services/GeolocationService.php · src/Http/Controllers/AnalyticsDashboardController.php · src/Http/Controllers/AnalyticsSettingsController.php · routes/cp.php · resources/js/components/Dashboard.vue · resources/lang/en/messages.php · resources/lang/fr/messages.php · README.md

3.1.3

August 6th, 2026

Correctif P0 — session()->invalidate() dans le middleware de tracking

Problème

Depuis la mise en place du tracking, session()->invalidate() était appelé à la première visite trackée d'un visiteur. Cette méthode vide intégralement la session Laravel — panier, authentification, état de formulaire, toute donnée tierce — pas uniquement les clés propres à l'addon. Tout site hôte utilisant la session pour autre chose que l'analytics était donc exposé à une perte silencieuse de données à la première page vue.

Correctif

Suppression du bloc invalidate() / regenerate() et de la sauvegarde manuelle du consentement qui le compensait. Le middleware pose désormais uniquement ses propres clés de session (analytics_session_started, visitor_id, visited_pages, etc.) sans jamais toucher aux données existantes.

Changements

  • src/Middleware/TrackPageVisit.php — suppression de invalidate(), regenerate() et de la restauration de analytics_consent / analytics_settings
  • tests/TrackPageVisitSessionTest.php — test de non-régression test_tracking_does_not_destroy_existing_session
  • README.md — section Privacy & tracking : garantie explicite de préservation de la session applicative

Mise à jour recommandée

Cette version est un correctif de sécurité fonctionnelle. La mise à jour est recommandée pour tous les sites utilisant la session Laravel (panier, auth, formulaires multi-étapes, etc.).

3.1.2

August 6th, 2026

Correctif

Compatibilité multi-driver dans getHeatmapData()

Le widget heatmap utilisait strftime() (syntaxe SQLite uniquement), ce qui provoquait une erreur silencieuse sur MySQL et MariaDB.

getHeatmapData() détecte désormais le driver actif via DB::getDriverName() et sélectionne les expressions SQL correspondantes :

Driver Heure Jour
SQLite strftime('%H', visited_at) strftime('%w', visited_at) + 1
MySQL / MariaDB HOUR(visited_at) DAYOFWEEK(visited_at)

Les deux expressions retournent le même encodage de jour (1=Dim … 7=Sam), le remapping interne vers 0=Lun … 6=Dim reste inchangé.

Requirements mis à jour

SQLite, MySQL et MariaDB sont désormais officiellement supportés.

Ce qui ne change pas

Aucune migration, aucun changement de configuration.

3.1.1

August 5th, 2026

Correctif

Filtre Content-Type dans isTrackableResponse()

Le filtre HTTP 200 introduit en v3.1.0 ne suffisait pas à lui seul : les assets statiques servis en 200 par des addons tiers (fichiers .js, .wasm, etc. — ex. vendor/statamic-cap/*) étaient comptabilisés comme des pages vues.

isTrackableResponse() vérifie désormais en plus que le Content-Type de la réponse commence par text/html. Les réponses JSON, JavaScript, WebAssembly, CSS et autres types non-HTML sont silencieusement ignorées.

Ce qui ne change pas

  • Aucune migration, aucun changement de configuration
  • shouldTrack() et le bloc de tracking : inchangés
  • Str était déjà importé — aucun ajout d'import

3.1.0

August 5th, 2026

Nouveauté

Middleware après — filtrage par statut HTTP

Le middleware TrackPageVisit est converti en middleware après : $next($request) est désormais appelé en premier, et l'insertion en base n'a lieu que si la réponse retourne exactement HTTP 200.

Avant : toutes les requêtes correspondant aux critères de shouldTrack() étaient enregistrées, y compris celles aboutissant en 404 — scans automatisés testant des chemins WordPress/PHP (wp-admin/install.php, phpmyadmin, etc.), sondes de pénétration, robots d'indexation mal configurés.

Après : seules les pages effectivement servies (200) sont comptabilisées. Les 404 sont silencieusement ignorées, sans liste d'exclusion manuelle à maintenir.

Ce qui ne change pas

  • shouldTrack() et tous ses filtres (consent, exclude_paths, exclude_ips, exclude_bots, track_authenticated_users) — inchangés, appliqués cumulativement
  • Le bloc de tracking (session, visitor_id, géolocalisation, insertion DB) — strictement identique
  • Aucune migration, aucun changement de configuration

Mise à jour sans action requise

Déployer le code suffit. Aucune publication de config ni migration.

3.0.2

August 5th, 2026

Correctifs

Bug Carbon 3.x — diffIn*() absolu explicite

Carbon 3.x a changé le comportement par défaut de diffIn*() : $absolute vaut désormais false (au lieu de true en 2.x), provoquant des valeurs négatives dans les calculs de durée de session.

AnalyticsDashboardController

  • getTopPages() — temps moyens par page retournaient des valeurs négatives
  • getUserFlow() — pages engagées calculées incorrectement
  • calculateAverageTimeOnSite() — rendu explicite par cohérence
  • $periodLength (diffInDays) — rendu explicite par cohérence

CacheManager

  • cleanupFiles() — bug silencieux : la condition diffInSeconds retournait une valeur négative, donc les fichiers de cache expirés n'étaient jamais supprimés depuis le passage à Carbon 3.x

Dashboard.vue

  • formatDuration() — filet défensif : une valeur < 0 affiche désormais 0:00 au lieu d'un résultat absurde

Mise à jour des assets

Rebuild Vite inclus.

3.0.1

August 5th, 2026

Correctif — Fuite mémoire dans GeolocationService

Problème

trackLookup() utilisait une clé de cache globale unique avec un TTL glissant de 30 jours. Le tableau unique_ips à l'intérieur croissait indéfiniment tant qu'il y avait du trafic.

Correctif

  • trackLookup : clé journalière geolocation_stats_YYYY-MM-DD avec TTL fixe de 32 jours — chaque entrée expire naturellement, unique_ips est borné à une journée de trafic.
  • getStats(int $days = 30) : agrège les N dernières clés journalières au lieu de lire une clé globale. Signature rétrocompatible (valeur par défaut 30).
  • clearCache : simplifié — les clés expirent d'elles-mêmes via leur TTL, aucun nettoyage manuel nécessaire.

Aucun changement de comportement pour les appelants existants.

3.0.0

August 5th, 2026

Breaking change — Politique de rétention IP par défaut

Les adresses IP et user-agents des pages vues de plus de 90 jours sont désormais anonymisés (mis à NULL) automatiquement par une commande planifiée quotidienne. Les statistiques de fréquentation (visites, visiteurs uniques) et les données de géolocalisation déjà résolues ne sont pas affectées.

Migration requise

php artisan migrate

Nouveautés

  • Nouvelle section privacy.ip_retention_days dans la config (défaut : 90 jours, via ANALYTICS_IP_RETENTION_DAYS)
  • Nouvelle commande analytics:anonymize-ips avec option --dry-run
  • Planification quotidienne automatique via le scheduler Laravel

Options

Ajuster la durée de rétention :

ANALYTICS_IP_RETENTION_DAYS=30

Désactiver l'anonymisation automatique (non recommandé) :

ANALYTICS_IP_RETENTION_DAYS=null

⚠️ Le mot null doit être écrit littéralement. Une valeur vide (ANALYTICS_IP_RETENTION_DAYS=) serait interprétée comme une chaîne vide et provoquerait une anonymisation immédiate de la quasi-totalité des données.

Voir UPGRADE.md pour le guide de migration complet.

2.0.1

November 29th, -0001

  • N/A Changelog not available.

2.0.0

August 4th, 2026

⚠ Breaking change

The default geolocation provider has changed from ip-api to maxmind.

If you never set ANALYTICS_GEO_PROVIDER in your .env, your installation was using ip-api. After upgrading, it will silently switch to maxmind, which requires a free MaxMind account and credentials.

Migration options — see UPGRADE.md for full details:

  • Keep using ip-api: add ANALYTICS_GEO_PROVIDER=ip-api to your .env
  • Set up MaxMind: add MAXMIND_ACCOUNT_ID + MAXMIND_LICENSE_KEY, then run php artisan analytics:update-geoip
  • Disable geolocation entirely: ANALYTICS_GEO_PROVIDER=disabled

What's new

analytics:update-geoip command rewritten

  • No more system callscurl via system()/exec() replaced by Laravel's Http facade (Guzzle)
  • SHA-256 integrity check after download via MaxMind's ?suffix=tar.gz.sha256 endpoint
  • Atomic .mmdb write — staging copy on the same filesystem + POSIX rename(), eliminating any partial-read window for concurrent requests; explicit fallback copy() with warning if cross-device
  • Return value checks on every copy(), rename(), and fallback copy() — clean FAILURE returned at each step
  • Collision-safe temp filenames via uniqid() instead of time()
  • PharData::extractTo() wrapped in try/catch \PharException|\Exception with guaranteed cleanup
  • Checksum URL derived from $this->url — no more independent string to keep in sync
  • File permissions read from config('statamic-analytics.cache.file.permissions.file', 0644)
  • Network errors caught via ConnectionException with clear error messages

Control Panel warning banner

When maxmind is the active provider but credentials are missing, a warning banner is displayed in the analytics dashboard with a link to the setup procedure and a mention of the disabled alternative.

Geographic widgets hidden when disabled

When provider = disabled, the Top countries and Top cities widgets are removed from the dashboard entirely — no empty widget, no placeholder.

Throttled "database missing" log

The Log::warning that fired on every request when the .mmdb file was not found is now capped to once per hour via Cache::remember.


Bug fixes

  • rename() cross-device failure: fallback to copy()+unlink() with warn() (not error()) and return value check
  • countryChart: guarded with if (countryChartEl.value) on init and && countryChart in updateState to prevent a crash when the canvas element is absent due to v-if

Documentation

  • UPGRADE.md added with full migration guide
  • README: providers table updated, .env example with all three options commented, note on the CP warning banner and widget hiding behaviour

1.3.3

November 29th, -0001

  • N/A Changelog not available.

1.3.2

November 29th, -0001

  • N/A Changelog not available.

1.3.1

November 29th, -0001

  • N/A Changelog not available.

1.3.0

November 29th, -0001

  • N/A Changelog not available.

1.2.8

November 29th, -0001

  • N/A Changelog not available.

1.2.7

July 29th, 2026

  • New 'analytics_overview' widget displaying stats for the last 7 days (today's visits, page views, unique visitors)
  • Blade view using native Statamic CP classes (no additional build step required)
  • Auto-injected into the CP dashboard if not already manually configured

1.2.6

June 16th, 2026

  • N/A Changelog not available.

1.2.5

June 16th, 2026

  • N/A Changelog not available.

1.2.4

May 27th, 2026

  • N/A Changelog not available.

1.2.3

May 27th, 2026

  • N/A Changelog not available.

1.2.2

May 27th, 2026

correction consent banner

1.2.1

May 27th, 2026

correction name consent banner

1.2.0

May 26th, 2026

  • N/A Changelog not available.

1.1.0

March 19th, 2026

traduction

1.0.18

June 21st, 2025

  • N/A Changelog not available.

1.0.17

June 21st, 2025

  • N/A Changelog not available.

1.0.16

June 21st, 2025

  • N/A Changelog not available.

1.0.15

June 21st, 2025

  • N/A Changelog not available.

1.0.14

June 21st, 2025

  • N/A Changelog not available.

1.0.13

June 21st, 2025

  • N/A Changelog not available.

1.0.12

March 5th, 2025

  • N/A Changelog not available.

1.0.11

March 5th, 2025

  • N/A Changelog not available.

1.0.10

March 5th, 2025

  • N/A Changelog not available.

1.0.9

January 15th, 2025

  • N/A Changelog not available.

1.0.8

January 15th, 2025

  • N/A Changelog not available.

1.0.7

January 14th, 2025

  • N/A Changelog not available.

1.0.6

January 14th, 2025

  • N/A Changelog not available.

1.0.5

January 12th, 2025

  • N/A Changelog not available.

1.0.4

January 12th, 2025

  • N/A Changelog not available.

1.0.3

January 12th, 2025

  • N/A Changelog not available.

1.0.2

January 12th, 2025

  • N/A Changelog not available.

1.0.1

January 12th, 2025

  • N/A Changelog not available.

1.0.0

May 26th, 2026

  • N/A Changelog not available.

1.0.0

March 19th, 2026

1ère release