Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions edge-middleware/ab-testing-statsig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ useCase:
- Edge Middleware
- Documentation
css: Tailwind
deployUrl: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fedge-middleware%2Fab-testing-statsig&project-name=ab-testing-statsig&repository-name=ab-testing-statsig&integration-ids=oac_NAO87zzp3ADxj2ZUh3vikLip&env=STATSIG_SERVER_API_KEY,NEXT_PUBLIC_STATSIG_CLIENT_KEY,STATSIG_CONSOLE_API_KEY,EDGE_CONFIG,EDGE_CONFIG_ITEM_KEY&envDescription=Statsig%20API%20keys%20and%20Edge%20Config%20settings&envLink=https%3A%2F%2Fdocs.statsig.com%2Fguides%2Ffirst-feature
deployUrl: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fedge-middleware%2Fab-testing-statsig&project-name=ab-testing-statsig&repository-name=ab-testing-statsig&integration-ids=oac_NAO87zzp3ADxj2ZUh3vikLip
demoUrl: https://edge-ab-testing-statsig.vercel.app
relatedTemplates:
- ab-testing-google-optimize
Expand All @@ -31,7 +31,7 @@ You can choose from one of the following two methods to use this repository:

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=vercel-examples):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fedge-middleware%2Fab-testing-statsig&project-name=ab-testing-statsig&repository-name=ab-testing-statsig&integration-ids=oac_NAO87zzp3ADxj2ZUh3vikLip&env=STATSIG_SERVER_API_KEY,NEXT_PUBLIC_STATSIG_CLIENT_KEY,STATSIG_CONSOLE_API_KEY,EDGE_CONFIG,EDGE_CONFIG_ITEM_KEY&envDescription=Statsig%20API%20keys%20and%20Edge%20Config%20settings&envLink=https%3A%2F%2Fdocs.statsig.com%2Fguides%2Ffirst-feature)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fedge-middleware%2Fab-testing-statsig&project-name=ab-testing-statsig&repository-name=ab-testing-statsig&integration-ids=oac_NAO87zzp3ADxj2ZUh3vikLip)

### Clone and Deploy

Expand Down
27 changes: 16 additions & 11 deletions edge-middleware/ab-testing-statsig/lib/statsig-api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const STATSIG_URL = 'https://statsigapi.net'
const STATSIG_CONSOLE_API_KEY = process.env.STATSIG_CONSOLE_API_KEY!
const STATSIG_CONSOLE_API_KEY = process.env.STATSIG_CONSOLE_API_KEY ?? ''

/**
* Fetch wrapper for the Statsig API
Expand Down Expand Up @@ -44,17 +44,22 @@ async function statsig(

const api = {
async getBuckets(experiment: string) {
// https://docs.statsig.com/console-api/experiments#get-/experiments/-experiment_id-
const experimentConfig = await statsig(
`/console/v1/experiments/${experiment}`,
'GET',
{ apiKey: STATSIG_CONSOLE_API_KEY }
)
try {
// https://docs.statsig.com/console-api/experiments#get-/experiments/-experiment_id-
const experimentConfig = await statsig(
`/console/v1/experiments/${experiment}`,
'GET',
{ apiKey: STATSIG_CONSOLE_API_KEY }
)

return experimentConfig.data.groups.map(
(group: { parameterValues: { bucket: string } }) =>
group.parameterValues.bucket
)
return experimentConfig.data.groups.map(
(group: { parameterValues: { bucket: string } }) =>
group.parameterValues.bucket
)
} catch (e) {
console.error('Failed to fetch buckets from Statsig', e)
return []
}
},
}

Expand Down
25 changes: 20 additions & 5 deletions edge-middleware/ab-testing-statsig/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ import { EXPERIMENT, UID_COOKIE, GROUP_PARAM_FALLBACK } from './lib/constants'
// We'll use this to validate a random UUID
const IS_UUID = /^[0-9a-f-]+$/i

const edgeConfigClient = createClient(process.env.EDGE_CONFIG)
const dataAdapter = new EdgeConfigDataAdapter({
edgeConfigClient,
edgeConfigItemKey: process.env.EDGE_CONFIG_ITEM_KEY!,
})
let dataAdapter: EdgeConfigDataAdapter;

const missingEdgeConfigEnvVars = !process.env.EDGE_CONFIG || !process.env.EDGE_CONFIG_ITEM_KEY
const missingConsoleApiEnvVars = !process.env.STATSIG_CONSOLE_API_KEY

if (!missingEdgeConfigEnvVars) {
const edgeConfigClient = createClient(process.env.EDGE_CONFIG)
dataAdapter = new EdgeConfigDataAdapter({
edgeConfigClient,
edgeConfigItemKey: process.env.EDGE_CONFIG_ITEM_KEY!,
})
}

export const config = {
matcher: '/',
Expand Down Expand Up @@ -75,6 +82,14 @@ export async function middleware(req: NextRequest, event: NextFetchEvent) {
const url = req.nextUrl.clone()
url.pathname = `/${bucket}`

if (missingEdgeConfigEnvVars) {
url.searchParams.set('missingEdgeConfigEnvVars', 'true');
}

if (missingConsoleApiEnvVars) {
url.searchParams.set('missingConsoleApiEnvVars', 'true');
}

// Response that'll rewrite to the selected bucket
const res = NextResponse.rewrite(url)

Expand Down
51 changes: 39 additions & 12 deletions edge-middleware/ab-testing-statsig/pages/[bucket].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const getStaticPaths: GetStaticPaths<{ bucket: string }> = async () => {
}

function BucketPage({ bucket }: Props) {
const { reload } = useRouter()
const { query, reload } = useRouter()

function resetBucket() {
Cookie.remove(UID_COOKIE)
Expand All @@ -52,23 +52,14 @@ function BucketPage({ bucket }: Props) {
return (
<Page className="flex flex-col gap-12">
<section className="flex flex-col gap-6">
<Text variant="h1">Performant experimentation with Statsig</Text>
<Text variant="h1">Experimentation with Statsig</Text>
<Text>
In this demo we use Statsig&apos;s Server SDK at the edge to pull
experiment variants and show the resulting allocation. We leverage the{' '}
<Link href="https://vercel.com/integrations/statsig" target="_blank">
edge config integration
</Link>{' '}
to pull Statsig configurations from the edge. As long as you have a
experiment variants and show the resulting allocation. As long as you have a
bucket assigned you will always see the same result, otherwise you
will be assigned a bucket to mantain the odds specified in the
experiment.
</Text>
<Text>
Buckets are statically generated at build time in a{' '}
<Code>/[bucket]</Code> page so its fast to rewrite to them. Take a
look at the <Code>middleware.ts</Code> file to know more.
</Text>
<Text>
You can reset the bucket multiple times to get a different bucket
assigned. You can configure your experiments, see diagnostics and
Expand Down Expand Up @@ -101,6 +92,42 @@ function BucketPage({ bucket }: Props) {
/>
</section>

<section className="flex flex-col gap-6">
<Text variant="h1">Leveraging Edge Config For Performance</Text>
{
query.missingEdgeConfigEnvVars ?
<Text>
You can leverage the {' '}
<Link href="https://vercel.com/integrations/statsig" target="_blank">
edge config integration
</Link>{' '} to pull Statsig configurations from the edge to improve performance. Follow the README for more information.
</Text> :
<Text>
We leverage the{' '}
<Link href="https://vercel.com/integrations/statsig" target="_blank">
edge config integration
</Link>{' '}
to pull Statsig configurations from the edge.
</Text>
}

{
query.missingConsoleApiEnvVars ?
<Text>
Set the STATSIG_CONSOLE_API_KEY env variable to leverage static page
generation. The sample pre-renders pages at build time in a{' '}
<Code>/[bucket]</Code> page based on the experiment variants
so its fast to rewrite to them. Take a look at the
<Code>middleware.ts</Code> file to know more.
</Text> :
<Text>
Buckets are statically generated at build time in a{' '}
<Code>/[bucket]</Code> page so its fast to rewrite to them. Take a
look at the <Code>middleware.ts</Code> file to know more.
</Text>
}
</section>

<section className="flex flex-col gap-6">
<Text variant="h2">Using metrics in your experiments</Text>
<Text>
Expand Down