Getting Started With Next.js
Setup Flowgrid on your Next.js app in just a few easy steps. Follow the instructions below to get started using app router (version 13+).
Add the tracking script to app layout
Create your new website and add the following script tag preferably in the layout.jsx section:
- Open your project's
app/layout.jsxfile. - Add the Flowgrid tracking script tag inside the
headsection:
1import Script from 'next/script';
2
3export default function RootLayout({ children }) {
4 return (
5 <html lang="en">
6 <head>
7 <Script
8 src="https://core.flow-grid.xyz/flowgrid.js"
9 data-site="YOUR_WEBSITE_ID"
10 data-api-key="YOUR_API_KEY"
11 strategy="afterInteractive"
12 />
13 </head>
14 <body>{children}</body>
15 </html>
16 );
17}
18 Use the npm SDK + drop-in helpers
Prefer typed, in-app tracking over the script tag? Install the SDK and use the built-in helpers so you never re-implement consent wiring or stable IDs by hand. Everything below is framework-agnostic — the helpers import directly fromflowgrid-sdk.
1. Install
1npm install flowgrid-sdk
2# or: pnpm add flowgrid-sdk / yarn add flowgrid-sdk2. Create a single setup file
Initialise FlowGrid once and re-export the helpers. setupConsent creates a consent manager andkeeps FlowGrid's consent gates in sync automatically.
1// lib/flowgrid.ts
2import {
3 FlowGrid,
4 setupConsent,
5 attachConsentBanner,
6 getOrCreateAnonId,
7 getOrCreateCartId,
8} from "flowgrid-sdk";
9
10// init() touches browser globals, so guard against SSR (window is undefined on the server).
11const isClient = typeof window !== "undefined";
12
13export const flowgrid = isClient
14 ? FlowGrid.init({
15 webId: process.env.NEXT_PUBLIC_FLOWGRID_WEB_ID!,
16 apiKey: process.env.NEXT_PUBLIC_FLOWGRID_API_KEY!,
17 autoTrack: { performance: true, engagement: true, replay: true },
18 })
19 : null;
20
21export const track = flowgrid?.track.bind(flowgrid) ?? (() => undefined);
22
23// One call creates a consent manager AND keeps FlowGrid's consent gates in sync —
24// no manual FlowGridTransport.setConsent() plumbing.
25export const getConsent = () =>
26 setupConsent({ cookieName: "my_app_consent", cookieDays: 180, respectDNT: true });
27
28// Re-export the drop-in helpers so the rest of your app imports from one place.
29export { attachConsentBanner, getOrCreateAnonId, getOrCreateCartId };3. Cookie consent banner
Drop this client component into your app/layout.tsx. No manual transport sync — getConsent() did that for you.
1// components/cookie-banner.tsx
2"use client";
3import { useEffect, useState } from "react";
4import { getConsent } from "@/lib/flowgrid";
5
6export function CookieBanner() {
7 const [manager, setManager] = useState<ReturnType<typeof getConsent>>();
8 const [visible, setVisible] = useState(false);
9
10 useEffect(() => {
11 const cm = getConsent(); // already pushes stored prefs into FlowGrid
12 setManager(cm);
13 if (!cm.hasConsented()) setVisible(true);
14 }, []);
15
16 if (!visible) return null;
17
18 return (
19 <div id="cookie-banner" className="fixed bottom-0 inset-x-0 p-4 bg-background border-t">
20 <button onClick={() => { manager?.rejectNonEssential(); setVisible(false); }}>
21 Reject non-essential
22 </button>
23 <button onClick={() => { manager?.acceptAll(); setVisible(false); }}>
24 Accept all
25 </button>
26 </div>
27 );
28}Not using React for the banner?
CallattachConsentBanner() instead — it wires the#accept-btn /#reject-btn buttons inside any#cookie-banner element for you.4. Track with stable IDs
getOrCreateAnonId() andgetOrCreateCartId() persist a stable visitor / cart id (SSR-safe), so cart and checkout events line up automatically.
1import { track, flowgrid, getOrCreateAnonId, getOrCreateCartId } from "@/lib/flowgrid";
2
3// Product page view — stable anonymous id, no boilerplate.
4track("product_view", {
5 productId: p.id, name: p.name, price: p.price, currency: "EUR",
6 userId: getOrCreateAnonId(),
7});
8
9// Add to cart — every line in the session shares one cartId.
10flowgrid?.cart.add(
11 { productId: p.id, name: p.name, price: p.price },
12 1,
13 getOrCreateCartId(),
14);5. Run an A/B experiment
exposureAuto() resolves the assigned variant and the visitor id for you, and localConversion() logs the win — no user-id threading required.
1// hooks/use-experiment.ts
2"use client";
3import { useEffect, useState } from "react";
4import { flowgrid } from "@/lib/flowgrid";
5
6export function useExperiment(id: string, variants: { id: string; weight: number }[]) {
7 const [variant, setVariant] = useState<string | null>(null);
8
9 useEffect(() => {
10 flowgrid?.experiments.init([{ id, variants }]).then(() => {
11 setVariant(flowgrid!.experiments.variant(id));
12 flowgrid!.experiments.exposureAuto(id); // resolves the variant + anon id for you
13 });
14 }, [id]);
15
16 return {
17 variant,
18 convert: (metric: string, value = 1) =>
19 flowgrid?.experiments.localConversion(id, metric, value),
20 };
21}
22
23// Usage in a component:
24// const { variant, convert } = useExperiment("hero_cta_copy", [
25// { id: "control", weight: 50 },
26// { id: "treatment", weight: 50 },
27// ]);
28// <Button onClick={() => convert("signup")}>{variant === "treatment" ? "Start Free Trial" : "Book a Demo"}</Button>Verify installation
After adding the script do the following to verify that the installation was successful:
- Open your website that you are now tracking in the browser.
- Go to your dashboard, click on your website and click the
go to website's dashboardto see if the incoming traffic are being tracked.