Skip to content

Commit

Permalink
Add a Contentful example app (#52)
Browse files Browse the repository at this point in the history
* 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
tzjames and royalfig authored Dec 11, 2024
1 parent 833be7e commit 5b22132
Show file tree
Hide file tree
Showing 32 changed files with 6,642 additions and 0 deletions.
9 changes: 9 additions & 0 deletions contentful/.env.local.example
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=
3 changes: 3 additions & 0 deletions contentful/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
40 changes: 40 additions & 0 deletions contentful/.gitignore
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
256 changes: 256 additions & 0 deletions contentful/README.md
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** &rarr; **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** &rarr; **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** &rarr; **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** &rarr; **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** &rarr; **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)
7 changes: 7 additions & 0 deletions contentful/next.config.ts
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;
Loading

0 comments on commit 5b22132

Please sign in to comment.