Skip to main content

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.

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,
});
OptionDefaultDescription
baseURLhttps://ingest.mostlygoodmetrics.comAPI endpoint
environment"production"Environment name
appVersion-App version (required for install/update tracking)
maxBatchSize100Events per batch
flushInterval30Auto-flush interval in seconds
maxStoredEvents10000Max cached events
enableDebugLoggingfalseEnable console output
trackAppLifecycleEventstrueAuto-track lifecycle events
existingInstallationfalseBaseline lifecycle state on a provider migration without emitting $app_installed
contextProvider-Dynamic properties evaluated for every event
optedOutByDefaultfalseStart opted out until optIn() is called (Privacy)
collectDevicePropertiestrueCollect device properties

Automatic Events​

EventWhenProperties
$app_installedFirst launch after install$version
$app_updatedFirst launch after version change$version, $previous_version
$app_openedApp became active (foreground)-
$app_backgroundedApp 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`);