-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add a Contentful example app * fix .env.local.example and change readme * move code to the homepage and instructions to Readme. * Update readme and change product slug in page.tsx * formating changes + update Variations Not Switching help * Add screenshots and links to Contentful docs * Fix typo --------- Co-authored-by: Ryan Feigenbaum <48868107+royalfig@users.noreply.github.com>
- Loading branch information
Showing
32 changed files
with
6,642 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
CONTENTFUL_SPACE_ID= | ||
CONTENTFUL_ACCESS_TOKEN= | ||
CONTENTFUL_PREVIEW_ACCESS_TOKEN= | ||
|
||
CONTENTFUL_CMA_TOKEN= | ||
CONTENTFUL_ENVIRONMENT=master | ||
|
||
NEXT_PUBLIC_GROWTHBOOK_API_HOST=https://cdn.growthbook.io | ||
NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": ["next/core-web-vitals", "next/typescript"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/versions | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# env files (can opt-in for commiting if needed) | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
This example codebase is a Next.js app that demonstrates how to integrate **Contentful** CMS and **GrowthBook** for A/B testing and feature flag management. This integration enables teams to run experiments directly from their familiar Contentful interface while leveraging GrowthBook's powerful experimentation capabilities. | ||
|
||
## Requirements | ||
|
||
Before you begin ensure you have the following: | ||
|
||
[] [GrowthBook account](https://www.growthbook.io) (free tier available) | ||
[] [Contentful account](https://www.contentful.com) (free tier available) | ||
|
||
## Overview | ||
|
||
The guide below takes you through the steps to spin up this demo with a live connection to Contentful and GrowthBook. | ||
|
||
## Setup Instructions | ||
|
||
### 1. Setting Up GrowthBook | ||
|
||
**Create Your SDK Connection** | ||
|
||
1. Log in to GrowthBook | ||
2. Navigate to **SDK Configuration** → **SDK Connections** in the sidebar | ||
3. Click **Add SDK Connection** | ||
4. Select **JavaScript** or **React** as your language | ||
5. Save your **API Host** URL and **Client Key** for later use | ||
|
||
![SDK connection UI](./screenshots/sdk-connection-data.png) | ||
|
||
**Configure Your Data Source** | ||
|
||
1. Go to **Metrics and Data** → **Data Sources** in GrowthBook | ||
2. Click **Add Data Source** | ||
3. Choose your preferred analytics platform | ||
4. Follow the connection guide | ||
5. Note your data source ID for later use | ||
|
||
![Data source id is the last of the URL on the data source page](./screenshots/data-source-id.png) | ||
|
||
**Generate API Key** | ||
|
||
1. Navigate to **Settings** → **API Keys** | ||
2. Click **Create New Key** | ||
3. Select `admin` role | ||
4. Save the generated key securely | ||
|
||
![API generation UI](./screenshots/api-keys.png) | ||
|
||
### 2. Setting Up Contentful | ||
|
||
**Create API Access** | ||
|
||
1. Log in to your Contentful Space | ||
2. Click the gear icon (Settings) | ||
3. Navigate to **API keys** | ||
4. Click **Add API key** | ||
5. Save the **Space ID**, **Content Delivery API** token, and **Content Preview API** token | ||
|
||
**Generate CMA Token** | ||
|
||
1. Still in Settings, go to **CMA tokens** | ||
2. Click **Create new token** | ||
3. Name it "GrowthBook Content Management Access" | ||
4. Be sure to securly save the token, as you won't be able to access it again. | ||
|
||
**Install GrowthBook Plugin** | ||
|
||
// TODO May need revision | ||
|
||
1. Go to **Apps** → **Marketplace** | ||
2. Search for GrowthBook | ||
3. Click **Install** | ||
4. Configure the plugin: | ||
|
||
- Enter your GrowthBook API host URL | ||
- Paste your Admin API key | ||
- Set your data source | ||
- Click **Save** | ||
|
||
### 3. Configuring the Example App | ||
|
||
1. Clone the repository and install dependencies | ||
|
||
```bash | ||
git clone https://github.com/growthbook/examples.git | ||
cd examples/contentful | ||
npm install | ||
``` | ||
|
||
2. Set up environmental variables: | ||
|
||
```bash | ||
cp .env.local.example .env.local | ||
``` | ||
|
||
3. Fill in your `.env.local` with the saved keys: | ||
|
||
``` | ||
CONTENTFUL_SPACE_ID=your_space_id | ||
CONTENTFUL_ACCESS_TOKEN=your_access_token | ||
CONTENTFUL_PREVIEW_ACCESS_TOKEN=your_preview_token | ||
CONTENTFUL_MANAGEMENT_TOKEN=CMA_token | ||
GROWTHBOOK_API_HOST=your_growthbook_url | ||
``` | ||
|
||
4. Create initial content models: | ||
|
||
```bash | ||
npm run create-contentful-content | ||
``` | ||
|
||
5. Start the development server: | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
**Running Your First Experiment** | ||
|
||
Let's create a simple A/B test comparing two product variants: | ||
|
||
![GrowthBook Example Product Page showing 3 different t-shirts](./screenshots/product-demo.png) | ||
|
||
1. Access Product Page | ||
|
||
- Open Contentful | ||
- Navigate to **GrowthBook Example: Product Page** | ||
- Click the overflow menu and remove the "Control t-shirt" from the Products collection | ||
|
||
2. Create Experiment | ||
|
||
- Click **Add content** | ||
- Select **GrowthBook Experiment** | ||
- Add an **Experiment Name** | ||
|
||
3. Add Variations | ||
|
||
- Click **Add Variation** → **Link an existing variant** | ||
- Select **Control t-shirt** | ||
- Repeat for **Variant t-shirt** | ||
|
||
4. Launch Experiment | ||
|
||
- Click **Create New Experiment** | ||
- Click **Start Experiment** | ||
- Click **Publish** | ||
|
||
5. Update Product Page | ||
|
||
- Return to Product Page | ||
- Click **Publish** | ||
|
||
6. View Results | ||
|
||
- View your product page | ||
- Refresh to see different variations | ||
- Notice how GrowthBook alternates between control and variant 😎 | ||
|
||
## Technical Implementation | ||
|
||
This integration uses GrowthBook's server-side Next.js implementation for optimal performance. For additional examples of integrating GrowthBook with Next.js, including client-side implementation, see our other [Next.js examples](https://github.com/growthbook/examples/tree/main/next-js). | ||
|
||
### Content Model Structure | ||
|
||
The **GrowthBook Experiment** content model is fetched via the following GraphQL code, which contains the `featureFlagId` and the `variationsCollection`. The response contains data about your experiment content, as you set it up in Contentful. | ||
|
||
To get specific Variation content, make an additional call to the Contentful API using its `id` and `_typename`, or, as in the example below, add the fields for each Content Type you want to be able to experiment on. | ||
|
||
```ts | ||
// src/app/lib/growthbookExperiment.ts | ||
export const GROWTHBOOK_EXPERIMENT_GRAPHQL_FIELDS = ` | ||
sys { | ||
id | ||
} | ||
featureFlagId | ||
variationsCollection { | ||
items { | ||
sys { | ||
id | ||
} | ||
__typename | ||
... on GbExampleProduct { | ||
${PRODUCT_GRAPHQL_FIELDS} | ||
} | ||
} | ||
} | ||
`; | ||
``` | ||
|
||
### Variation Selection Logic | ||
|
||
The `getVariation` function uses your GrowthBook data to determine the variation's state. Calling `gb.getFeatureValue` with the `featureFlagId` returns the index of the variation to show in the `variationsCollection`. | ||
|
||
```ts | ||
export function getVariation( | ||
gb: GrowthBook, | ||
growthbookExperiment: GrowthbookExperimentInterface | ||
) { | ||
const featureFlagId = growthbookExperiment.featureFlagId; | ||
const variationsCollection = growthbookExperiment.variationsCollection; | ||
const index = gb.getFeatureValue(featureFlagId ?? "", 0); | ||
|
||
if (index > variationsCollection.items.length + 1) { | ||
return variationsCollection.items[0]; | ||
} | ||
return variationsCollection.items[index]; | ||
} | ||
``` | ||
|
||
### GrowthBook Initializiation and Content Rendering | ||
|
||
In `src/app/page.tsx`, we configure and initialize GrowthBook. The following code uses the `getVariation` function from above to conditionally render the variation the user should see. | ||
|
||
```ts | ||
const items = page.productsCollection.items.map((item) => { | ||
if (item.__typename === "GrowthbookExperiment") { | ||
return getVariation(gb, item); | ||
} | ||
|
||
return item; | ||
}); | ||
``` | ||
|
||
### Caching | ||
|
||
Server-fetched feature flags and experiment definitions are persisted in the Next.js data cache for 60 seconds (configurable in `src/app/lib/growthbookServer.ts`). For faster updates, use the `POST /revalidate` route handler via an SDK Webhook in GrowthBook. | ||
|
||
### Tracking CallBack | ||
|
||
Data about which variation the user saw is sent to the client where an analytics event is triggered (or `console.log` in these examples). This happens via the `GrowthBookTracking` client component defined in `src/app/lib/GrowthBookTracking.ts`. | ||
|
||
## Troubleshooting | ||
|
||
### Common Issues | ||
|
||
1. Content Model Not Appearing | ||
|
||
- Verify CMA token permissions | ||
- Run `create-contentful-content` script again | ||
- Check Contentful Space access | ||
|
||
2. Variations Not Switching | ||
|
||
- Confirm experiment has been started and is in state "Running" | ||
- Confirm experiment and it's parent container are published | ||
- Check Growthbook connection | ||
- Verify targeting attributes | ||
|
||
3. Plugin Installation Fails | ||
|
||
- Verify admin API key permissions | ||
- Check Growthbook URL format | ||
- Confirm data source ID | ||
|
||
### Getting Help | ||
|
||
- Join our [Community Forum](https://slack.growthbook.io/?ref=community-page) | ||
- Submit issue on [GitHub](https://github.com/growthbook/examples/contentful) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import type { NextConfig } from "next"; | ||
|
||
const nextConfig: NextConfig = { | ||
/* config options here */ | ||
}; | ||
|
||
export default nextConfig; |
Oops, something went wrong.