@metricflow-ai/web
v0.1.1
Published
MetricFlow browser analytics SDK for event tracking, user identification, and behavioral analytics.
Readme
MetricFlow Browser SDK
A browser analytics SDK for tracking events, identifying users, and capturing behaviour on any web app.
Table of Contents
- Installation
- Quick Start
- Configuration
- Core API
- Identity
- Super Properties
- User Profile API
- Auto-Captured Properties
- Autocapture
- Privacy Controls
- Opt In / Opt Out
- Link and Form Helpers
- Common Patterns
- Public Methods Reference
Installation
npm install @metricflow-ai/webQuick Start
import { metricflow } from "@metricflow-ai/web";
await metricflow.init("YOUR_PROJECT_ID", {
track_pageview: true,
autocapture: false,
debug: true,
});
metricflow.identify("user_123", {
email: "[email protected]",
name: "Alex Kumar",
plan: "free",
});
metricflow.track("signup_started", {
plan: "free",
});Configuration
init(projectId, config?) — projectId (first argument) is required. The config object (second argument) is entirely optional; every field below has a working default.
await metricflow.init("YOUR_PROJECT_ID", {
persistence: "localStorage",
batch_requests: true,
batch_size: 20,
batch_flush_interval_ms: 3000,
track_pageview: true,
autocapture: false,
debug: false,
});| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| projectId | string | Required (first argument to init(), not part of the config object) | Your MetricFlow project ID. |
| endpoint | string | Optional | Full /api/track URL. Only needed to point at a custom ingestion endpoint — most integrations don't need this. |
| api_host | string | Optional | API origin, e.g. https://api.example.com. Used when endpoint is not set. |
| persistence | "cookie" | "localStorage" | Optional | Where to store identity and super properties. Default: "localStorage". |
| batch_requests | boolean | Optional | Batch events before sending. Default: true. |
| batch_size | number | Optional | Number of events per batch flush. |
| batch_flush_interval_ms | number | Optional | Auto-flush interval in milliseconds. |
| track_pageview | boolean \| string | Optional | true, "url-with-path", "url-with-path-and-query-string", or "full-url". Controls automatic pageview tracking. |
| autocapture | boolean \| object | Optional | Default false. Enable automatic click/input/form/scroll capture. |
| debug | boolean | Optional | Print SDK logs to the browser console. |
Core API
track(eventName, properties?)
Track any custom event.
metricflow.track("button_clicked", {
label: "Start Trial",
location: "hero",
});track_pageview(properties?, options?)
Manually track a pageview. Useful in SPAs where the URL changes without a full page reload.
metricflow.track_pageview({ page_title: document.title });
// Track with full URL mode
metricflow.track_pageview({}, { mode: "full-url" });time_event(eventName)
Start timing an event. The next track() call with the same event name will include a duration_ms property.
metricflow.time_event("checkout_completed");
// later...
metricflow.track("checkout_completed", { amount: 49 });
// → event includes duration_ms automaticallyIdentity
identify(userId, traits?)
Link future events to a known user. Call this after login.
metricflow.identify("user_123", {
email: "[email protected]",
name: "Alex Kumar", // use "name" key — not "fullName" or "displayName"
plan: "pro",
});Reserved trait keys (used by the Users list):
| Trait key | Example | Notes |
| --- | --- | --- |
| name | "Alex Kumar" | Primary display name. |
| email | "[email protected]" | Primary email. |
Optional common traits:
| Trait key | Example |
| --- | --- |
| first_name | "Alex" |
| last_name | "Kumar" |
| phone | "+15551234567" |
| plan | "pro" |
| role | "admin" |
| company | "Acme" |
| created_at | "2026-06-24T10:00:00Z" |
reset()
Clear current user identity and session. Always call this on logout.
metricflow.reset();After reset, the SDK assigns a new anonymous ID — the next identify() starts a fresh user.
alias(newId, originalId?)
Merge two identities (anonymous pre-login → known post-login).
metricflow.alias("user_123");get_distinct_id()
Read the current distinct ID (anonymous or identified).
const id = metricflow.get_distinct_id();Super Properties
Super properties are stored in the browser and automatically merged into every future event.
// Set on every event from now on
metricflow.register({
app_version: "1.2.0",
org_id: "org_456",
});
// Set only if not already set
metricflow.register_once({
first_landing_page: window.location.pathname,
});
// Remove a super property
metricflow.unregister("org_id");
// Read a super property
const version = metricflow.get_property("app_version");User Profile API
Update profile properties independently of event tracking.
metricflow.people.set({ plan: "pro", role: "admin" });
metricflow.people.set_once({ first_seen_at: new Date().toISOString() });
metricflow.people.increment("login_count", 1);
metricflow.people.append("recent_actions", "opened_dashboard");
metricflow.people.union("features_used", "autocapture");
metricflow.people.unset(["temporary_flag"]);Revenue tracking:
metricflow.people.track_charge(49, { currency: "USD", plan: "pro" });
metricflow.people.clear_charges();
metricflow.people.delete_user();Auto-Captured Properties
Every event automatically includes these properties — you do not need to set them manually.
| Property | Example value | Description |
| --- | --- | --- |
| lib | "metricflow-js" | SDK name. |
| lib_version | "1.0.0" | SDK version. |
| platform | "Web" | Always "Web" for browser SDK. |
| browser | "Chrome" | Detected browser. |
| browser_version | "120" | Detected browser version. |
| os | "Windows" | Detected OS. |
| device | "Desktop" | "Mobile" | Device type. |
| language | "en-US" | Browser language. |
| screen_width | 1440 | Screen width in pixels. |
| screen_height | 900 | Screen height in pixels. |
| viewport_width | 1440 | Viewport width in pixels. |
| viewport_height | 765 | Viewport height in pixels. |
| pathname | "/dashboard" | Current page pathname. |
| host | "app.example.com" | Current page host. |
| referring_domain | "google.com" | Domain of the referrer page. |
| timezone | "Asia/Calcutta" | Browser timezone. |
| search_engine | "google" | Detected search engine (if referrer is a search engine). |
| search_keyword | "analytics tool" | Search keyword (if referrer is a search engine). |
Autocapture
Autocapture is off by default. Enable it only when you want automatic interaction tracking.
// Disabled (default) — only manual track() calls fire
await metricflow.init("PROJECT_ID", { autocapture: false });
// Enabled — captures clicks, inputs, forms, and scroll depth automatically
await metricflow.init("PROJECT_ID", {
autocapture: true,
track_pageview: true,
});With autocapture: true, the SDK fires:
| Event | Trigger |
| --- | --- |
| $mf_click | Any element click |
| $mf_form_submit | Form submission |
| $mf_input | Input / select / textarea change (values not captured) |
| $mf_scroll | Scroll depth checkpoints |
Granular Autocapture Config
await metricflow.init("PROJECT_ID", {
track_pageview: "url-with-path",
autocapture: {
click: true,
input: true,
submit: true,
scroll: true,
scroll_depth_percent_checkpoints: [25, 50, 75, 100],
rage_click: true,
dead_click: true,
capture_text_content: false,
},
});| Option | Default | Description |
| --- | --- | --- |
| click | true | Capture clicks. |
| input | true | Capture input/select/textarea changes. Values are not captured. |
| submit | true | Capture form submissions. |
| scroll | true | Capture scroll depth checkpoints. |
| scroll_depth_percent_checkpoints | [25, 50, 75, 100] | Which scroll percentages trigger events. |
| scroll_capture_all | false | Fire on every throttled scroll instead of checkpoints only. |
| page_leave | false | Flush pending events when the user leaves the page. |
| rage_click | false | Detect repeated nearby clicks. |
| dead_click | false | Detect clicks that do not navigate or change state. |
| capture_text_content | false | Include element text for non-sensitive elements. |
Privacy Controls
Add any of these CSS classes to an element to block autocapture on it:
<button class="metricflow-no-track">Not captured</button>
<button class="mf-no-track">Not captured</button>
<button class="mp-no-track">Not captured</button>Block or allow elements and URLs via config:
await metricflow.init("PROJECT_ID", {
autocapture: {
block_selectors: [".sensitive", "[data-private='true']"],
allow_selectors: [".analytics-allowed"],
block_url_regexes: [/\/checkout/],
capture_text_content: false,
block_element_callback: element => element.hasAttribute("data-no-track"),
},
});Opt In / Opt Out
metricflow.opt_out_tracking(); // stop tracking
metricflow.has_opted_out_tracking(); // → true
metricflow.opt_in_tracking(); // resume tracking
metricflow.has_opted_in_tracking(); // → true
metricflow.clear_opt_in_out_tracking(); // clear persisted preferenceWhen opted out, no events are queued or sent.
Link and Form Helpers
Attach tracking to specific elements without writing individual listeners.
metricflow.track_links("a.pricing-link", "pricing_link_clicked", {
area: "header",
});
metricflow.track_forms("form.newsletter", "newsletter_submitted", {
source: "footer",
});Common Patterns
Login flow
// After successful login
metricflow.identify(String(user.id), {
name: `${user.first_name} ${user.last_name}`,
email: user.email,
});
metricflow.register({
org_id: user.orgId,
user_role: user.role,
});
metricflow.track("user_logged_in");Logout flow
metricflow.track("user_logged_out");
// Always reset on logout — clears identity and session
metricflow.reset();SPA pageview tracking (Next.js / React Router)
// Call on every route change instead of using track_pageview: true
metricflow.track_pageview({ page_title: document.title });Public Methods Reference
| Method | Purpose |
| --- | --- |
| init(projectId, config?) | Initialize the SDK. Call before anything else — calls made earlier are buffered and replayed once init() resolves, but relying on that isn't recommended. |
| track(eventName, properties?) | Track a custom event. |
| track_pageview(properties?, options?) | Track a pageview manually. |
| time_event(eventName) | Start timing an event. |
| identify(userId, traits?) | Link events to a known user. Call after login. |
| alias(newId, originalId?) | Merge two identities. |
| reset() | Clear identity and session state. Call on logout. |
| get_distinct_id() | Read the current distinct ID. |
| register(properties) | Set persistent super properties. |
| register_once(properties, defaultValue?) | Set super properties only if not already set. |
| unregister(propertyName) | Remove a super property. |
| get_property(propertyName) | Read a super property value. |
| opt_in_tracking() | Resume event tracking. |
| opt_out_tracking() | Stop event tracking. |
| has_opted_in_tracking() | Check if user has explicitly opted in. |
| has_opted_out_tracking() | Check if user has opted out. |
| clear_opt_in_out_tracking() | Clear persisted opt-in/out state. |
| get_config(key?) | Read current SDK config. |
| set_config(config) | Update SDK config at runtime. |
| track_links(query, eventName, properties?) | Attach click tracking to matched elements. |
| track_forms(query, eventName, properties?) | Attach submit tracking to matched forms. |
| push(command) | Run a queued snippet-style command. |
| flush() | Immediately flush all queued events. |
| people.set(properties) | Set user profile properties. |
| people.set_once(properties) | Set profile properties only if not already set. |
| people.unset(properties) | Remove profile properties. |
| people.increment(property, value?) | Increment a numeric profile property. |
| people.append(property, value?) | Append a value to a profile list property. |
| people.union(property, value?) | Add unique values to a profile list property. |
| people.track_charge(amount, properties?) | Track a revenue charge. |
| people.clear_charges() | Clear stored charges. |
| people.delete_user() | Delete the user profile. |
License
MIT — see LICENSE.
