Analytics y Google Tag ManagerAnalytics en eQuantic.UI es una capacidad, no un script que se pega: una página pide IAnalytics igual que pide una cámara, y nunca llega a saber quién está escuchando. El paquete eQuantic.UI.Gtm es un INSTALADOR: una llamada conecta un contenedor de Google Tag Manager a esa capacidad, de punta a punta.
Desde 0.2.0-preview.29
builder.Services.AddUI(options => options
.ScanAssembly(typeof(Program).Assembly)
Esa única llamada instala tres cosas en el shell de HTML:
1.
El fragmento oficial del contenedor: los mismos bytes que documenta Google, parametrizados solo donde GTM mismo los plantilla.
2.
La declaración del instalador (window.__EQ_ANALYTICS__): lo que arma la realización de IAnalytics del runtime. Sin un instalador, el seguimiento es una no-operación silenciosa por diseño.
3.
Vistas de página en la SPA: el router del cliente anuncia cada navegación confirmada (eq:navigate), y el shell la convierte en pushes de page_view que llevan page_path y page_title, los nombres de campo propios de GA4. El contenedor ve la carga inicial por sí mismo; estas son las navegaciones que no puede ver.
El id del contenedor se valida al arrancar: un id con una errata instala un contenedor que no recoge nada en silencio, y eso se descubre en el informe vacío del mes siguiente, así que negarse pronto es el fallo más amable.
Seguimiento desde una página
public override VisualNode Build(ComponentContext context)
_analytics = context.GetService<IAnalytics>();
private async Task Submit()
// …después de que el servidor dijo sí:
_analytics?.Track("sign_up");
_analytics?.Track("purchase", new Dictionary<string, object?>
Track es fire-and-forget por contrato, porque analytics nunca debe hacer esperar a una página. Los nombres de evento son TU vocabulario (sign_up, begin_checkout); el framework nunca inventa ninguno ni le pone prefijo. En el servidor la misma llamada es una no-operación: el SSR no es un usuario, y una página que rastreara durante el renderizado contaría a sus propios crawlers.
Un contenedor por aplicación, a propósito
Un contenedor de GTM se carga en el DOCUMENTO y nunca se descarga, así que en una SPA un "contenedor por página" no puede existir. La variación por ruta es para lo que están los propios triggers del contenedor: el page_view automático lleva page_path precisamente para que marketing pueda disparar tags por ruta sin que la aplicación cambie, que es todo el sentido de un gestor de tags.
Lo que sí existe es el caso de agencia más cliente: llama a UseGtm una vez por contenedor. La segunda llamada añade solo su fragmento; los dos van sobre el mismo dataLayer (la regla propia de GTM para varios contenedores, aplicada al arrancar).
.UseGtm("GTM-XXXXXXX", gtm => gtm
.WithDataLayerName("eqData") // cuando otro script ya es dueño de `dataLayer`
.WithoutSpaPageViews() // el contenedor usa el trigger de historial de GA4
.WithEnvironment("auth…", "env-9") // entornos de GTM (gtm_auth / gtm_preview)
.WithConsent()) // carga el contenedor solo tras el consentimiento
Activa WithoutSpaPageViews() cuando el contenedor rastrea los cambios de historial él mismo, o la misma navegación se cuenta dos veces.
Consentimiento (GDPR / LGPD)
ESTADO: ENTREGADO EN LA 0.2.0-PREVIEW.46
Las dos regulaciones dicen lo mismo sobre las cookies de analytics: no se fija nada hasta que quien visita dice sí, y un "no" se recuerda. Tres piezas hacen que eso sea verdad sin que la aplicación escriba una línea de JavaScript:
•
IConsent: una capacidad como cualquier otra (context.GetService<IConsent>()): State es Unknown, Granted o Denied; Grant() / Deny() guardan la respuesta. En la web vive en UNA cookie, eq-consent, durante un año, y un cambio se anuncia en el documento como eq:consent. En el servidor la misma cookie se LEE de la petición, así que la primera pintura de quien vuelve no lleva banner alguno, y la pasada de SSR sabe la respuesta que guarda el navegador.
•
CookieConsent(policyHref): el cartel que pregunta. Se dibuja solo mientras la respuesta es desconocida, y se va en el momento en que se da; dos botones (aceptar / rechazar) y el enlace a la política de privacidad, todo localizado (EN, pt-BR, es) y cada parte sobrescribible. Es un cartel, no una capa: ponlo donde el shell quiera (un Pinned al fondo de la página es su casa habitual).
•
UseGtm(id, gtm => gtm.WithConsent()): el instalador condiciona el contenedor a la respuesta. El head declara los valores por defecto de denied del Consent Mode de Google, y el script del contenedor se descarga solo cuando la cookie dice granted, o en el momento en que eq:consent lo dice. Quien rechaza o nunca responde no descarga ningún gestor de tags. Las llamadas a Track() hechas mientras tanto se quedan en el array del dataLayer, que el contenedor reproduce si el consentimiento llega después.
builder.Services.AddUI(o => o.ScanAssembly(typeof(Program).Assembly)
.UseGtm("GTM-XXXXXXX", gtm => gtm.WithConsent()));
// en algún sitio que cada página renderice, al fondo de su shell:
Pinned(CookieConsent("/privacy"))
Desactivado por defecto: un instalador que ya corría sin preguntar sigue corriendo. Activarlo es la decisión de la aplicación, emparejada con el cartel y una página de política detrás del enlace, porque un cartel de consentimiento sin una política detrás es una promesa que el sitio no puede cumplir.
Lo que está deliberadamente ausente
•
El iframe <noscript> de las instrucciones de instalación de Google. Mide a usuarios cuyos navegadores no corren JavaScript, y tal usuario no recibe aplicación alguna aquí: no hay nada que medir.
•
Una realización nativa. IAnalytics se resuelve a una no-operación en una ventana de Photon hoy; los puentes de analytics móviles se suman con la vía nativa.
•
Capacidades: el patrón de pedir-por-interfaz que sigue IAnalytics.