Skip to content

Commit 7ec5256

Browse files
committed
Have the next example use growthbook tracking
1 parent 65f63f6 commit 7ec5256

15 files changed

Lines changed: 100 additions & 94 deletions

File tree

next-js/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pnpm dev
1414
bun dev
1515
```
1616

17-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
17+
Open [http://localhost:8000](http://localhost:8000) with your browser to see the result.
1818

1919
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
2020

next-js/package-lock.json

Lines changed: 12 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

next-js/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"dev": "next dev",
6+
"dev": "next dev -p 8000",
77
"build": "next build",
8-
"start": "next start",
8+
"start": "next start -p 8000",
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12-
"@growthbook/growthbook": "^1.0.0",
13-
"@growthbook/growthbook-react": "^1.0.0",
12+
"@growthbook/growthbook": "^1.6.5",
13+
"@growthbook/growthbook-react": "^1.6.5",
1414
"js-cookie": "^3.0.5",
1515
"next": "14.2.2",
1616
"react": "^18",

next-js/src/app/client-optimized/ClientApp.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
"use client";
2-
import { onExperimentView } from "@/lib/GrowthBookTracking";
32
import ClientComponent from "./ClientComponent";
43
import { GrowthBook, GrowthBookPayload } from "@growthbook/growthbook";
54
import { GrowthBookProvider } from "@growthbook/growthbook-react";
65
import { useMemo } from "react";
7-
import { GB_UUID_COOKIE } from "@/middleware";
8-
import Cookies from "js-cookie";
6+
import { growthbookManagedWarehouseClientPlugins } from "@/lib/growthbookManagedWarehouse";
97

108
export default function ClientApp({ payload }: { payload: GrowthBookPayload }) {
9+
const isBrowser = typeof window !== "undefined";
10+
1111
// Create a singleton GrowthBook instance for this page
1212
const gb = useMemo(
1313
() =>
1414
new GrowthBook({
1515
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1616
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1717
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
18-
trackingCallback: onExperimentView,
19-
attributes: {
20-
id: Cookies.get(GB_UUID_COOKIE),
21-
},
18+
plugins: growthbookManagedWarehouseClientPlugins(isBrowser),
2219
}).initSync({
2320
payload,
2421
// Optional, enable streaming updates
2522
streaming: true,
2623
}),
27-
[payload]
24+
[payload, isBrowser]
2825
);
2926

3027
return (

next-js/src/app/client-optimized/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { configureServerSideGrowthBook } from "@/lib/growthbookServer";
22
import ClientApp from "./ClientApp";
33
import { GrowthBook } from "@growthbook/growthbook";
4+
import { growthbookManagedWarehouseServerPlugins } from "@/lib/growthbookManagedWarehouse";
45

56
export default async function PrerenderedClientPage() {
67
// Helper to configure cache for next.js
@@ -11,6 +12,7 @@ export default async function PrerenderedClientPage() {
1112
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1213
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1314
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
15+
plugins: growthbookManagedWarehouseServerPlugins(),
1416
});
1517
await gb.init({ timeout: 1000 });
1618

next-js/src/app/client/page.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
11
"use client";
2-
import Cookies from "js-cookie";
32
import { GrowthBook, GrowthBookProvider } from "@growthbook/growthbook-react";
43
import { useEffect, useMemo } from "react";
54
import ClientComponent from "./ClientComponent";
6-
import { GB_UUID_COOKIE } from "@/middleware";
7-
import { onExperimentView } from "@/lib/GrowthBookTracking";
5+
import { growthbookManagedWarehouseClientPlugins } from "@/lib/growthbookManagedWarehouse";
86

97
export default function ClientPage() {
8+
const isBrowser = typeof window !== "undefined";
9+
1010
// Create a single memoized GrowthBook instance for the client
1111
const gb = useMemo(() => {
1212
return new GrowthBook({
1313
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1414
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1515
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
16-
trackingCallback: onExperimentView,
16+
plugins: growthbookManagedWarehouseClientPlugins(isBrowser),
1717
});
18-
}, []);
18+
}, [isBrowser]);
1919

2020
useEffect(() => {
2121
// Fetch feature payload from GrowthBook
2222
gb.init({
2323
// Optional, enable streaming updates
2424
streaming: true,
2525
});
26-
27-
// Set targeting attributes for the user
28-
let uuid = Cookies.get(GB_UUID_COOKIE);
29-
if (!uuid) {
30-
uuid = Math.random().toString(36).substring(2);
31-
Cookies.set(GB_UUID_COOKIE, uuid);
32-
}
33-
gb.setAttributes({
34-
id: uuid,
35-
});
3626
}, [gb]);
3727

3828
return (

next-js/src/app/hybrid/ClientApp.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
"use client";
2-
import { onExperimentView } from "@/lib/GrowthBookTracking";
32
import { GrowthBookPayload } from "@growthbook/growthbook";
43
import { GrowthBook, GrowthBookProvider } from "@growthbook/growthbook-react";
54
import { PropsWithChildren, useMemo } from "react";
6-
import { GB_UUID_COOKIE } from "@/middleware";
7-
import Cookies from "js-cookie";
5+
import { growthbookManagedWarehouseClientPlugins } from "@/lib/growthbookManagedWarehouse";
86

97
export default function ClientApp({
108
payload,
119
children,
1210
}: PropsWithChildren<{ payload: GrowthBookPayload }>) {
11+
const isBrowser = typeof window !== "undefined";
12+
1313
// Create a singleton GrowthBook instance for this page
1414
const gb = useMemo(
1515
() =>
1616
new GrowthBook({
1717
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1818
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1919
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
20-
trackingCallback: onExperimentView,
21-
attributes: {
22-
id: Cookies.get(GB_UUID_COOKIE),
23-
},
20+
plugins: growthbookManagedWarehouseClientPlugins(isBrowser),
2421
}).initSync({
2522
payload,
2623
// Optional, enable streaming updates
2724
streaming: true,
2825
}),
29-
[payload]
26+
[payload, isBrowser]
3027
);
3128

3229
return <GrowthBookProvider growthbook={gb}>{children}</GrowthBookProvider>;

next-js/src/app/hybrid/page.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ClientApp from "./ClientApp";
44
import RevalidateMessage from "@/app/revalidate/RevalidateMessage";
55
import { GrowthBook } from "@growthbook/growthbook";
66
import { configureServerSideGrowthBook } from "@/lib/growthbookServer";
7-
import { GrowthBookTracking } from "@/lib/GrowthBookTracking";
7+
import { growthbookManagedWarehouseServerPlugins } from "@/lib/growthbookManagedWarehouse";
88
import ClientComponent from "./ClientComponent";
99

1010
export default async function ServerCombo() {
@@ -16,6 +16,7 @@ export default async function ServerCombo() {
1616
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1717
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1818
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
19+
plugins: growthbookManagedWarehouseServerPlugins(),
1920
});
2021
await gb.init({ timeout: 1000 });
2122

@@ -32,10 +33,6 @@ export default async function ServerCombo() {
3233
// We need the decrypted payload so the initial client-render can be synchronous
3334
const payload = gb.getDecryptedPayload();
3435

35-
// If the above features ran any experiments, get the tracking call data
36-
// This is passed into the <GrowthBookTracking> client component below
37-
const trackingData = gb.getDeferredTrackingCalls();
38-
3936
// Cleanup your GrowthBook instance
4037
gb.destroy();
4138

@@ -62,8 +59,6 @@ export default async function ServerCombo() {
6259
</ClientApp>
6360

6461
<RevalidateMessage />
65-
66-
<GrowthBookTracking data={trackingData} />
6762
</div>
6863
);
6964
}

next-js/src/app/page.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,19 @@ export default function Home() {
8989
from an SDK Webhook in GrowthBook.
9090
</p>
9191
<p>
92-
If an experiment is run server-side, data about which variation the
93-
user saw is sent to the client where an analytics event is triggered
94-
(or console.log in these examples). This happens via the{" "}
95-
<code>GrowthBookTracking</code> client component defined in{" "}
96-
<code>src/lib/GrowthBookTracking</code>.
92+
Experiment views and feature evaluations are sent to GrowthBook
93+
Managed Warehouse using the{" "}
94+
<code>growthbookTrackingPlugin</code> and{" "}
95+
<code>autoAttributesPlugin</code> (client only) from{" "}
96+
<code>@growthbook/growthbook/plugins</code>. See the{" "}
97+
<a
98+
href="https://docs.growthbook.io/app/managed-warehouse#client-side-javascript--react"
99+
target="_blank"
100+
rel="noreferrer"
101+
>
102+
Managed Warehouse docs
103+
</a>
104+
.
97105
</p>
98106
</section>
99107
</main>

next-js/src/app/server/page.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { cookies } from "next/headers";
22
import { GB_UUID_COOKIE } from "@/middleware";
33
import RevalidateMessage from "@/app/revalidate/RevalidateMessage";
44
import { GrowthBook } from "@growthbook/growthbook";
5-
import { GrowthBookTracking } from "@/lib/GrowthBookTracking";
65
import { configureServerSideGrowthBook } from "@/lib/growthbookServer";
6+
import { growthbookManagedWarehouseServerPlugins } from "@/lib/growthbookManagedWarehouse";
77

88
export default async function ServerDynamic() {
99
// Helper to configure cache for next.js
@@ -14,6 +14,7 @@ export default async function ServerDynamic() {
1414
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
1515
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
1616
decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
17+
plugins: growthbookManagedWarehouseServerPlugins(),
1718
});
1819
await gb.init({ timeout: 1000 });
1920

@@ -26,10 +27,6 @@ export default async function ServerDynamic() {
2627
const feature1Enabled = gb.isOn("feature1");
2728
const feature2Value = gb.getFeatureValue("feature2", "fallback");
2829

29-
// If the above features ran any experiments, get the tracking call data
30-
// This is passed into the <GrowthBookTracking> client component below
31-
const trackingData = gb.getDeferredTrackingCalls();
32-
3330
// Cleanup
3431
gb.destroy();
3532

@@ -50,8 +47,6 @@ export default async function ServerDynamic() {
5047
</ul>
5148

5249
<RevalidateMessage />
53-
54-
<GrowthBookTracking data={trackingData} />
5550
</div>
5651
);
5752
}

0 commit comments

Comments
 (0)