Skip to main content

Flutter SDK

A lightweight Flutter SDK with full cross-platform support.

Requirements​

  • Flutter 3.10+
  • Dart 3.0+

Platform Support​

PlatformSupported
iOSYes
AndroidYes
WebYes
macOSYes
WindowsYes
LinuxYes

Installation​

Add to your pubspec.yaml:

dependencies:
mostly_good_metrics_flutter: ^0.8.0

Then run:

flutter pub get

For iOS privacy manifest coverage, use shared_preferences ^2.2.3, path_provider ^2.1.3, and device_info_plus ^11.1.1 or compatible newer versions. See Apple privacy manifests and App Store labels for the app-level manifest and label.

Quick Start​

Initialize​

Initialize once at app startup (typically in main.dart):

import 'package:flutter/material.dart';
import 'package:mostly_good_metrics_flutter/mostly_good_metrics_flutter.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();

await MostlyGoodMetrics.configure(
MGMConfiguration(apiKey: 'mgm_proj_your_api_key'),
);

runApp(MyApp());
}

Track Events​

// Simple event
MostlyGoodMetrics.track('button_clicked');

// Event with properties
MostlyGoodMetrics.track('purchase_completed', properties: {
'product_id': 'SKU123',
'price': 29.99,
'currency': 'USD',
});

Identify Users​

// Set user identity
await MostlyGoodMetrics.identify('user_123');

// Reset identity (e.g., on logout)
await MostlyGoodMetrics.resetIdentity();

Configuration Options​

await MostlyGoodMetrics.configure(
MGMConfiguration(
apiKey: 'mgm_proj_your_api_key',
baseUrl: 'https://ingest.mostlygoodmetrics.com',
environment: 'production',
appVersion: '1.0.0',
maxBatchSize: 100,
flushInterval: 30,
maxStoredEvents: 10000,
enableDebugLogging: kDebugMode,
trackAppLifecycleEvents: true,
),
);
OptionDefaultDescription
apiKeyRequiredYour API key
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 debug 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 manufacturer, locale, timezone

Automatic Events​

EventWhenProperties
$app_installedFirst launch after install-
$app_updatedFirst launch after version changeprevious_version, current_version
$app_openedApp started-
$app_foregroundedApp became active-
$app_backgroundedApp 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.

await MostlyGoodMetrics.configure(MGMConfiguration(
apiKey: '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. DEBUG builds report invalid event names and reserved custom $ property keys.

Session Management​

// Start a new session manually
await MostlyGoodMetrics.startNewSession();

// Access current session ID
final sessionId = MostlyGoodMetrics.sessionId;

Privacy​

The SDK never collects advertising identifiers (IDFA/GAID), precise location, contacts, or any other personal data you don't explicitly pass to track() or identify(). identify() is entirely optional — without it, users are tracked under a random anonymous ID ($anon_...) generated by the SDK, not derived from the device.

Opt-out​

// Stop all tracking immediately. track(), identify(), and flush() become
// no-ops, and any queued (unsent) events are deleted. The choice is
// persisted and survives app restarts.
await MostlyGoodMetrics.optOut();

// Check the current state
final optedOut = MostlyGoodMetrics.isOptedOut;

// Resume tracking (also persisted)
await MostlyGoodMetrics.optIn();

For consent-first apps (e.g. GDPR), start opted out and only opt in after consent:

await MostlyGoodMetrics.configure(
MGMConfiguration(
apiKey: 'mgm_proj_your_api_key',
optedOutByDefault: true,
),
);

// Later, once the user consents:
await MostlyGoodMetrics.optIn();

A persisted opt-in/opt-out choice always takes precedence over optedOutByDefault.

Rotating the anonymous ID​

Generate a fresh anonymous ID so future events can't be linked to earlier anonymous activity:

await MostlyGoodMetrics.resetAnonymousId();

Forget me​

For a complete local reset (e.g. a user deletes their account):

await MostlyGoodMetrics.resetIdentity(clearAnonymousId: true);

This clears the user ID, rotates the anonymous ID, deletes all pending (unsent) events, clears super properties and sticky local experiment assignments, and starts a new session.

Limiting device properties​

await MostlyGoodMetrics.configure(
MGMConfiguration(
apiKey: 'mgm_proj_your_api_key',
collectDeviceProperties: false,
),
);

When disabled, events omit device manufacturer, locale, and timezone. Platform, OS version, and app version are still included.

Error Handling​

try {
MostlyGoodMetrics.track('invalid-event-name');
} on MGMError catch (e) {
print('Error type: ${e.type}');
print('Message: ${e.message}');
}

Error types:

  • MGMErrorType.notConfigured - SDK not configured
  • MGMErrorType.invalidEventName - Invalid event name
  • MGMErrorType.invalidProperties - Invalid properties
  • MGMErrorType.networkError - Network failure
  • MGMErrorType.rateLimited - API rate limited

Manual Flush​

await MostlyGoodMetrics.flush();

// Check pending events
final count = await MostlyGoodMetrics.getPendingEventCount();
print('$count events pending');

// Clear pending events
await MostlyGoodMetrics.clearPendingEvents();