Privacy
Cookie consent
Be GDPR / CCPA-friendly in a couple of lines. Two drop-in helpers handle the whole flow — storing the visitor's choice, respecting DNT/GPC, and gating analytics & marketing events until consent is given — so you never wire consent by hand.
Overview
Both helpers import directly from flowgrid-sdk:
setupConsent()— creates a consent manager andkeeps FlowGrid's consent gates in sync automatically. Returns the manager so you can readhasConsented()/getPreferences()and callacceptAll()/rejectNonEssential().attachConsentBanner()— does all of the above andwires an existing HTML banner's buttons, showing it only when the visitor hasn't consented yet.renderConsentBanner()— the zero-markup option: FlowGrid builds, styles and injects the whole banner for you. Opt-in by default — analytics, marketing and session replay stay blocked until the visitor accepts.
Which one do I use?
Want a banner with nothing to wire up? Reach for renderConsentBanner() — one call, no HTML. Already have your own banner markup (or a non-React framework)? Use attachConsentBanner(). Rendering the banner in React/JSX yourself? Use setupConsent() and drive visibility with component state (shown below).
Permissive by default — gating is opt-in
Out of the box FlowGrid tracks with implied consent: all categories default to granted, and setupConsent() / attachConsentBanner() keep tracking on until the visitor explicitly rejects. To block tracking before consent (GDPR-style opt-in), pass requireExplicitConsent: true — or use renderConsentBanner(), which is opt-in by default. Necessary cookies (session, security) always run, and Do-Not-Track / GPC visitors are treated as having declined automatically.
Zero-markup banner
renderConsentBanner()is the fastest path: no HTML, no React, no CSS. One call and FlowGrid builds a styled, accessible banner, injects it into the page, wires the buttons, and keeps the consent gates in sync. It's opt-in by default, so tracking — including session replay — only starts after the visitor clicks Accept.
1import { renderConsentBanner } from "flowgrid-sdk";
2
3const banner = renderConsentBanner({
4 title: "We value your privacy",
5 description: "We use cookies to analyse traffic and improve your experience.",
6 privacyPolicyUrl: "/privacy",
7 theme: {
8 position: "bottom-right", // top | bottom | bottom-left | bottom-right | center
9 primaryColor: "#EBF212",
10 },
11});
12
13// returns { manager, show, hide, destroy } (or null during SSR).The banner shows a Customize view with per-category toggles (analytics, marketing) plus Accept all / Reject non-essential. Every label, the copy, the privacy link and the theme are configurable.
Re-open it later
Keep the returned handle and call banner?.show()from a footer "Manage cookies" link. Pass forceShow: true to open it even after the visitor has already chosen.
1. Add the banner markup
Give the container id="cookie-banner" and the buttonsid="accept-btn" / id="reject-btn". All three ids are configurable via options. Start it hidden — the helper reveals it when needed.
1<div id="cookie-banner" style="display:none" class="fixed bottom-0 inset-x-0 ...">
2 <p>We use cookies to improve your experience.</p>
3 <button id="reject-btn">Reject non-essential</button>
4 <button id="accept-btn">Accept all</button>
5</div>2a. Vanilla JS — one call
attachConsentBanner() does everything: clicking accept callsacceptAll(), reject calls rejectNonEssential(), the banner hides itself, and consent is synced to FlowGrid.
1import { attachConsentBanner } from "flowgrid-sdk";
2
3const banner = attachConsentBanner({
4 cookieName: "my_app_consent",
5 cookieDays: 180,
6 respectDNT: true,
7 requireExplicitConsent: true,
8});
9
10// banner is { manager, show, hide, destroy } (or null during SSR / if the
11// #cookie-banner element isn't on the page yet).Custom element ids
Pass bannerId, acceptId and rejectId to match your own markup, or manager to reuse a manager you already created with setupConsent().
2b. React component
Prefer JSX? Use setupConsent() (consent is already synced) and drive the banner with state. Drop <CookieBanner /> near your app root.
1import { useEffect, useState } from "react";
2import { setupConsent } from "flowgrid-sdk";
3
4export function CookieBanner() {
5 const [manager, setManager] = useState<ReturnType<typeof setupConsent>>();
6 const [visible, setVisible] = useState(false);
7
8 useEffect(() => {
9 const cm = setupConsent({ cookieName: "my_app_consent", cookieDays: 180, respectDNT: true });
10 setManager(cm);
11 if (!cm.hasConsented()) setVisible(true);
12 }, []);
13
14 if (!visible) return null;
15
16 return (
17 <div className="fixed bottom-0 inset-x-0 p-4 bg-background border-t">
18 <p className="text-sm">We use cookies to improve your experience.</p>
19 <button onClick={() => { manager?.rejectNonEssential(); setVisible(false); }}>
20 Reject non-essential
21 </button>
22 <button onClick={() => { manager?.acceptAll(); setVisible(false); }}>
23 Accept all
24 </button>
25 </div>
26 );
27}Re-open the banner later
A "Manage cookies" link in your footer is a common requirement. Keep the handle returned by attachConsentBanner() and call show() — or in React, flip your visible state.
1const banner = attachConsentBanner();
2
3document
4 .getElementById("manage-cookies")
5 ?.addEventListener("click", () => banner?.show());
6
7// Call banner?.destroy() on teardown (e.g. a React effect cleanup) to remove listeners.Consent categories
Preferences are tracked per category: necessary (always on),analytics, marketing, and preferences. FlowGrid automatically gates analytics & marketing events until the visitor opts in. Toggle individual categories from a custom settings panel with update():
1import { setupConsent } from "flowgrid-sdk";
2
3const consent = setupConsent();
4
5// Save granular choices from a "cookie settings" dialog:
6consent.update({ analytics: true, marketing: false, preferences: true });
7
8// Read current state:
9const prefs = consent.getPreferences(); // { necessary, analytics, marketing, preferences }
10if (consent.hasConsented()) { /* visitor has made a choice */ }DNT / GPC respected by default
With respectDNT: true, a visitor sending Do-Not-Track or Global Privacy Control is treated as having declined non-essential categories automatically.
What you're asking consent for
When a visitor clicks Accept, this is exactly what each category permits FlowGrid to do. Each category maps to a hard gate in the SDK transport — it's enforced behaviour, not banner copy — which is what you can point auditors and your privacy policy at.
Remember the default posture: every category starts granted(implied consent). The “Declined” behaviour below only kicks in when you've installed a consent gate and the visitor actively rejects a category.
| Category | Declinable? | What accepting permits |
|---|---|---|
| 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. |
| analytics | Yes | All event tracking. Page views, sessions, clicks, forms, searches, feature usage, funnels, performance, engagement, identity events, and session replay recordings — plus the device/page context on each event (screen size, device type, language, URL, path, title, referrer). Declined → no events leave the browser. |
| marketing | Yes | Campaign attribution. The utm_* and ref/via/source parameters read from the URL and the __flowgrid_* landing-page cookies, attached to events as _utm_* properties. Declined → events (if analytics is granted) are sent without campaign attribution. |
| 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. |
Server-side events are a separate basis
Events from flowgrid-sdk/server(auth events, API feature usage, server errors) sit outside the browser consent gates: they are your backend's own records about signed-in users, collected under your contractual / legitimate-interest basis — not cookie consent. If your policy extends cookie consent to server analytics, check your stored consent state before calling the server client.
Lower-level API
setupConsent() wraps new ConsentManager() and calls FlowGridTransport.setConsent() for you on every change. If you need full control, both are still exported — drop the helper and wire the transport yourself:
1import { ConsentManager, FlowGridTransport as transport } from "flowgrid-sdk";
2
3const consent = new ConsentManager({
4 cookieName: "my_app_consent",
5 onChange: (prefs) => {
6 transport.setConsent({ analytics: prefs.analytics, marketing: prefs.marketing });
7 },
8});Migrating?
If your app currently does the above by hand, replace it with a single setupConsent() (or attachConsentBanner()) call and delete the manual transport.setConsent() plumbing.