Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PostHog feature flag example #20

Merged
merged 7 commits into from Oct 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions edge-functions/feature-flag-posthog/.env.example
@@ -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=
34 changes: 34 additions & 0 deletions edge-functions/feature-flag-posthog/.gitignore
@@ -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
43 changes: 43 additions & 0 deletions edge-functions/feature-flag-posthog/README.md
@@ -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
```
11 changes: 11 additions & 0 deletions edge-functions/feature-flag-posthog/lib/constants.ts
@@ -0,0 +1,11 @@
/**
* List of known active Feature Flags
*/
export const FEATURE_FLAGS = {
NEW_ABOUT_PAGE: 'New_About_Page',
NEW_MARKETING_PAGE: 'New_Marketing_Page',
} as const

export type FEATURE_FLAGS = typeof FEATURE_FLAGS[keyof typeof FEATURE_FLAGS]
leerob marked this conversation as resolved.
Show resolved Hide resolved

export const DISTINCT_ID_COOKIE_NAME = 'distinct_id'
33 changes: 33 additions & 0 deletions edge-functions/feature-flag-posthog/lib/posthog-node.ts
@@ -0,0 +1,33 @@
import { FEATURE_FLAGS } from './constants'

/**
* Checks if a feature flag is enabeld.
*/
export async function isFeatureFlagEnabled(distinctUserId: string, featureName: FEATURE_FLAGS): Promise<boolean> {
console.log('isFeatureEnabled', 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)

const featureEnabled = data.featureFlags[featureName] || false
console.log('featureEnabled', featureEnabled)

return featureEnabled
}
43 changes: 43 additions & 0 deletions edge-functions/feature-flag-posthog/lib/posthog.ts
@@ -0,0 +1,43 @@
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 store get 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
}
6 changes: 6 additions & 0 deletions edge-functions/feature-flag-posthog/next-env.d.ts
@@ -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.
3 changes: 3 additions & 0 deletions edge-functions/feature-flag-posthog/next.config.js
@@ -0,0 +1,3 @@
const withTM = require('@vercel/edge-functions-ui/transpile')()

module.exports = withTM()