Skip to content
Concept

Google Analytics Operations

Configure consent-gated Central GA4 collection, server-allowlisted demo collection, and reports in the Central admin.

Google Analytics Operations

This is a Central operator task, not an App SDK integration. Configure browser collection and server reports separately using the example below; confirm consent refusal and customer-tenant exclusion before accepting the setup. App code must not initialize GA directly. See Configuration Ownership for the boundary.

Configure and observe

For a production deployment that collects indexable marketing pages, the developer portal, and the public demo, configure:

Code example
DOTENV
GOOGLE_ANALYTICS_ENABLED=true
GOOGLE_ANALYTICS_MEASUREMENT_ID=G-XXXXXXXXXX
GOOGLE_ANALYTICS_COLLECT_SUBDOMAINS=developers
GOOGLE_ANALYTICS_COLLECT_TENANT_FIXTURES=demo

ANALYTICS_PROPERTY_ID=123456789
ANALYTICS_CREDENTIALS_BASE64=<base64-service-account-json>
ANALYTICS_CACHE_STORE=file
ANALYTICS_CACHE_MINUTES=60
ANALYTICS_STALE_CACHE_MINUTES=10080
ANALYTICS_CLICK_DIMENSIONS_ENABLED=false
ANALYTICS_REQUEST_TIMEOUT_MILLISECONDS=12000

Clear configuration cache after changing environment values. Visit an indexable central page without consent and confirm no GA request or _ga cookie appears. Grant consent and confirm a page view is sent. Decline again and confirm the cookies are removed. Open a normal customer tenant and confirm the shell config contains no demo measurement ID; repeat on the demo fixture tenant and confirm collection begins only after its demo initialization path.

Sign in to the Central admin and open the four analytics pages. The overview, acquisition, content, and surfaces reports should render for the selected period. If a Data API refresh fails, the last successful report may be served for up to the stale-cache window. A missing report with working browser collection usually means the numeric property, credential, Data API access, or cache configuration is wrong—not that the public measurement ID failed.

What it is

Nexia has one application-owned Google Analytics 4 integration with two separate halves. Browser collection sends page and interaction events from consented Central surfaces and the server-allowlisted demo fixture. Server-side reporting reads the GA4 Data API and renders four operator reports in the Central Filament admin. The public measurement ID and the private reporting credentials are intentionally separate configuration.

How it fits

Central browser injection occurs only when all of these are true:

  1. GOOGLE_ANALYTICS_ENABLED is true and a measurement ID is present.
  2. The request is an indexable marketing document, or its host begins with a configured GOOGLE_ANALYTICS_COLLECT_SUBDOMAINS entry.
  3. The visitor grants analytics consent.

The default extra Central host is developers, which lets the developer portal collect even though it is not a marketing document. Authentication and other unregistered Central pages remain dark.

The tenant shell has a narrower rule. It injects demo analytics only when the current tenant's fixture_key appears in GOOGLE_ANALYTICS_COLLECT_TENANT_FIXTURES; the default is demo. Customer tenants carry no fixture key and therefore cannot match, even if their domain is renamed. Do not replace this with a broad tenant-domain rule.

The Central browser runtime starts with analytics storage denied, disables advertising features and personalization, and sends no typed event before initialization. On decline it updates consent to denied, sets the GA disable flag, and removes _ga* cookies. Destination tracking strips query strings and fragments. The supported application events are navigation_click, cta_click, generate_lead, demo_session_start, and demo_app_opened. Never put names, email addresses, tenant identifiers, free-form user values, or other PII in event parameters.

Server-side reporting uses these independent settings:

SettingDefaultMeaning
ANALYTICS_PROPERTY_IDexample property in .env.exampleNumeric GA4 property, not the G- measurement ID
ANALYTICS_CREDENTIALS_BASE64emptyPreferred production secret: Base64 service-account JSON
ANALYTICS_CREDENTIALS_PATHprivate storage pathLocal or mounted JSON fallback when Base64 is absent
ANALYTICS_CACHE_STOREfileLaravel cache store for reports
ANALYTICS_CACHE_MINUTES60Fresh report lifetime
ANALYTICS_STALE_CACHE_MINUTES10080Last successful report fallback after refresh failure
ANALYTICS_REQUEST_TIMEOUT_MILLISECONDS12000Data API request timeout
ANALYTICS_CLICK_DIMENSIONS_ENABLEDfalseEnables custom click dimensions only after GA4 registration

The Central admin registers only google-analytics-dashboard, google-analytics-acquisition, google-analytics-content, and google-analytics-surfaces. No corresponding tenant-admin pages exist.

Boundaries

Keep collection disabled in local and staging environments unless they have a dedicated non-production data stream. Reusing production pollutes acquisition, retention, and content reports with development traffic. A measurement ID is public configuration; the numeric property ID selects the server report, and service-account credentials are secrets. Mount the JSON outside the repository or provide the Base64 secret. Never commit credentials.

Consent is not only a banner state. New Central tracking code must call the typed, consent-aware analytics entrypoint so it is a no-op before initialization. The demo tracker initializes only after the server injects its allowlisted fixture configuration. Do not call the GA library directly from an App. New event parameters need a privacy review and stable low-cardinality values.

The interaction report's element_id, placement, and destination_path columns depend on event-scoped GA4 custom dimensions. Leave ANALYTICS_CLICK_DIMENSIONS_ENABLED=false until all three matching dimensions are registered on the property. Enabling it early makes the Data API reject the custom-dimension report; collection itself can continue while the flag is off.

Source of truth: docs/developers/content/en/operations/analytics.md