flowgrid-sdk 1.7.7 → 1.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -10
- package/dist/flowgrid.min.js +1 -1
- package/dist/flowgrid.min.js.map +1 -1
- package/dist/lib/client/transport.js +5 -0
- package/dist/lib/client/transport.js.map +1 -1
- package/dist/lib/features/analytics/authIntent.d.ts +35 -0
- package/dist/lib/features/analytics/authIntent.js +89 -0
- package/dist/lib/features/analytics/authIntent.js.map +1 -0
- package/dist/lib/features/core/activation.d.ts +14 -0
- package/dist/lib/features/core/activation.js +23 -0
- package/dist/lib/features/core/activation.js.map +1 -1
- package/dist/lib/flowgrid.d.ts +152 -1
- package/dist/lib/flowgrid.js +205 -2
- package/dist/lib/flowgrid.js.map +1 -1
- package/dist/lib/server/index.d.ts +533 -0
- package/dist/lib/server/index.js +812 -0
- package/dist/lib/server/index.js.map +1 -0
- package/dist/lib/tracking/analytics/identify.d.ts +2 -0
- package/dist/lib/tracking/analytics/identify.js +4 -0
- package/dist/lib/tracking/analytics/identify.js.map +1 -1
- package/dist/lib/tracking/core/activation.d.ts +5 -0
- package/dist/lib/tracking/core/activation.js +4 -0
- package/dist/lib/tracking/core/activation.js.map +1 -1
- package/dist/lib/utils/identity.d.ts +9 -0
- package/dist/lib/utils/identity.js +14 -0
- package/dist/lib/utils/identity.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ e-commerce, experiments, and enterprise insights — with a single unified entry
|
|
|
9
9
|
point that works in any JavaScript environment (Node, browsers, edge runtimes,
|
|
10
10
|
React, Vue, Next, Nuxt, Svelte, Angular, etc.).
|
|
11
11
|
|
|
12
|
+
Start for free: [https://www.flow-grid.xyz/]
|
|
13
|
+
|
|
12
14
|
```ts
|
|
13
15
|
import { FlowGrid } from "flowgrid-sdk";
|
|
14
16
|
|
|
@@ -62,7 +64,54 @@ Requires Node `>= 18.12`. No peer dependencies.
|
|
|
62
64
|
|
|
63
65
|
## Quick Start
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
FlowGrid is one platform with two runtimes. Initialise **once per runtime** —
|
|
68
|
+
the browser client for everything a visitor does on the page, the server
|
|
69
|
+
client for what happens in your backend — and both feed the same dashboard
|
|
70
|
+
under the same identity:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// lib/flowgrid.client.ts — BROWSER: init once, import everywhere client-side
|
|
74
|
+
import { FlowGrid } from "flowgrid-sdk";
|
|
75
|
+
|
|
76
|
+
export const fg = FlowGrid.init({
|
|
77
|
+
webId: process.env.NEXT_PUBLIC_FLOWGRID_WEB_ID!, // public site id (wx_…)
|
|
78
|
+
apiKey: process.env.NEXT_PUBLIC_FLOWGRID_API_KEY!, // public API key
|
|
79
|
+
|
|
80
|
+
// Who is this? (optional — identifies up-front so the very first events attribute)
|
|
81
|
+
user: { userId: "u_1", email: "alice@example.com", name: "Alice" },
|
|
82
|
+
|
|
83
|
+
// What gets auto-tracked? engagement + replay are on by default;
|
|
84
|
+
// pageviews/sessions/heatmaps/performance come from the script tag install.
|
|
85
|
+
autoTrack: {
|
|
86
|
+
engagement: true,
|
|
87
|
+
replay: { sampleRate: 1.0, maskAllInputs: true },
|
|
88
|
+
passiveIdentity: true, // recognise visitors from forms (PII hashed in-browser)
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// What is the visitor consenting to? (see “Cookie Consent” below —
|
|
92
|
+
// pair with renderConsentBanner() for an opt-in banner in one call)
|
|
93
|
+
consent: { analytics: true, marketing: true },
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
// lib/flowgrid.server.ts — SERVER (Node ≥ 18 / edge): identity, feature usage, revenue, errors
|
|
99
|
+
import { FlowGridServer } from "flowgrid-sdk/server";
|
|
100
|
+
|
|
101
|
+
export const fgServer = FlowGridServer.init({
|
|
102
|
+
webId: process.env.NEXT_PUBLIC_FLOWGRID_WEB_ID!, // same site id
|
|
103
|
+
apiKey: process.env.FLOWGRID_API_KEY!, // private key — server env only
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
That's the whole setup. Browser calls (`fg.track`, `fg.identifyUser`,
|
|
108
|
+
`fg.cart.add`, …) and server calls (`fgServer.trackAuth`,
|
|
109
|
+
`fgServer.trackFeature`, `fgServer.trackPurchase`, `fgServer.trackError`, …) speak the same wire
|
|
110
|
+
contract, so a user identified in an OAuth callback on the server and the
|
|
111
|
+
same user clicking around in the browser resolve to **one identity** in the
|
|
112
|
+
dashboard.
|
|
113
|
+
|
|
114
|
+
### Unified client (browser)
|
|
66
115
|
|
|
67
116
|
```ts
|
|
68
117
|
import { FlowGrid } from "flowgrid-sdk";
|
|
@@ -202,25 +251,193 @@ to the server-side identity store; the event stream sees hashes.
|
|
|
202
251
|
|
|
203
252
|
## Server-side / Edge Usage
|
|
204
253
|
|
|
205
|
-
|
|
254
|
+
Use the dedicated **`flowgrid-sdk/server`** entry point on the server. It is a
|
|
255
|
+
Node/edge-safe client (global `fetch` only — no `window`, `document`, or
|
|
256
|
+
storage) scoped to what makes sense off-browser: **identity**, **feature
|
|
257
|
+
usage**, **ecommerce / revenue**, and **API / server error tracking**. It speaks the same wire contract
|
|
258
|
+
as the browser SDK, so events land in the same pipes. Works in Node ≥ 18, Bun,
|
|
259
|
+
Deno, Cloudflare Workers, and Vercel Edge/serverless.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// lib/flowgrid-server.ts — init once, import anywhere server-side
|
|
263
|
+
import { FlowGridServer } from "flowgrid-sdk/server";
|
|
264
|
+
|
|
265
|
+
export const fg = FlowGridServer.init({
|
|
266
|
+
webId: process.env.NEXT_PUBLIC_WEB_ID!,
|
|
267
|
+
apiKey: process.env.FLOWGRID_API_KEY!, // required on the server
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Identity — auth-level events** (identify a visitor server-side, e.g. in an
|
|
272
|
+
OAuth callback or session endpoint). Pass the browser's visitor id when you
|
|
273
|
+
have the request cookies so server events link to the web session; without it,
|
|
274
|
+
a stable synthetic visitor is derived from the `userId`:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { visitorIdFromCookies } from "flowgrid-sdk/server";
|
|
278
|
+
import { cookies } from "next/headers";
|
|
279
|
+
|
|
280
|
+
const visitorId = visitorIdFromCookies(await cookies());
|
|
281
|
+
|
|
282
|
+
await fg.trackAuth(
|
|
283
|
+
{ event: "login", userId: user.id, email: user.email, method: "google" },
|
|
284
|
+
{ visitorId },
|
|
285
|
+
); // identify + login_completed + active_user ping, in one call
|
|
286
|
+
|
|
287
|
+
// Or the individual operations:
|
|
288
|
+
await fg.identifyUser(user.id, { email: user.email, plan: "pro" }, { visitorId });
|
|
289
|
+
await fg.updateTraits(user.id, { plan: "enterprise" });
|
|
290
|
+
await fg.pingActiveUser(user.id, { email: user.email }); // DAU/WAU/MAU by identity
|
|
291
|
+
await fg.logout(user.id);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Feature usage** from API routes, jobs, and webhooks:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
await fg.trackFeature({ featureId: "csv_export", featureName: "CSV Export", userId: user.id });
|
|
298
|
+
|
|
299
|
+
// Or bind once and use semantic verbs (server twin of fg.defineFeature):
|
|
300
|
+
const teamUpdate = fg.defineFeature("team_update", "Team update", { category: "teams" });
|
|
301
|
+
await teamUpdate.used({ userId: user.id, teamId });
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Ecommerce / revenue** — record purchases, refunds, order lifecycle, and
|
|
305
|
+
subscription MRR events from your **payment webhooks**, where the money is
|
|
306
|
+
actually confirmed. Browser purchase events are structurally lossy (ad
|
|
307
|
+
blockers, closed tabs on the checkout redirect); the server is the
|
|
308
|
+
authoritative source for revenue:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
// Stripe webhook: checkout.session.completed
|
|
312
|
+
await fg.trackPurchase({
|
|
313
|
+
order: {
|
|
314
|
+
orderId: session.id,
|
|
315
|
+
items, // CartItem[] — same shape as the browser SDK
|
|
316
|
+
subtotal, discountTotal: 0, shippingTotal: 0, taxTotal,
|
|
317
|
+
total: session.amount_total / 100,
|
|
318
|
+
currency: "USD",
|
|
319
|
+
payment: { method: "credit_card", provider: "stripe" },
|
|
320
|
+
},
|
|
321
|
+
userId: session.client_reference_id,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// charge.refunded — keeps net revenue accurate
|
|
325
|
+
await fg.trackRefund({
|
|
326
|
+
orderId, refundId: refund.id,
|
|
327
|
+
amount: refund.amount / 100, currency: "USD",
|
|
328
|
+
reason: "customer_request", isFullRefund: true, userId,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Fulfilment webhooks
|
|
332
|
+
await fg.trackOrderStatus(orderId, "processing", "pending", { userId });
|
|
333
|
+
await fg.trackOrderShipped(orderId, { method: "express", cost: 5, trackingNumber });
|
|
334
|
+
await fg.trackOrderDelivered(orderId);
|
|
335
|
+
|
|
336
|
+
// Subscription / MRR lifecycle — one method, discriminated on `event`:
|
|
337
|
+
await fg.trackSubscription({
|
|
338
|
+
event: "start", // "change" | "cancel" | "renew" | "trial_converted" | "trial_expired"
|
|
339
|
+
subscriptionId: sub.id,
|
|
340
|
+
userId,
|
|
341
|
+
plan: "professional",
|
|
342
|
+
mrr: { amount: 9900, currency: "USD" }, // smallest currency unit
|
|
343
|
+
billingCycle: "monthly",
|
|
344
|
+
trialDays: 14,
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Revenue attribution** — payment webhooks arrive with no cookies, so the
|
|
349
|
+
visitor/session ids ride through the provider's checkout metadata and come
|
|
350
|
+
back out in the webhook. Two legs:
|
|
206
351
|
|
|
207
352
|
```ts
|
|
208
|
-
//
|
|
209
|
-
import {
|
|
353
|
+
// LEG 1 — checkout creation: embed the ids from the request cookies.
|
|
354
|
+
import { checkoutAttributionFromCookies } from "flowgrid-sdk/server";
|
|
355
|
+
import { cookies } from "next/headers";
|
|
356
|
+
|
|
357
|
+
// Stripe
|
|
358
|
+
const session = await stripe.checkout.sessions.create({
|
|
359
|
+
// …
|
|
360
|
+
metadata: { ...checkoutAttributionFromCookies(await cookies()) },
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Lemon Squeezy
|
|
364
|
+
const checkout = await createCheckout(storeId, variantId, {
|
|
365
|
+
checkoutData: { custom: { ...checkoutAttributionFromCookies(await cookies()) } },
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// (Creating the checkout client-side instead? Use fg.checkoutAttribution()
|
|
369
|
+
// from the browser SDK — same keys.)
|
|
370
|
+
```
|
|
210
371
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
372
|
+
```ts
|
|
373
|
+
// LEG 2 — webhook: read the ids back and attach them to the revenue event.
|
|
374
|
+
import { attributionFromMetadata } from "flowgrid-sdk/server";
|
|
375
|
+
|
|
376
|
+
// Stripe checkout.session.completed — unwraps `.metadata` automatically
|
|
377
|
+
const { visitorId, sessionId } = attributionFromMetadata(event.data.object);
|
|
378
|
+
|
|
379
|
+
// Lemon Squeezy order_created — unwraps `.meta.custom_data` automatically
|
|
380
|
+
// const { visitorId, sessionId } = attributionFromMetadata(payload);
|
|
381
|
+
|
|
382
|
+
await fg.trackPurchase({ order, userId }, { visitorId, sessionId });
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
With the real `visitorId` + `sessionId` on the purchase, revenue joins the
|
|
386
|
+
visitor's full journey — the session, landing page and UTM campaign that
|
|
387
|
+
earned it — instead of a synthetic server visitor.
|
|
388
|
+
|
|
389
|
+
**API + server-side error tracking** — errors become `error_event`s with
|
|
390
|
+
route/method/status context; FlowGrid-internal noise is filtered out:
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
try { … } catch (err) {
|
|
394
|
+
await fg.trackError(err, { route: "/api/teams/edit/[teamId]", method: "PATCH", statusCode: 500, userId });
|
|
395
|
+
throw err;
|
|
215
396
|
}
|
|
397
|
+
|
|
398
|
+
// Or wrap a handler — tracks and rethrows, framework behaviour unchanged:
|
|
399
|
+
export const PATCH = fg.withErrorTracking(handler, { route: "/api/teams/edit/[teamId]", method: "PATCH" });
|
|
400
|
+
|
|
401
|
+
// Opt-in process-level capture (Node only; observes, never swallows):
|
|
402
|
+
const detach = fg.captureUncaught();
|
|
216
403
|
```
|
|
217
404
|
|
|
218
|
-
|
|
405
|
+
Like the browser transport, the server client **never throws** for delivery
|
|
406
|
+
problems — every method resolves `{ ok, status?, reason? }`.
|
|
219
407
|
|
|
220
408
|
---
|
|
221
409
|
|
|
222
410
|
## Cookie Consent
|
|
223
411
|
|
|
412
|
+
### What you're asking consent for
|
|
413
|
+
|
|
414
|
+
When a visitor accepts cookies, this is exactly what each category permits
|
|
415
|
+
FlowGrid to do (this is what the SDK enforces, not aspirational copy — each
|
|
416
|
+
category maps to a hard gate in the transport).
|
|
417
|
+
|
|
418
|
+
**Default posture: implied consent.** Every category starts granted, and
|
|
419
|
+
tracking runs out of the box — the "declined" behaviour below only applies
|
|
420
|
+
when you've installed a consent gate (`requireExplicitConsent: true` or the
|
|
421
|
+
opt-in banner) and the visitor actively rejects a category:
|
|
422
|
+
|
|
423
|
+
| Category | Can the visitor decline? | What it covers |
|
|
424
|
+
| ------------- | ------------------------ | -------------- |
|
|
425
|
+
| `necessary` | No — always on | The visitor/session identifiers (`visitor_id` cookie, `fg_session_id`) and the consent cookies themselves (`fg_consent`, `fg_tracking_consent`). Required for the service to function; no behavioural profiling. |
|
|
426
|
+
| `analytics` | Yes | **All event tracking.** Page views, sessions, clicks, forms, searches, feature usage, funnels, performance/Web Vitals, engagement, identity events (`identifyUser`, active-user pings), and **session replay** recordings — plus the device/page context attached to each event (screen size, device type, language, URL, path, title, referrer). Declined → no events leave the browser. |
|
|
427
|
+
| `marketing` | Yes | **Campaign attribution.** The `utm_source/medium/campaign/term/content` and `ref`/`via`/`source` parameters read from the URL and the `__flowgrid_*` landing-page cookies, attached to events as `_utm_*`/`_ref` properties. Declined → events (if analytics is granted) are sent **without** any campaign attribution. |
|
|
428
|
+
| `preferences` | Yes | UI preferences your own app stores (locale, theme). FlowGrid itself stores nothing in this category — it exists so your banner can offer it. |
|
|
429
|
+
|
|
430
|
+
Independent of the banner, visitors sending **Do-Not-Track** or **Global
|
|
431
|
+
Privacy Control** are treated as having declined non-essential tracking by
|
|
432
|
+
default (`respectDNT: true`), and localhost traffic is never tracked unless
|
|
433
|
+
explicitly enabled.
|
|
434
|
+
|
|
435
|
+
Server-side events (`flowgrid-sdk/server`) are outside the browser consent
|
|
436
|
+
gates by design: they represent your backend's own records (auth events,
|
|
437
|
+
API feature usage, server errors) under your contractual/legitimate-interest
|
|
438
|
+
basis. If you want browser consent to extend to server calls, check your
|
|
439
|
+
stored consent state before calling the server client.
|
|
440
|
+
|
|
224
441
|
### No-code (one tag) — recommended
|
|
225
442
|
|
|
226
443
|
Drop a single element on the page and FlowGrid renders a styled, **opt-in**,
|
|
@@ -339,6 +556,7 @@ FlowGridTransport.hasConsent("analytics"); // true
|
|
|
339
556
|
| `flowgrid-sdk/ecommerce` | Ecommerce modules only |
|
|
340
557
|
| `flowgrid-sdk/core` | Core modules (activation, experiments, prompts) |
|
|
341
558
|
| `flowgrid-sdk/consent` | `ConsentManager` + types |
|
|
559
|
+
| `flowgrid-sdk/server` | `FlowGridServer` — Node/edge tracking (identity, feature usage, revenue, errors) |
|
|
342
560
|
| `flowgrid-sdk/types` | Shared TypeScript type definitions |
|
|
343
561
|
|
|
344
562
|
---
|
|
@@ -349,6 +567,6 @@ Full reference: <https://flow-grid.xyz/documentation>
|
|
|
349
567
|
|
|
350
568
|
## License
|
|
351
569
|
|
|
352
|
-
MIT ©
|
|
570
|
+
MIT © Flowgrid
|
|
353
571
|
|
|
354
572
|
Contact Support suport@toastlabz.com
|