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 read hasConsented() / getPreferences()and call acceptAll() / 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.

lib/consent.ts
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.

index.html
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.

lib/consent.ts
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.

components/CookieBanner.tsx
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.

footer.ts
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():

settings.ts
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.

CategoryDeclinable?What accepting permits
necessaryNo — always onThe 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.
analyticsYesAll 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.
marketingYesCampaign 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.
preferencesYesUI 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:

lib/consent.ts
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.