Flowgrid SDK
A production-grade, framework-agnostic TypeScript SDK for product analytics, ecommerce, experiments, and enterprise insights — with a single unified entry point that works in any JavaScript environment (Node, browsers, edge runtimes, React, Vue, Next, Nuxt, Svelte, Angular, etc.).
import { FlowGrid } from "flowgrid-sdk";
// One line. Sane defaults. Auto-instruments sessions, page views,
// performance, heatmaps, and attribution out of the box.
const fg = FlowGrid.init({
webId: "wx_123",
apiKey: "pk_xxx",
user: { userId: "u_1", traits: { plan: "pro" } },
// Opt in to session replay (rrweb) when you want it.
replay: { sampleRate: 0.25, maskAllInputs: true },
});
await fg.track("signup_completed", { plan: "pro" });
await fg.track("feature_used", { featureId: "export", featureName: "Data Export", userId: "u_1" });
await fg.track("experiment_exposure", { experimentId: "checkout_v2", variantId: "B", userId: "u_1" });
await fg.track("add_to_cart", { productId: "sku_1", name: "T-Shirt", price: 29, currency: "USD", quantity: 1 });Highlights
- One class, every feature —
new FlowGrid(...)exposes analytics, ecommerce, experiments, and enterprise modules as lazy properties. - Feature usage, explicit —
fg.track("feature_usage", { featureId, featureName }). You say what happened; the SDK just sends it. - Passive identity — opt in with
autoTrack({ passiveIdentity: true })to recognise anonymous visitors from any form (PII hashed in the browser). - Framework-agnostic — zero peer dependencies. Works with React, Vue, Next.js, Nuxt, Svelte, Astro, plain Node, Cloudflare Workers, etc.
- Tree-shake-friendly — also export individual modules (
Events,Products,Experiment, …) for minimal bundles. - Privacy & consent built-in — DNT/GPC support,
ConsentManager, bot filtering. - Resilient transport — retry with exponential backoff,
sendBeaconfallback, offlinelocalStoragebuffering, 10KB payload guard. - Identity layer — visitor + session lifecycle, SSR-safe, backwards-compatible with track.js cookies.
- Strict TypeScript — strong types for every config and response.
Installation
npm install flowgrid-sdk
# or
pnpm add flowgrid-sdk
# or
yarn add flowgrid-sdkRequires Node >= 18.12. No peer dependencies.
Quick Start
Unified client (recommended)
import { FlowGrid } from "flowgrid-sdk";
const fg = FlowGrid.init({
webId: "web_123",
apiKey: "key_xxx",
autoTrack: { heatmaps: { movement: true } },
});
// Plain custom events still work.
await fg.track("cta_click", { id: "hero" }, { userId: "u_1" });
// Feature usage — a plain event.
fg.track("feature_usage", { featureId: "data_export", featureName: "Data Export" });
// Recognized event names route to the matching feature module.
await fg.track("feature_used", { featureId: "export", featureName: "Data Export", userId: "u_1" });
await fg.track("prompt_submitted", { promptId: "p_1", promptType: "chat", userId: "u_1" });
await fg.track("experiment_conversion", { experimentId: "checkout_v2", variantId: "B", userId: "u_1", metricName: "purchase" });
await fg.track("purchase", { order });
await fg.track("support.ticket_created", { ticketId: "t_1", userId: "u_1", subject: "Help", category: "billing", priority: "medium", channel: "email" });Available namespaces on FlowGrid:
| Group | Properties |
|---|---|
| Core | activation, features, prompts, experiments |
| Analytics | pageViews, sessions, events, identify, funnels, retention, attribution, heatmaps, performance, replay |
| Ecommerce | products, cart, checkout, purchases, refunds, promotions, wishlist, ltv, search, subscriptions |
| Enterprise | engagement, cohorts, churn, monetization, multiPathFunnels, support, acquisition, paths, alerts, security, forecasting |
Direct module imports (tree-shaking)
import { Events, Products } from "flowgrid-sdk";
const events = new Events("web_123", "https://core.flow-grid.xyz", "key_xxx");
await events.track({ eventName: "signup", properties: { plan: "pro" } });Browser script tag (CMS / no-build)
<script src="https://cdn.flow-grid.xyz/flowgrid.min.js"></script>
<script>
FlowGrid.init({
webId: "web_abc123",
apiKey: "key_xxx",
});
FlowGrid.track("signup_clicked", { placement: "hero" });
FlowGrid.identify("user_123", { plan: "pro" });
FlowGrid.track("feature_usage", { featureId: "ai_agent_builder", featureName: "AI Agent Builder" });
FlowGrid.productView({ productId: "sku_1", name: "T-Shirt", price: 29 });
FlowGrid.addToCart({ productId: "sku_1", name: "T-Shirt", price: 29 }, 1);
</script>The script-tag API is intentionally small: init, track, page, identify,
feature, experiment, productView, addToCart, purchase, autoTrack,
consent helpers (setConsent / hasConsent), reset, and instance() for the
full SDK. FlowGrid.init() auto-instruments sessions, page views, SPA route
changes, scroll depth, time on page, performance, heatmaps, and attribution by
default; session replay is opt-in with replay: true, and passive identity
capture with autoTrack({ passiveIdentity: true }).
Session Replay
Replay is opt-in and browser-only. It uses rrweb dynamically, records DOM/input/scroll/mouse events, and sends sequenced chunks to core with call=replay_chunk.
const fg = FlowGrid.init({
webId: "wx_123",
apiKey: "pk_xxx",
user: { userId: "u_1" },
replay: {
sampleRate: 0.25,
maskAllInputs: true,
flushIntervalMs: 5000,
flushBytes: 512 * 1024,
onFlush: ({ sessionId, sequence, eventsCount }) => {
console.debug("replay chunk", sessionId, sequence, eventsCount);
},
},
});
fg.replay.identify("u_1");
await fg.replay.flush();
fg.replay.stop();Manual lifecycle control is available when you do not want init-time recording:
const stop = await fg.replay.start({ sampleRate: 1, maskAllInputs: true });
const status = fg.replay.status();
await fg.replay.flush("manual");
stop();Each replay chunk includes the core ingestion fields web_id, visitor_id, session_id, sequence, started_at, captured_at, events, plus replay metadata such as page_url, idempotency_key, compression, is_final, privacy, flush_reason, dropped_events, and recorder_version.
Feature Usage
Track product feature usage with a plain event — featureId and featureName
are the only required props:
fg.track("feature_usage", { featureId: "ai_agent_builder", featureName: "AI Agent Builder" });
// Optional: an action ("viewed" | "used" | "completed" | "abandoned"), a category, a known user.
fg.track("feature_usage", {
featureId: "ai_agent_builder",
featureName: "AI Agent Builder",
action: "completed",
category: "automation",
userId: "u_1",
});
// script tag: FlowGrid.track("feature_usage", { featureId: "ai_agent_builder", featureName: "AI Agent Builder" })action defaults to "used". No userId or category is required — it works
for anonymous visitors out of the box (the backend defaults userId to the
visitor and category to "general"). The event routes through the unified
.track() router, so it shares routing/consent/transport with every other event.
Helpers
Don't want to hand-write track("feature_usage", …) and repeat the id/name?
Bind a feature once with fg.defineFeature and call the verb that describes
what happened — each maps to a lifecycle stage the dashboard funnel understands
(a viewed feature is Discovered, a used one is Adopted):
const agent = fg.defineFeature("ai-agent-builder", "AI Agent Builder", { category: "automation" });
agent.viewed(); // action: "viewed" → Discovered + Viewed
agent.used({ model: "opus" }); // action: "used" → Adopted
agent.completed(); // action: "completed" → Completed
agent.abandoned(); // action: "abandoned" → Abandonment
// script tag: FlowGrid.defineFeature("ai-agent-builder", "AI Agent Builder").used()Each call is a thin, explicit wrapper over track("feature_usage", …) — no
hidden state, no lifecycle guessing; you send exactly the action you name. The
same verbs exist on fg.features.viewed/used/completed/abandoned(id, name) for
one-off calls, and fg.features.record(id, name, action) for a dynamic action.
Passive Identity Capture
Recognise anonymous visitors automatically: when a visitor types their email /
name / phone into any form, FlowGrid classifies the field, hashes PII in the
browser, and links the identity to their visitor_id — so the dashboard shows
them by name (and, with a CRM connected, matches them to the contact). No
per-form instrumentation.
It's opt-in in the SDK (the flowgrid.js snippet runs it by default) and
requires analytics consent:
const fg = FlowGrid.init({ webId: "...", apiKey: "..." });
FlowGrid.setConsent({ analytics: true });
const stop = fg.autoTrack({ passiveIdentity: true });
// or with options:
fg.autoTrack({ passiveIdentity: { debounceMs: 800, excludePath: /\/(checkout|admin)/i } });Never reads password/hidden/card/cvv/ssn/pin fields, anything marked
data-analytics="ignore" or .no-track, free-text (message/comment/search), or
sensitive paths (/checkout, /account/settings, /admin). Raw email goes only
to the server-side identity store; the event stream sees hashes. Full guide:
vission_manager/docs/PASSIVE_IDENTITY_DEVELOPER_GUIDE.md.
Server-side / Edge Usage
Works in any JavaScript runtime that supports fetch — Node, Bun, Deno, Cloudflare Workers, Vercel Edge, etc.
// app/api/track/route.ts (Next.js example, but works anywhere)
import { FlowGrid } from "flowgrid-sdk";
const fg = new FlowGrid("web_123", "https://core.flow-grid.xyz", process.env.FG_API_KEY!);
export async function POST(req: Request) {
const { userId } = await req.json();
await fg.events.track({ eventName: "server_event", properties: { userId } });
return Response.json({ ok: true });
}For Node-style batch jobs, simply create a FlowGrid instance, fire your tracking calls, and let the process exit — events use sendBeacon/fetch and a localStorage-style buffer for resilience.
Cookie Consent
The SDK ships a framework-agnostic ConsentManager. Render your own banner UI in whatever framework you use, and call into the manager to persist preferences.
import { ConsentManager, FlowGridTransport } from "flowgrid-sdk";
const consent = new ConsentManager({
cookieDomain: ".example.com",
cookieExpiry: 365,
respectDNT: true,
onChange: (prefs) => {
FlowGridTransport.setConsent({
analytics: prefs.analytics,
marketing: prefs.marketing,
});
},
});
consent.acceptAll();
consent.rejectNonEssential();
consent.update({ analytics: true, marketing: false, preferences: true });
consent.hasCategory("analytics"); // boolean
consent.reset();CookieBannerConfig and CookieBannerTheme types are exported from flowgrid-sdk/consent if you want a typed config object to pass to your own banner component.
You can also gate the transport directly without ConsentManager:
import { FlowGridTransport } from "flowgrid-sdk";
FlowGridTransport.setConsent({ analytics: true, marketing: false });
FlowGridTransport.hasConsent("analytics"); // trueIdentity & Storage Helpers
import {
FlowGrid,
IdentityManager,
getVisitorId,
getSessionId,
getWebId,
getUTM,
getUTMHistory,
} from "flowgrid-sdk";
const identity = new IdentityManager({ cookieDomain: ".example.com" });
const visitorId = identity.getVisitorId();
// Pass to FlowGrid for shared identity across modules
const fg = new FlowGrid(
"web_123",
"https://core.flow-grid.xyz",
"key_xxx",
visitorId,
identity
);Package Exports
| Import path | Description |
|---|---|
flowgrid-sdk |
Unified FlowGrid class + every feature module |
flowgrid-sdk/analytics |
Analytics modules only |
flowgrid-sdk/ecommerce |
Ecommerce modules only |
flowgrid-sdk/core |
Core modules (activation, experiments, prompts) |
flowgrid-sdk/consent |
ConsentManager + types |
flowgrid-sdk/types |
Shared TypeScript type definitions |
Configuration
The transport accepts an optional FlowGridTransportConfig as its 6th argument:
new FlowGrid(webId, endpoint, apiKey, visitorId, identityManager, {
botDetection: "block", // "block" | "tag" | "disabled"
respectDNT: true, // honour Do-Not-Track / GPC
sampleRate: 1.0, // 0.0 – 1.0
});Defaults: botDetection: "block", respectDNT: true, sampleRate: 1.0.
Scripts
npm run build # tsc + webpack production build
npm run build:browser # browser UMD bundle (flowgrid.min.js)
npm run build:all # both
npm run build:types # emit .d.ts only
npm test # run audit-fixes test suiteDocumentation
Full reference: https://flow-grid.xyz/documentation
Contributing
Issues and PRs welcome on GitHub.
License
MIT Brandon Roulstone