Overview

Prev Next

Analytics (GA4) Overview

ONECMS tracks user behavior via Google Analytics 4 using a typed, envelope-based event system. The architecture supports two delivery modes — one where the CMS owns the full pipeline (script injection through to gtag calls), and another where the CMS generates a GA-compatible payload and hands it off to a third-party library.

Related Decisions

  • ADR-018: Typed Analytics Architecture
  • RFC-001: GA4 Event Contract
  • RFC-002: GA4 Authentication Event Contract
  • RFC-003: GA4 Customer Support Event Contract

Delivery Modes

Image

Mode Script ownership Delivery Status
Owned pipeline CMS injects gtag.js via GoogleAnalytics component window.gtag('event', ...) Active
Third-party mode External package provides its own tags/scripts Payload handed to external SDK Planned

In both modes, the event generation and normalization layers are identical — only the last-mile delivery differs.

Source Layout

src/
  lib/external/GA.ts                          # GA transport class
  modules/GoogleAnalytics.tsx                  # Script injection component (Mode 1)
  adapters/analytics/
    normalizeAnalyticsPayload.adapter.ts       # Payload normalization
  types/analytics/
    index.ts                                   # Envelope, categories, registry
    authentication/index.ts                    # Auth events + payload map
    customer-support/index.ts                  # CS events + payload map
    upload/index.ts                            # Upload events + payload map
    content/index.ts                           # Content events (stub)
    monetization/index.ts                      # Monetization events (stub)
    navigation/index.ts                        # Navigation events (stub)
    appcms/index.ts                            # AppCMS events (stub)
  lib/helpers/customer-support/analytics.ts    # Domain-specific tracking helpers
  config/config.ts                             # GA config (measurementId, limits)
File Role
GA.ts Static transport — normalizes envelope, gates on production, calls gtag
GoogleAnalytics.tsx Next.js <Script> tags for gtag.js + dataLayer init
normalizeAnalyticsPayload.adapter.ts Truncates strings, joins arrays, enforces param limit
types/analytics/index.ts Envelope type, category union, CategoryEventMap, AllAnalyticsEnvelopes
types/analytics/{domain}/index.ts Per-domain event names, payload types, payload maps
config.tsConfig.GA measurementId, schema_version, string_char_limit, param_limit
helpers/.../analytics.ts Domain-scoped convenience functions (e.g., customer support)

Configuration

All analytics configuration lives in Config.GA:

GA: {
  measurementId: process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID,
  schema_version: '1.0',
  string_char_limit: 100,  // max chars per string param
  param_limit: 25,         // max params per event (GA4 limit)
}
Setting Source Purpose
measurementId NEXT_PUBLIC_GA_MEASUREMENT_ID GA4 property identifier
schema_version Hardcoded in config Payload contract version — increment on breaking changes only
string_char_limit NEXT_PUBLIC_GA_STRING_LIMIT (default 100) Truncation threshold for string values
param_limit NEXT_PUBLIC_GA_PARAM_LIMIT (default 25) Max event parameters sent to GA4

Design Principles

  • Type safety end-to-end — every event is typed from domain code through to the gtag call; invalid category/event combinations are compile errors
  • Production-only emission — non-production events are logged to console and never sent to GA4, preventing data pollution
  • Normalization as an adapter — payload truncation, array joining, and param limits are isolated in a single adapter, not scattered across callers
  • Schema versioning — a schema_version field travels with every event so dashboards can distinguish incompatible payload shapes
  • Fire-and-forget — event emission never throws, never blocks UI, never retries
  • Transport-agnostic envelope — the AllAnalyticsEnvelopes type is the contract; how the payload reaches GA4 is a delivery concern, not a domain concern

Doc Index

Page Covers
Pipeline Mode 1 — script injection, GA.ts transport, consent, production gating
Event Contracts Type system — envelope, categories, payload maps, adding new events
Third-Party Mode Mode 2 — payload-only delivery via external libraries (planned)