Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
11,237 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,6 @@ | ||
# This is the PostHog Project API Key | ||
NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY= | ||
|
||
# This is the PostHog host. | ||
# For PostHog cloud this would be https://app.posthog.com | ||
NEXT_PUBLIC_POSTHOG_HOST= |
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,34 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
|
||
# vercel | ||
.vercel |
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,43 @@ | ||
# A/B Testing with PostHog | ||
|
||
[PostHog](https://posthog.com/) is an open-source product analytics platform that offers a suite of tools, including funnels, heat maps, session recording, feature flags and more, all in a single platform. | ||
|
||
## Demo | ||
|
||
https://edge-functions-feature-flag-posthog.vercel.sh | ||
|
||
### One-Click Deploy | ||
|
||
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme): | ||
|
||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/feature-flag-posthog&env=NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY,NEXT_PUBLIC_POSTHOG_HOST&project-name=feature-flag-posthog&repository-name=feature-flag-posthog) | ||
|
||
## Getting Started | ||
|
||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: | ||
|
||
```bash | ||
npx create-next-app --example https://github.com/vercel/examples/tree/main/edge-functions/feature-flag-posthog feature-flag-posthog | ||
# or | ||
yarn create next-app --example https://github.com/vercel/examples/tree/main/edge-functions/feature-flag-posthog feature-flag-posthog | ||
``` | ||
|
||
You'll need to have an account with [PostHog](https://posthog.com/signup). Once that's done, copy the `.env.example` file in this directory to `.env.local` (which will be ignored by Git): | ||
|
||
```bash | ||
cp .env.example .env.local | ||
``` | ||
|
||
Then open `.env.local` and set the environment variables to match the host for your PostHog instance and the Project API key available under Project settings - Project API Key. | ||
|
||
Next, run Next.js in development mode: | ||
|
||
```bash | ||
npm install | ||
npm run dev | ||
|
||
# or | ||
|
||
yarn | ||
yarn dev | ||
``` |
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,12 @@ | ||
/** | ||
* List of known active Feature Flags | ||
*/ | ||
export const FEATURE_FLAGS = { | ||
NEW_ABOUT_PAGE: 'New_About_Page', | ||
NEW_MARKETING_PAGE: 'New_Marketing_Page', | ||
NEW_PRODUCT_PAGE: 'New_Product_Page', | ||
} as const | ||
|
||
export type FEATURE_FLAGS = typeof FEATURE_FLAGS[keyof typeof FEATURE_FLAGS] | ||
|
||
export const DISTINCT_ID_COOKIE_NAME = 'distinct_id' |
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,62 @@ | ||
import { FEATURE_FLAGS } from './constants' | ||
|
||
/** | ||
* Checks if a feature flag is enabled. | ||
* | ||
* @param distinctUserId A unique identifier for the user | ||
* @param featureName The name of the feature flag | ||
* @returns true if the feature flag is enabled. Otherwise, false. | ||
*/ | ||
export async function isFeatureFlagEnabled( | ||
distinctUserId: string, | ||
featureName: FEATURE_FLAGS | ||
): Promise<boolean> { | ||
console.log('isFeatureEnabled', distinctUserId, featureName) | ||
|
||
const featureFlagValue = await getFeatureFlagVariant( | ||
distinctUserId, | ||
featureName | ||
) | ||
|
||
const featureEnabled = featureFlagValue ? true : false | ||
console.log('featureEnabled', featureEnabled) | ||
|
||
return featureEnabled | ||
} | ||
|
||
/** | ||
* Retrieves the value of the feature flag. | ||
* | ||
* @param distinctUserId A unique identifier for the user | ||
* @param featureName The name of the feature flag | ||
* @returns If the feature flag is an A/B test, then the value may be true or undefined. | ||
* If the feature flag is a multvariate, then the value will be a string | ||
*/ | ||
export async function getFeatureFlagVariant( | ||
distinctUserId: string, | ||
featureName: FEATURE_FLAGS | ||
): Promise<string | boolean | undefined> { | ||
console.log('getFeatureFlagVariant', distinctUserId, featureName) | ||
|
||
const res = await fetch( | ||
`${process.env.NEXT_PUBLIC_POSTHOG_HOST}/decide?v=2`, | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
api_key: process.env.NEXT_PUBLIC_POSTHOG_PROJECT_API_KEY, | ||
distinct_id: distinctUserId, | ||
}), | ||
} | ||
) | ||
|
||
if (!res.ok) { | ||
throw new Error( | ||
`Fetch request to retrieve the ${featureName} flag status failed with: (${res.status}) ${res.statusText}` | ||
) | ||
} | ||
|
||
const data = await res.json() | ||
console.log(data) | ||
|
||
return data.featureFlags[featureName] | ||
} |
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,47 @@ | ||
import { useEffect } from 'react' | ||
import { useRouter } from 'next/router' | ||
import posthog, { PostHog } from 'posthog-js' | ||
|
||
let POSTHOG_INSTANCE: PostHog | ||
|
||
export const usePostHog = ( | ||
apiKey: string, | ||
config?: posthog.Config, | ||
name?: string | ||
): void => { | ||
const router = useRouter() | ||
|
||
if (config.loaded) { | ||
// override the existing loaded function so we can store a reference | ||
// to the PostHog instance | ||
const oldLoaded = config.loaded | ||
config.loaded = (posthog: PostHog) => { | ||
setPostHogInstance(posthog) | ||
oldLoaded(POSTHOG_INSTANCE) | ||
} | ||
} else { | ||
config.loaded = setPostHogInstance | ||
} | ||
|
||
useEffect((): (() => void) => { | ||
if (typeof window === undefined) return | ||
|
||
posthog.init(apiKey, config, name) | ||
|
||
// Track page views | ||
const handleRouteChange = () => posthog.capture('$pageview') | ||
router.events.on('routeChangeComplete', handleRouteChange) | ||
|
||
return () => { | ||
router.events.off('routeChangeComplete', handleRouteChange) | ||
} | ||
}, [router.events]) | ||
} | ||
|
||
const setPostHogInstance = (posthog: PostHog) => { | ||
POSTHOG_INSTANCE = posthog | ||
} | ||
|
||
export const getPostHogInstance = (): PostHog => { | ||
return POSTHOG_INSTANCE | ||
} |
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,6 @@ | ||
/// <reference types="next" /> | ||
/// <reference types="next/types/global" /> | ||
/// <reference types="next/image-types/global" /> | ||
|
||
// NOTE: This file should not be edited | ||
// see https://nextjs.org/docs/basic-features/typescript for more information. |
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 @@ | ||
const withTM = require('@vercel/edge-functions-ui/transpile')() | ||
|
||
module.exports = withTM() |
Oops, something went wrong.
e660a99
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
edge-functions-news – ./edge-functions/power-parity-pricing-strategies
edge-functions-news-git-main.vercel.sh
edge-functions-news.vercel.sh