Aller au contenu

Tracking & Analytics (Web + Native)

This document describes how advertising/marketing tracking and analytics providers are wired in the investor app across native (iOS/Android) and web (React Native Web) platforms.

Architecture overview

┌─────────────────────────────────────────────────────────────┐
│  Root Provider Stack (_layout.tsx)                           │
│                                                             │
│  ... > ProductTracking(PostHog) > AdvertisingTracking > ... │
│  ... > NavigationTrackingProvider > ...                      │
│                                                             │
│  (authenticated)                                            │
│  ... > UserTrackingProvider > ...                            │
└─────────────────────────────────────────────────────────────┘

Platform-specific implementations use Metro's .web.tsx resolution — no runtime platform checks needed.

Providers

AdvertisingTrackingProvider

Native Web
File src/providers/AdvertisingTrackingProvider/AdvertisingTrackingProvider.tsx ...AdvertisingTrackingProvider.web.tsx
SDK Facebook SDK + Firebase Analytics Google Tag Manager (GTM)
Consent ATT (App Tracking Transparency) None in code (handled by GTM consent mode)
Init Requests ATT → enables advertiser tracking + analytics collection Loads GTM snippet if advertisingTrackingEnabled && GTM_ID
Events AppEventsLogger (Facebook) + @react-native-firebase/analytics dataLayer.push({ event, ...params })

Event mapping (web): Brick event names are mapped to GTM-facing names via toGtmEventName():

App event GTM event
AccountCreation register-form-submitted
(others) see AdvertisingTrackingProvider.web.tsx

GTM tags: Facebook Pixel and Google Analytics are configured as tags inside the GTM container — they are not loaded separately in app code.

Customer.io

Native Web
File src/core/customerIO/utils.tsx src/core/customerIO/utils.web.tsx + snippet.web.ts
SDK customerio-reactnative + Expo plugin Customer.io CDP JS snippet (EU region)
Init Expo plugin auto-initializes at native build time loadCioSnippet(apiKey) runs at module evaluation
Screen views CustomerIO.screen(name) window.cioanalytics.page(name)
Identify CustomerIO.identify(userId) window.cioanalytics.identify(userId)
Reset CustomerIO.clearIdentify() window.cioanalytics.reset()

Integration points:

  • NavigationTrackingProvider calls trackScreenView(viewName) on route changes (both platforms)
  • UserTrackingProvider calls identifyUser(user.id) when the authenticated user is available
  • Push notifications pre-prompt (useDisplayPrePromptIfApplicable) is a no-op on web (index.web.ts)

ProductTrackingProvider (PostHog)

Single implementation (ProductTrackingProvider.tsx), no .web.tsx split. Uses PostHog for product analytics events. Not part of advertising tracking.

Configuration

All values come from Doppler and are injected as EXPO_PUBLIC_* env vars (baked into the bundle at build time):

Variable Required Purpose
EXPO_PUBLIC_ADVERTISING_TRACKING_ENABLED Yes Must be literal 'true' to enable advertising features
EXPO_PUBLIC_GTM_ID Web only GTM container ID. If unset, web advertising is disabled
EXPO_PUBLIC_CUSTOMER_IO_API_KEY Yes CDP write key (used by both native plugin and web snippet)
EXPO_PUBLIC_CUSTOMER_IO_SITE_ID Yes Site ID for native SDK

Web builds (Docker)

The Dockerfile passes these as ARGs so they are available at build time:

ARG EXPO_PUBLIC_GTM_ID
ARG EXPO_PUBLIC_ADVERTISING_TRACKING_ENABLED
ARG EXPO_PUBLIC_CUSTOMER_IO_API_KEY
ARG EXPO_PUBLIC_CUSTOMER_IO_SITE_ID

Native builds (Expo)

Customer.io is configured in app.config.ts via customerio-expo-plugin:

["customerio-expo-plugin", {
  config: {
    cdpApiKey: process.env.EXPO_PUBLIC_CUSTOMER_IO_API_KEY,
    siteId: process.env.EXPO_PUBLIC_CUSTOMER_IO_SITE_ID,
    region: "eu",
  },
}]

File map

src/
├── core/providers/
│   └── AdvertisingTrackingProvider/
│       ├── AdvertisingTrackingProvider.tsx       (native: ATT + Facebook + Firebase)
│       ├── AdvertisingTrackingProvider.web.tsx   (web: GTM dataLayer)
│       ├── gtm.web.ts                           (GTM snippet loader + pushToDataLayer)
│       └── types.ts                             (event names + params map)
├── core/customerIO/
│   ├── utils.tsx                                (native: customerio-reactnative)
│   ├── utils.web.tsx                            (web: CDP JS analytics)
│   ├── snippet.web.ts                           (web: script injection)
│   ├── index.ts                                 (native: push pre-prompt)
│   └── index.web.ts                             (web: no-op push pre-prompt)
├── core/providers/
│   ├── NavigationTrackingProvider/              (screen views → Customer.io + Datadog)
│   └── UserTrackingProvider.tsx                 (identify on auth → Customer.io)
└── core/config/
    └── config.ts                                (AppConfig: reads EXPO_PUBLIC_* env vars)

Adding a new tracking event

  1. Add the event name to BricksAdvertisingEvent in types.ts
  2. Add param types (if any) to AdvertisingEventParamsMap in types.ts
  3. In native: add the case to logAdvertisingEvent (uses AppEventsLogger + Firebase)
  4. In web: add the GTM event name mapping in toGtmEventName() (AdvertisingTrackingProvider.web.tsx)
  5. Configure the corresponding tag in the GTM container (external, not in code)

Troubleshooting

  • GTM not firing on web dev: Check that EXPO_PUBLIC_GTM_ID is set in your Doppler developement config
  • Customer.io not identifying: UserTrackingProvider only mounts inside the authenticated layout — unauthenticated screens won't identify
  • Native events not appearing: Verify ATT is granted (simulator always grants). Check Firebase Analytics debug view
  • Web events missing in GTM: Use GTM Preview mode to verify dataLayer.push calls are reaching the container