Capacitor SDK
The official Capacitor SDK for hybrid mobile apps.
Requirements
- Capacitor 5+
- iOS and Android support
Installation
Use Capacitor SDK 0.5.1 or later for the native storage, initialization, and lifecycle safeguards described below.
npm install @mostly-good-metrics/capacitor@^0.5.1
Required Peer Dependencies
npm install @capacitor/core @capacitor/app @capacitor/device @capacitor/preferences
npx cap sync
On iOS, the core Capacitor pod has a privacy manifest from 5.7.3 onward. The @capacitor/app, @capacitor/device, and @capacitor/preferences plugins still need app-level declarations. See Apple privacy manifests and App Store labels, including the UserDefaults CA92.1 entry for Preferences.
Quick Start
Initialize
Initialize as early as possible in your app:
import MostlyGoodMetrics from '@mostly-good-metrics/capacitor';
MostlyGoodMetrics.configure('mgm_proj_your_api_key', {
appVersion: '1.0.0',
environment: 'production',
});
Track Events
MostlyGoodMetrics.track('button_clicked', {
button_name: 'signup',
screen: 'home',
});
Identify Users
MostlyGoodMetrics.identify('user-123');
Super Properties
Set properties that will be included with every event:
// Set a single super property
MostlyGoodMetrics.setSuperProperty('plan', 'premium');
// Set multiple super properties
MostlyGoodMetrics.setSuperProperties({
plan: 'premium',
tier: 'gold',
});
// Remove a super property
MostlyGoodMetrics.removeSuperProperty('plan');
// Clear all super properties
MostlyGoodMetrics.clearSuperProperties();
Configuration Options
| Option | Default | Description |
|---|---|---|
appVersion | - | App version for install/update tracking |
environment | 'production' | Environment name |
maxBatchSize | 100 | Max events per batch |
flushInterval | 30 | Seconds between auto-flushes |
maxStoredEvents | 10000 | Max events to store locally |
enableDebugLogging | false | Enable console logging |
trackAppLifecycleEvents | true | Track app open/background 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
When trackAppLifecycleEvents is enabled (default):
| Event | When |
|---|---|
$app_installed | First launch after install |
$app_updated | First launch after app version change |
$app_opened | App came to foreground |
$app_backgrounded | App went to 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 Capacitor 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 handles both thrown errors and rejected removal promises.
Call MostlyGoodMetrics.destroy() when tearing down the SDK. Pending
initialization cannot recreate the client or overwrite a later configuration;
listeners that finish registering after teardown are removed. 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.
If a native lifecycle listener cannot be removed, its callbacks become inert and the SDK avoids registering more listeners while removal is pending. A late successful removal can resume subscriptions; a failed removal disables further subscriptions for that process. Manual tracking remains available during this lifecycle fallback.
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 Capacitor Preferences 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 = MostlyGoodMetrics.resetAnonymousId();
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 Capacitor configuration.
Manual Flush
MostlyGoodMetrics.flush();
Platform Support
- iOS
- Android
- Web (with limited lifecycle tracking)