React Native SDK
A lightweight React Native SDK for iOS and Android.
Requirements
- React Native 0.71+
- Expo SDK 49+ (if using Expo)
Installation
Use React Native SDK 0.9.1 or later for the native storage, initialization, and teardown safeguards described below.
Expo (Recommended)
npm install @mostly-good-metrics/react-native@^0.9.1
That's it! Expo includes AsyncStorage by default.
Bare React Native
npm install @mostly-good-metrics/react-native@^0.9.1 @react-native-async-storage/async-storage
cd ios && pod install
For iOS privacy manifest coverage, use @react-native-async-storage/async-storage 1.23.1 or later. See Apple privacy manifests and App Store labels for the app-level manifest and label.
Quick Start
Initialize
import MostlyGoodMetrics from '@mostly-good-metrics/react-native';
MostlyGoodMetrics.configure('mgm_proj_your_api_key');
Track Events
// Simple event
MostlyGoodMetrics.track('button_clicked');
// Event with properties
MostlyGoodMetrics.track('purchase_completed', {
product_id: 'SKU123',
price: 29.99,
currency: 'USD',
});
Identify Users
// Set user identity
MostlyGoodMetrics.identify('user_123');
// Reset identity (e.g., on logout)
MostlyGoodMetrics.resetIdentity();
Configuration Options
import { version } from './package.json';
MostlyGoodMetrics.configure('mgm_proj_your_api_key', {
baseURL: 'https://ingest.mostlygoodmetrics.com',
environment: 'production',
appVersion: version,
maxBatchSize: 100,
flushInterval: 30,
maxStoredEvents: 10000,
enableDebugLogging: __DEV__,
trackAppLifecycleEvents: true,
});
| Option | Default | Description |
|---|---|---|
baseURL | https://ingest.mostlygoodmetrics.com | API endpoint |
environment | "production" | Environment name |
appVersion | - | App version (required for install/update tracking) |
maxBatchSize | 100 | Events per batch |
flushInterval | 30 | Auto-flush interval in seconds |
maxStoredEvents | 10000 | Max cached events |
enableDebugLogging | false | Enable console output |
trackAppLifecycleEvents | true | Auto-track lifecycle events |
existingInstallation | false | Baseline lifecycle state on a provider migration without emitting $app_installed |
contextProvider | - | Dynamic properties evaluated for every event |
optedOutByDefault | false | Start opted out until optIn() is called (Privacy) |
collectDeviceProperties | true | Collect device properties |
Automatic Events
| Event | When | Properties |
|---|---|---|
$app_installed | First launch after install | $version |
$app_updated | First launch after version change | $version, $previous_version |
$app_opened | App became active (foreground) | - |
$app_backgrounded | App resigned active (background) | - |
Migration and dynamic context
For an existing app moving from another provider, derive existingInstallation
from that provider's persisted installation marker. Do not set it to true
for every user, which would suppress genuine new installs.
MostlyGoodMetrics.configure('mgm_proj_your_api_key', {
existingInstallation: legacyAnalytics.hasInstallationMarker(),
contextProvider: () => ({ active_workspace_id: currentWorkspaceId() }),
});
Dynamic context overrides super properties; explicit event properties and MGM
system properties take precedence. With enableDebugLogging, MGM warns when
custom properties use reserved $ keys.
Failure handling and teardown
The SDK uses the JavaScript core with React Native storage and lifecycle adapters. Storage failures fall back to memory. Damaged persisted event queues are recovered while valid events are retained, and native listener cleanup and debug logging contain ordinary exceptions.
Call MostlyGoodMetrics.destroy() when tearing down the SDK. Pending
initialization from that configuration cannot recreate the client or overwrite
a later configuration. flush() handles delivery errors internally and can be
awaited to wait for the attempt to finish; resolution does not guarantee server
acceptance.
ready(timeoutMs) applies its deadline to native initialization as well as
experiment readiness. An unavailable native operation times out after five
seconds; later calls use current-process memory for that storage key. Writes
are coalesced so a stalled plugin cannot build an unbounded chain. A timed-out
write is not canceled by JavaScript, so the SDK avoids issuing newer writes
that the old operation could overwrite. This fallback is not durable across
process restarts. Unreadable or malformed native consent disables tracking
until an explicit optIn() or optOut() choice.
Startup calls and the built-in native event adapter each have a 1 MiB retained data budget in addition to event-count limits. Events can be dropped when those budgets are full or when persisted data is oversized or damaged. Event properties are copied before queuing. Teardown invalidates old adapter work, so a late read or save cannot resurrect an abandoned event queue.
Privacy
The SDK never collects advertising identifiers, location, or anything you don't explicitly pass to track() or identify(). identify() is optional — without it, users are tracked under a random, resettable anonymous ID ($anon_...).
Opt-out
MostlyGoodMetrics.optOut(); // stop all tracking immediately
MostlyGoodMetrics.optIn(); // resume tracking
MostlyGoodMetrics.isOptedOut(); // current state
While opted out, tracking calls are no-ops and queued (unsent) events are purged. The SDK attempts to persist the choice in AsyncStorage so it survives restarts when native storage is available.
For consent-first apps (e.g. GDPR), start opted out and call optIn() after consent:
MostlyGoodMetrics.configure('mgm_proj_your_api_key', {
optedOutByDefault: true, // no events until optIn() is called
});
A persisted opt-in/opt-out choice always wins over optedOutByDefault on later launches.
Rotating the anonymous ID
const newId = await MostlyGoodMetrics.resetAnonymousId(); // async in React Native
Forget me
resetIdentity() clears the user ID; pass clearAnonymousId: true for a full local reset:
MostlyGoodMetrics.resetIdentity({ clearAnonymousId: true });
This clears the user ID, rotates the anonymous ID, purges pending events and super properties, and starts a new session.
Limiting device properties
MostlyGoodMetrics.configure('mgm_proj_your_api_key', {
collectDeviceProperties: false,
});
The JS core's respectDoNotTrack and persistence options are web-only and are not part of the React Native configuration.
Manual Flush
MostlyGoodMetrics.flush();
// Check pending events
const count = await MostlyGoodMetrics.getPendingEventCount();
console.log(`${count} events pending`);