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:

  1. Open your project's app/layout.jsx file.
  2. Add the Flowgrid tracking script tag inside the head section:
layout.jsx
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

terminal
1npm install flowgrid-sdk 2# or: pnpm add flowgrid-sdk / yarn add flowgrid-sdk

2. 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.

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

components/cookie-banner.tsx
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?

Call attachConsentBanner() 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.

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

hooks/use-experiment.ts
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:

  1. Open your website that you are now tracking in the browser.
  2. Go to your dashboard, click on your website and click the go to website's dashboard to see if the incoming traffic are being tracked.