@codeimplants/analytics
v0.2.0
Published
Shared analytics SDK for all **CodeImplants** mobile apps (React Native).
Readme
@codeimplants/analytics
Shared analytics SDK for all CodeImplants mobile apps (React Native).
Built on top of @react-native-firebase/analytics (GA4), this package provides a safe, centralized, and governed analytics layer — ensuring your app never crashes due to analytics, events are always valid, and data is always clean.
Table of Contents
- Features
- Prerequisites
- Installation
- Setup: React Native (Firebase)
- Initialization
- API Reference
- Available Events
- Types
- Integration Patterns
- Environment Behaviour
- Internal Safeguards
- Mandatory Rules
Features
- ✅ Never crashes the app — every analytics call is wrapped in a try/catch
- ✅ Clean GA4 data — only pre-approved event names can be tracked
- ✅ Environment separation — analytics is disabled in
localenvironments automatically - ✅ Double-init protection — calling
initmore than once is a no-op - ✅ Rate-limiting guard — rapid duplicate events are throttled (min 300ms apart)
- ✅ Payload sanitization — max 25 params, max 100 chars per value, type-safe
- ✅ GA4 DebugView — automatically enabled for non-production environments
- ✅ User identity management —
setUser/clearUser
Prerequisites
This package requires @react-native-firebase/analytics to be installed and configured in your host app.
- React Native
>=0.72 @react-native-firebase/appconfigured@react-native-firebase/analyticsinstalled
Install Firebase in your app
# npm
npm install @react-native-firebase/app @react-native-firebase/analytics
# yarn
yarn add @react-native-firebase/app @react-native-firebase/analyticsFor platform-specific Firebase setup (google-services.json / GoogleService-Info.plist), follow the React Native Firebase documentation.
Installation
From npm (public package)
npm install @codeimplants/analyticsFrom a monorepo (workspace)
If your app is in the same monorepo, add the workspace reference in your app's package.json:
{
"dependencies": {
"@codeimplants/analytics": "*"
}
}Setup: React Native (Firebase)
Ensure your Firebase project is connected:
- Create a Firebase project at https://console.firebase.google.com
- Register your Android and iOS apps
- Download
google-services.json→ place underandroid/app/ - Download
GoogleService-Info.plist→ place underios/<AppName>/ - Follow the native setup steps from rnfirebase.io
Initialization
Call Analytics.init once at the very start of your app — before any screen renders or events fire.
import { Analytics } from "@codeimplants/analytics";
Analytics.init({
appName: "my-app",
environment: "prod", // "dev" | "qa" | "preprod" | "prod"
appVersion: "1.0.0",
enableAnalytics: true,
});⚠️ Init is idempotent — calling it more than once is safely ignored. Only the first call takes effect.
⚠️ Analytics is disabled in
localenvironment — events will be silently dropped even ifenableAnalytics: true.
API Reference
Analytics.init
Analytics.init(config: AnalyticsConfig): voidInitializes the analytics SDK with your app's configuration and sets up the GA4 adapter.
| Parameter | Type | Required | Description |
| ----------------- | ---------------------- | -------- | ------------------------------------------- |
| appName | string | ✅ | Name of the app (used as an event property) |
| environment | AnalyticsEnvironment | ✅ | One of dev, qa, preprod, prod |
| appVersion | string | ✅ | App version string (e.g. "2.1.0") |
| enableAnalytics | boolean | ✅ | Master kill-switch for all analytics |
Analytics.track
Analytics.track(
eventName: AnalyticsEventName,
payload?: AnalyticsEventPayload
): Promise<void>Tracks a custom event. Only events from AnalyticsEvents are accepted.
Automatic enrichment — every event payload is automatically extended with:
environment— the configured environmentapp_name— the configured app nameapp_version— the configured app version
Payload sanitization rules:
- Maximum 25 parameters per event (extras are dropped)
- String values are truncated to 100 characters
- Only
string,number,booleanvalues are allowed (nulls are filtered)
import { Analytics, AnalyticsEvents } from "@codeimplants/analytics";
await Analytics.track(AnalyticsEvents.LOGIN_SUCCESS, {
method: "email",
user_type: "premium",
});Analytics.screen
Analytics.screen(screenName: string): Promise<void>Logs a screen view event to Firebase Analytics via logScreenView. Sets both screen_name and screen_class to the provided value.
await Analytics.screen("HomeScreen");Analytics.setUser
Analytics.setUser(userId: string): Promise<void>Associates all subsequent events with the given user ID (calls Firebase setUserId).
await Analytics.setUser("user_abc123");Analytics.clearUser
Analytics.clearUser(): Promise<void>Removes the user ID association. Call this on logout.
await Analytics.clearUser();Available Events
All valid event names are defined in AnalyticsEvents. Do not use raw strings — always import and use this constant.
import { AnalyticsEvents } from "@codeimplants/analytics";| Constant | Event Name | Category |
| ------------------------- | ------------------------- | --------------------- |
| SCREEN_VIEW | screen_view | Navigation |
| LOGIN_SUCCESS | login_success | Auth |
| LOGIN_FAILURE | login_failure | Auth |
| LOGOUT | logout | Auth |
| API_FAILURE | api_failure | Network / Reliability |
| RETRY_ATTEMPT | retry_attempt | Network / Reliability |
| OFFLINE_DETECTED | offline_detected | Network / Reliability |
| APP_OPEN | app_open | App Lifecycle |
| APP_BACKGROUND | app_background | App Lifecycle |
| SUPPORT_CONTACTED | support_contacted | Support |
| APP_UPDATE_PROMPT_SHOWN | app_update_prompt_shown | Updates |
🚫 Any event name not in this list will be silently dropped at the validator level.
Types
import type {
AnalyticsConfig,
AnalyticsEnvironment,
AnalyticsEventPayload,
} from "@codeimplants/analytics";AnalyticsEnvironment
type AnalyticsEnvironment = "dev" | "qa" | "preprod" | "prod";AnalyticsConfig
type AnalyticsConfig = {
appName: string;
environment: AnalyticsEnvironment;
appVersion: string;
enableAnalytics: boolean;
};AnalyticsEventPayload
type AnalyticsEventPayload = Record<string, string | number | boolean | null>;AnalyticsEventName
// Derived automatically — union of all values in AnalyticsEvents
type AnalyticsEventName = "screen_view" | "login_success" | "login_failure" | ...;Integration Patterns
React Native App (Expo / Bare)
Initialize analytics in your root App.tsx or index.js:
// App.tsx
import React, { useEffect } from "react";
import { Analytics, AnalyticsEvents } from "@codeimplants/analytics";
const APP_ENV = process.env.APP_ENV ?? "local"; // "local" | "dev" | "qa" | "prod"
Analytics.init({
appName: "my-app",
environment: APP_ENV as any,
appVersion: "1.0.0",
enableAnalytics: APP_ENV !== "local",
});
export default function App() {
useEffect(() => {
Analytics.track(AnalyticsEvents.APP_OPEN);
}, []);
return <RootNavigator />;
}Navigation Screen Tracking
Automatically log screen views with React Navigation:
import { NavigationContainer } from "@react-navigation/native";
import { Analytics } from "@codeimplants/analytics";
export default function RootNavigator() {
return (
<NavigationContainer
onStateChange={(state) => {
const currentRoute = state?.routes[state.index];
if (currentRoute?.name) {
Analytics.screen(currentRoute.name);
}
}}
>
{/* your navigators */}
</NavigationContainer>
);
}Authentication Events
import { Analytics, AnalyticsEvents } from "@codeimplants/analytics";
// On successful login
async function handleLoginSuccess(userId: string) {
await Analytics.setUser(userId);
await Analytics.track(AnalyticsEvents.LOGIN_SUCCESS, { method: "email" });
}
// On login failure
async function handleLoginFailure(reason: string) {
await Analytics.track(AnalyticsEvents.LOGIN_FAILURE, { reason });
}
// On logout
async function handleLogout() {
await Analytics.track(AnalyticsEvents.LOGOUT);
await Analytics.clearUser();
}App Lifecycle Events
import { useEffect } from "react";
import { AppState } from "react-native";
import { Analytics, AnalyticsEvents } from "@codeimplants/analytics";
export function useAppLifecycleTracking() {
useEffect(() => {
const subscription = AppState.addEventListener("change", (nextState) => {
if (nextState === "background" || nextState === "inactive") {
Analytics.track(AnalyticsEvents.APP_BACKGROUND);
}
});
return () => subscription.remove();
}, []);
}Network / Reliability Events
import { Analytics, AnalyticsEvents } from "@codeimplants/analytics";
// Track API failure
async function fetchData(endpoint: string) {
try {
const res = await fetch(endpoint);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (error) {
await Analytics.track(AnalyticsEvents.API_FAILURE, {
endpoint,
error: String(error),
});
throw error;
}
}
// Track retry attempt
async function retryFetch(endpoint: string, attempt: number) {
await Analytics.track(AnalyticsEvents.RETRY_ATTEMPT, { endpoint, attempt });
return fetchData(endpoint);
}
// Track offline state
import NetInfo from "@react-native-community/netinfo";
NetInfo.addEventListener((state) => {
if (!state.isConnected) {
Analytics.track(AnalyticsEvents.OFFLINE_DETECTED);
}
});User Identity
import { Analytics } from "@codeimplants/analytics";
// Set user after login / session restore
await Analytics.setUser("user_42abc");
// Clear user on logout or session expiry
await Analytics.clearUser();Environment Behaviour
| Environment | Analytics Collected | DebugView (GA4) |
| ----------- | ------------------- | --------------- |
| dev | ✅ If enabled | ✅ Enabled |
| qa | ✅ If enabled | ✅ Enabled |
| preprod | ✅ If enabled | ✅ Enabled |
| prod | ✅ If enabled | ❌ Disabled |
Even if
enableAnalytics: true, thelocalenvironment will never send events to Firebase. This prevents development noise in your GA4 dashboard.
Internal Safeguards
The following safety mechanisms are built into the SDK — you don't need to implement them yourself:
| Safeguard | Description |
| --------------------- | ------------------------------------------------------------------ |
| Try/Catch wrapper | All Firebase calls are wrapped — analytics never crashes the app |
| Double-init guard | init can only take effect once per app session |
| Event allowlist | Unknown event names are silently dropped by the validator |
| Rate-limit guard | Events fired within 300ms of each other are dropped |
| Payload sanitizer | Max 25 params, max 100 chars per string value, filters null values |
| Environment gate | local environment always skips tracking |
| Init check | track / screen are no-ops if init was never called |
Mandatory Rules
| Rule | Detail |
| ------------------------------------------------------------------------ | ------------------------------------------------------- |
| ❌ Do NOT import @react-native-firebase/analytics directly in your app | Always go through this SDK |
| ❌ Do NOT invent or hardcode event name strings | Always use AnalyticsEvents.* constants |
| ✅ Call Analytics.init exactly once at app startup | Place it before any screen renders |
| ✅ Always use Analytics.setUser after login | And clearUser on logout |
| ✅ Use Analytics.screen for screen tracking | Integrate with your navigation library's state listener |
