JavaScript SDK
A lightweight JavaScript/TypeScript SDK for web applications.
Requirements
- Node.js 16+ (for build tools)
- Modern browser with ES2020 support, or Node.js runtime
Installation
Use JavaScript SDK 0.13.1 or later for the exception containment and bounded event storage described below.
npm install @mostly-good-metrics/javascript@^0.13.1
Quick Start
Initialize
import { MostlyGoodMetrics } from '@mostly-good-metrics/javascript';
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
trackPageViews: true, // Enable the Web Analytics overview
});
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 (optional - anonymous ID is auto-generated)
MostlyGoodMetrics.identify('user_123');
// Reset identity (e.g., on logout)
MostlyGoodMetrics.resetIdentity();
User Identification
The SDK automatically generates and persists an anonymous user_id (UUID) for each user:
- Auto-generated on first visit
- Persists across sessions (stored in cookies and localStorage)
- Included in every event as
user_id
When you call identify(), the identified user ID takes precedence.
Cross-Subdomain Tracking
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
cookieDomain: '.yourdomain.com', // Share across all subdomains
});
Privacy Mode (No Cookies)
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
disableCookies: true, // Only use localStorage
});
Configuration Options
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
baseURL: 'https://ingest.mostlygoodmetrics.com',
environment: 'production',
appVersion: '1.0.0',
maxBatchSize: 100,
flushInterval: 30,
maxStoredEvents: 10000,
enableDebugLogging: process.env.NODE_ENV === 'development',
trackAppLifecycleEvents: true,
trackPageViews: true,
});
| Option | Default | Description |
|---|---|---|
apiKey | Required | Your API key |
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 |
enableDebugLogging | false | Enable console output |
trackAppLifecycleEvents | false | Auto-track lifecycle events |
trackPageViews | false | Capture initial and SPA page views plus visible-page engagement |
sessionTimeoutMinutes | 30 | Start a new website visit after this many inactive minutes |
existingInstallation | false | Baseline lifecycle state on a provider migration without emitting $app_installed |
contextProvider | - | Dynamic properties evaluated for every event; precedence is super properties, context, event properties, then MGM system properties |
cookieDomain | - | Cookie domain for cross-subdomain tracking |
disableCookies | false | Disable cookies, use only localStorage |
persistence | 'localStorage+cookie' | Where state persists: 'localStorage+cookie', 'localStorage', or 'memory' |
respectDoNotTrack | false | Treat browsers with DNT or GPC enabled as opted out (Privacy) |
optedOutByDefault | false | Start opted out until optIn() is called (Privacy) |
collectDeviceProperties | true | Collect device properties |
Automatic Events
Website analytics
Set trackPageViews: true to capture an initial page_view, History API and
back/forward navigation, and $page_engagement when the current page becomes
hidden. This powers the Web Analytics screen without replacing your product
events.
Page views include the URL, hostname, pathname, title, referrer/referring
domain, and UTM campaign values. Browser sessions continue across reloads and
navigation, then renew after 30 minutes of inactivity. The SDK also attaches
browser, OS, device, screen, viewport, and user-agent context unless
collectDeviceProperties is disabled.
When trackAppLifecycleEvents is enabled:
| Event | When | Properties |
|---|---|---|
$app_installed | First visit (localStorage) | $version |
$app_updated | Version change detected | $version, $previous_version |
$app_opened | Page load / tab visible | - |
$app_backgrounded | Tab hidden / page unload | - |
Migration and dynamic context
For an existing site moving from another provider, derive existingInstallation
from that provider's persisted install marker. Do not set it to true for
all users: that would suppress genuine new installs.
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
existingInstallation: legacyAnalytics.hasInstallationMarker(),
contextProvider: () => ({ active_workspace_id: currentWorkspaceId() }),
});
contextProvider runs for every event. Its values override super properties;
explicit event properties and MGM system properties take precedence. With
enableDebugLogging, MGM warns when custom properties use reserved $ keys.
Callback and failure handling
contextProvider runs synchronously on the JavaScript caller. Return ordinary
JSON-like values; asynchronous providers are unsupported. Provider exceptions
are contained, unreadable property getters are omitted, and traversal of nested
objects and arrays is bounded. Properties are copied at capture time, including
super properties.
Automatic batch, timer, and page-exit work handles storage and network failures internally. If an error callback returns a rejected promise, MGM observes that rejection without waiting for the callback to complete. Explicitly awaited operations retain their failure contract for custom adapters:
try {
await MostlyGoodMetrics.flush();
} catch (error) {
// Handle an unexpected failure from a custom storage or network adapter.
}
Also handle promises returned by clearPendingEvents() and
getPendingEventCount() when using custom adapters.
Built-in event stores enforce a 1 MiB serialized event-data ceiling as well as
maxStoredEvents. They drop the oldest events when either limit is reached and
reject oversized persisted queues before parsing. Analytics can be dropped to
protect the host during long offline periods; a custom storage adapter must
enforce its own resource limits.
Call MostlyGoodMetrics.reset() when tearing down the singleton. This stops
its timers, removes browser hooks, and aborts its built-in network requests.
Late responses from the destroyed instance cannot update its experiment cache.
Privacy
The SDK collects no advertising identifiers or precise client location.
identify() is optional — without it, users are tracked under a random,
resettable anonymous ID ($anon_...). Automatic browser/device context is
documented above and can be disabled with collectDeviceProperties: false;
page URL, title, referrer, and campaign values are collected only when
trackPageViews is enabled.
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 choice is persisted and survives page loads.
For consent-first sites (e.g. GDPR), start opted out and call optIn() after consent:
MostlyGoodMetrics.configure({
apiKey: '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 visits.
Do Not Track / Global Privacy Control
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
respectDoNotTrack: true,
});
When enabled, browsers with Do Not Track (navigator.doNotTrack === '1') or Global Privacy Control (navigator.globalPrivacyControl === true) are treated as opted out automatically.
Persistence modes
MostlyGoodMetrics.configure({
apiKey: 'mgm_proj_your_api_key',
persistence: 'memory', // nothing written to disk
});
| Mode | Behavior |
|---|---|
'localStorage+cookie' (default) | localStorage plus a cookie (enables cross-subdomain tracking) |
'localStorage' | No cookies — same as disableCookies: true |
'memory' | Nothing persisted; IDs and the event queue live only for the page session |
Rotating the anonymous ID
Rotate the anonymous ID so future events can't be linked to earlier anonymous activity:
const newId = MostlyGoodMetrics.resetAnonymousId();
Forget me
resetIdentity() clears the user ID (e.g. on logout); 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({
apiKey: 'mgm_proj_your_api_key',
collectDeviceProperties: false,
});
Framework Integration
React
// src/analytics.ts
import { MostlyGoodMetrics } from '@mostly-good-metrics/javascript';
export function initAnalytics() {
MostlyGoodMetrics.configure({
apiKey: process.env.REACT_APP_MGM_API_KEY!,
environment: process.env.NODE_ENV,
appVersion: process.env.REACT_APP_VERSION,
});
}
// src/index.tsx
import { initAnalytics } from './analytics';
initAnalytics();
Next.js
// lib/analytics.ts
import { MostlyGoodMetrics } from '@mostly-good-metrics/javascript';
export function initAnalytics() {
if (typeof window !== 'undefined') {
MostlyGoodMetrics.configure({
apiKey: process.env.NEXT_PUBLIC_MGM_API_KEY!,
environment: process.env.NODE_ENV,
});
}
}
// app/layout.tsx
'use client';
import { useEffect } from 'react';
import { initAnalytics } from '@/lib/analytics';
export default function RootLayout({ children }) {
useEffect(() => {
initAnalytics();
}, []);
return <html>...</html>;
}
Vue
// src/plugins/analytics.ts
import { MostlyGoodMetrics } from '@mostly-good-metrics/javascript';
export default {
install() {
MostlyGoodMetrics.configure({
apiKey: import.meta.env.VITE_MGM_API_KEY,
environment: import.meta.env.MODE,
});
}
};
// src/main.ts
import analytics from './plugins/analytics';
app.use(analytics);
TypeScript Support
Full TypeScript support with exported types:
import {
MostlyGoodMetrics,
MGMConfiguration,
MGMEvent,
EventProperties,
} from '@mostly-good-metrics/javascript';