Analytics et Google Tag ManagerL'analytics dans eQuantic.UI est une capacité, pas un script que l'on colle : une page demande IAnalytics comme elle demande une caméra, et elle n'apprend jamais qui écoute. Le paquet eQuantic.UI.Gtm est un INSTALLEUR : un appel câble un conteneur Google Tag Manager à cette capacité, de bout en bout.
Depuis 0.2.0-preview.29
builder.Services.AddUI(options => options
.ScanAssembly(typeof(Program).Assembly)
Ce seul appel installe trois choses dans le shell HTML :
1.
L'extrait officiel du conteneur : les mêmes octets que Google documente, paramétrés seulement là où GTM lui-même les gabarise.
2.
La déclaration de l'installeur (window.__EQ_ANALYTICS__) : ce qui arme la réalisation d'IAnalytics du runtime. Sans installeur, le suivi est une opération nulle silencieuse, par conception.
3.
Les vues de page en SPA : le routeur client annonce chaque navigation validée (eq:navigate), et le shell la transforme en pushes de page_view portant page_path et page_title, les noms de champ propres à GA4. Le conteneur voit le chargement initial de lui-même ; voici les navigations qu'il ne peut pas voir.
L'id du conteneur est validé au démarrage : un id avec une coquille installe un conteneur qui ne collecte rien en silence, et cela se découvre dans le rapport vide du mois suivant, donc refuser tôt est l'échec le plus aimable.
public override VisualNode Build(ComponentContext context)
_analytics = context.GetService<IAnalytics>();
private async Task Submit()
// …après que le serveur a dit oui :
_analytics?.Track("sign_up");
_analytics?.Track("purchase", new Dictionary<string, object?>
Track est fire-and-forget par contrat, parce que l'analytics ne doit jamais faire attendre une page. Les noms d'événements sont VOTRE vocabulaire (sign_up, begin_checkout) ; le framework n'en invente ni n'en préfixe aucun. Sur le serveur le même appel est une opération nulle : le SSR n'est pas un utilisateur, et une page qui suivrait pendant le rendu compterait ses propres crawlers.
Un conteneur par application, à dessein
Un conteneur GTM se charge dans le DOCUMENT et ne se décharge jamais, donc dans une SPA un "conteneur par page" ne peut pas exister. La variation par route est ce à quoi servent les propres déclencheurs du conteneur : le page_view automatique porte page_path précisément pour que le marketing puisse déclencher des tags par route sans que l'application change, et c'est tout l'intérêt d'un gestionnaire de tags.
Ce qui existe, c'est le cas agence plus client : appelez UseGtm une fois par conteneur. Le second appel n'ajoute que son extrait ; les deux roulent sur le même dataLayer (la règle propre à GTM pour plusieurs conteneurs, appliquée au démarrage).
.UseGtm("GTM-XXXXXXX", gtm => gtm
.WithDataLayerName("eqData") // quand un autre script possède déjà `dataLayer`
.WithoutSpaPageViews() // le conteneur utilise le déclencheur d'historique de GA4
.WithEnvironment("auth…", "env-9") // environnements GTM (gtm_auth / gtm_preview)
.WithConsent()) // charge le conteneur seulement après le consentement
Activez WithoutSpaPageViews() quand le conteneur suit lui-même les changements d'historique, ou la même navigation est comptée deux fois.
Consentement (RGPD / LGPD)
ÉTAT : LIVRÉ EN 0.2.0-PREVIEW.46
Les deux réglementations disent la même chose des cookies d'analytics : rien n'est posé avant que la visiteuse dise oui, et un "non" est retenu. Trois pièces rendent cela vrai sans que l'application écrive une ligne de JavaScript :
•
IConsent : une capacité comme une autre (context.GetService<IConsent>()) : State vaut Unknown, Granted ou Denied ; Grant() / Deny() enregistrent la réponse. Sur le web elle vit dans UN cookie, eq-consent, pendant un an, et un changement est annoncé sur le document comme eq:consent. Sur le serveur le même cookie est LU depuis la requête, donc le premier affichage d'une visiteuse qui revient ne contient aucune bannière, et la passe SSR connaît la réponse que détient le navigateur.
•
CookieConsent(policyHref) : la carte qui demande. Dessinée seulement pendant que la réponse est inconnue, partie dès qu'elle est donnée ; deux boutons (accepter / refuser) et le lien vers la politique de confidentialité, le tout localisé (EN, pt-BR, es) et chaque élément surchargeable. C'est une carte, pas une couche : mettez-la là où le shell la veut (un Pinned au bas de la page est son logis habituel).
•
UseGtm(id, gtm => gtm.WithConsent()) : l'installeur conditionne le conteneur à la réponse. Le head déclare les valeurs par défaut denied du Consent Mode de Google, et le script du conteneur n'est récupéré que lorsque le cookie dit granted, ou au moment où eq:consent le dit. Une visiteuse qui refuse ou ne répond jamais ne télécharge aucun gestionnaire de tags. Les appels à Track() faits entre-temps restent dans le tableau du dataLayer, que le conteneur rejoue si le consentement arrive plus tard.
builder.Services.AddUI(o => o.ScanAssembly(typeof(Program).Assembly)
.UseGtm("GTM-XXXXXXX", gtm => gtm.WithConsent()));
// quelque part que chaque page rend, au bas de son shell :
Pinned(CookieConsent("/privacy"))
Désactivé par défaut : un installeur qui tournait déjà sans demander continue de tourner. L'activer est la décision de l'application, appariée à la carte et à une page de politique derrière le lien, parce qu'une carte de consentement sans politique derrière est une promesse que le site ne peut pas tenir.
Ce qui est délibérément absent
•
L'iframe <noscript> des instructions d'installation de Google. Elle mesure les utilisateurs dont le navigateur n'exécute aucun JavaScript, et un tel utilisateur ne reçoit aucune application ici : il n'y a rien à mesurer.
•
Une réalisation native. IAnalytics se résout en une opération nulle dans une fenêtre Photon aujourd'hui ; les ponts d'analytics mobiles arrivent avec la voie native.
•
Capacités : le motif demander-par-interface que suit IAnalytics.