How to set up a public beta program using early access management
Jul 28, 2023
Public betas are a way to get new features into the hands of users and get valuable feedback and analytics. In this tutorial, we show you how to add a basic public beta program to your app with PostHog’s early access management feature.
Our example uses Next.js, but this also works for other frameworks and languages.
Already have an app and PostHog set up? Skip creating the beta feature.
Creating a Next.js app and adding PostHog
First, create a Next.js app. To do so, install Node and run the command below. Select No for TypeScript, Yes for use app router
, and the defaults for every other option.
npx create-next-app@latest beta-program
Next, we go into our newly created beta-program folder and install PostHog.
cd beta-programnpm i posthog-js
After this, we initialize PostHog. Create a providers.js
file in the app
folder, then set up PostHog with your project API key and instance address (which you get from your project settings). Make sure to include the use client
directive, a check for the window, and opt-in to site apps (which we will use later).
// app/providers.js'use client'import posthog from 'posthog-js'import { PostHogProvider } from 'posthog-js/react'import { useEffect } from 'react'export function PHProvider({ children }) {useEffect(() => {posthog.init('<ph_project_api_key>', {api_host: 'https://us.i.posthog.com',person_profiles: 'identified_only',opt_in_site_apps: true})}, []);return <PostHogProvider client={posthog}>{children}</PostHogProvider>}
We then import the PHProvider
into layout.js
and wrap our app in it.
// app/layout.jsimport { PHProvider } from './providers'export default function RootLayout({ children }) {return (<html lang="en"><PHProvider><body>{children}</body></PHProvider></html>)}
After setting this all up and running npm run dev
, we are ready to set up our public beta program.
Creating our beta feature in PostHog
Next, we create our beta feature in PostHog. As an example, we create a beta for a new set of docs.
To start, go to the early access management tab in PostHog and click "New public beta." Give your beta a name like "New docs," any other details you want, and click "Save as draft." This automatically creates a feature flag we can use. Finally, click "Release beta."
Adding our beta functionality
Next, we add our beta functionality. To do this, we check our new-docs
feature flag with useFeatureFlagEnabled
to show more documentation on our main page.js
page.
'use client'import { useFeatureFlagEnabled } from 'posthog-js/react'export default function Home() {const newDocs = useFeatureFlagEnabled('new-docs')return (<div><h1>Welcome to our app</h1><p>This is the old documentation</p>{newDocs && (<p>This is the new cool beta managed documentation</p>)}</div>)}
When we run npm run dev
again and go to our localhost, we see the old documentation because we haven’t joined the beta yet.
Adding our public beta opt-in to our app
To make this beta a public one, we need a way for people to opt in on our site. The easiest way to do this is using PostHog’s early access modal site app.
To set this up, search for the "Early Access Features App," enable it, set a selector of #beta-button
, and press save.
Because we set opt_in_site_apps: true
in config earlier, all we do is add a button to our page.js
file with the ID of beta-button
. Clicking this button opens a modal that enables users to opt into public betas for your app.
// app/page.js'use client'import { useFeatureFlagEnabled } from 'posthog-js/react'export default function Home() {const newDocs = useFeatureFlagEnabled('new-docs')return (<div><h1>Welcome to our app</h1><p>This is the old documentation</p>{newDocs && (<p>This is the new cool beta managed documentation</p>)}<button id="beta-button">Public Betas</button></div>)}
When you head back to your browser and click the "Public Betas" button, a modal pops up allowing users to opt into the "New docs" beta. Once they do this, they see the new text we added behind the flag earlier.
This is a simple example of a public beta you can set up. At PostHog, we’ve used early access management to run public betas for full features like surveys, notebooks, and our data warehouse.
Creating a beta opt-in page
For full control over our beta opt-in page, we can create a custom page instead of using the modal.
To do this, first, create a new folder named beta
. In this beta
folder, create a file named page.js
. In this file, we will:
- Check for available betas and active feature flags.
- Create two lists: currently active betas and currently inactive betas.
- Display each list on the page with buttons to opt in or out of the beta.
- Toggle their early access enrollment when they click those buttons.
First, set up a basic page with PostHog, our active flags, states for active and inactive betas, and spots to display both of them.
// app/beta/page.js'use client'import { useActiveFeatureFlags, usePostHog } from 'posthog-js/react'import { useState, useEffect } from 'react'export default function Beta() {const posthog = usePostHog()const activeFlags = useActiveFeatureFlags()const [activeBetas, setActiveBetas] = useState([])const [inactiveBetas, setInactiveBetas] = useState([])return (<div><h1>Available betas</h1><h3>Inactive</h3><h3>Active</h3></div>)}
Next, we set up a useEffect
hook for our key logic. It filters the early access features (from getEarlyAccessFeatures
) into active and inactive betas depending on if the flag key exists and then sets those two filtered lists in their states. We also just set all betas to inactive if they don’t have any active flags.
// ...const [inactiveBetas, setInactiveBetas] = useState([])useEffect(() => {posthog.getEarlyAccessFeatures((features) => {if (!activeFlags || activeFlags.length === 0) {setInactiveBetas(features)return}const activeBetas = features.filter(beta => activeFlags.includes(beta.flagKey));const inactiveBetas = features.filter(beta => !activeFlags.includes(beta.flagKey));setActiveBetas(activeBetas)setInactiveBetas(inactiveBetas)}, true)}, [activeFlags])return (// ...
We then map the active and inactive beta states on our page.
//...return (<div><h1>Available betas</h1><h3>Inactive</h3>{inactiveBetas.map(beta => (<div key={beta.id}>{beta.name}</div>))}<h3>Active</h3>{activeBetas.map(beta => (<div key={beta.id}>{beta.name}</div>))}</div>)}
This displays the active and inactive betas (you can create and launch another inactive beta feature to show that it works if you want).
The last piece is adding buttons to let users opt-in and out. To do this, we create a function that checks if the related flag key is in the activeBetas
state.
- If the flag key is active, it then calls
updateEarlyAccessFeatureEnrollment
with the key andfalse
, removing them from the beta, and updates theactiveBetas
state. - If the flag key is inactive, it does the opposite. It calls
updateEarlyAccessFeatureEnrollment
with the key andtrue
,and removes them frominactiveBetas
state.
We also add buttons to call this function and opt in or out.
// ...const toggleBeta = (betaKey) => {if (activeBetas.some(beta => beta.flagKey === betaKey)) {posthog.updateEarlyAccessFeatureEnrollment(betaKey, false)setActiveBetas(prevActiveBetas => prevActiveBetas.filter(item => item.flagKey !== betaKey));return}posthog.updateEarlyAccessFeatureEnrollment(betaKey, true)setInactiveBetas(prevInactiveBetas => prevInactiveBetas.filter(item => item.flagKey !== betaKey));}return (<div><h1>Available betas</h1><h3>Inactive</h3>{inactiveBetas.map(beta => (<div key={beta.id}>{beta.name} - <button onClick={() => toggleBeta(beta.flagKey)}>Opt In</button></div>))}<h3>Active</h3>{activeBetas.map(beta => (<div key={beta.id}>{beta.name} - <button onClick={() => toggleBeta(beta.flagKey)}>Opt Out</button></div>))}</div>)// ...
With this, our beta page is all set up. Users can opt-in and out of betas whenever they want. You can customize it further to your needs.
Further reading
- How to collect beta feedback from beta users
- Get feedback and book user interviews with surveys
- How to use Next.js middleware to bootstrap feature flags