Definition
When sending product intent such as button clicks, checkout start, or login success to analytics tools, screen code does not call vendor SDKs like Google Tag Manager (GTM) or PostHog directly. Instead it uses one API such as useTelemetry().track(...).
A facade is a simple front desk in front of complex plumbing. Fan-out means one track call is replicated to multiple sinks — systems that receive data.
Why It Matters
Mixing posthog.capture and dataLayer.push at call sites means (1) events reach only one sink, (2) replacing a sink requires changing the whole app, and (3) SDK exceptions can break checkout or login flows. A facade lets consumers speak intent only while the Provider owns init, routing, and masking.
How It Works
TelemetryProviderinitializes sinks and exposes actions via context.track({ event, ...props })→ push to primary sink (e.g. dataLayer) → route matching events only to secondary sink (e.g. PostHog).identify(userId, traits)/reset()align login/logout boundaries.- Each sink has an independent env gate (no-op that sink only when key is missing).
- All sink calls use try/catch best-effort — analytics failure must not stop business logic.
Practical Application
- Code review/lint so new events go through the hook only (denylist direct vendor SDK imports).
- Turn off autocapture and use explicit track only for easier noise and quota control.
- If using session replay, set masking defaults for inputs and images in init.
- Helpers that are exported but have zero consumers are dead paths — document as Non-goals so they are not revived during migration.
Trade-offs
| Choice | Upside | Cost |
|---|---|---|
| Single facade | Consistent reach, easy swap | Provider design and testing |
| Direct SDK at call sites | Fast short term | Drift and exception propagation |
| Best-effort swallow | UX protection | Silent failure — dashboard smoke needed |
When Not to Use
- Records where loss is unacceptable such as server audit logs or payment ledgers (do not rely on client analytics layer).
- Blindly replicating PII in props to multiple sinks (schema and masking first).
Common Mistakes
- Mixing
capturePostHogandtrack→ GTM not reached. - Omitting
reseton logout so previous user session continues. - Analytics mock throws in tests with no try/catch, failing checkout tests.
Related Concepts
- react-context-render-granularity — Render scope when injecting actions via Provider