Amplitude
Introduction
To compare an experiment's variations in Amplitude, your application tells Amplitude which variation each user saw. You add a handler once, and Amplitude joins those exposures to the events you already send it.
Nothing passes through ConfigDirector, and ConfigDirector never holds your Amplitude API key.
What Amplitude reads
Amplitude's experiment analysis reads an $exposure event with two properties:
| Property | What you send | Example |
|---|---|---|
flag_key | The config key | checkout-cta-copy |
variant | The variation's name | treatment-a |
When it receives the event, Amplitude renames it [Experiment] Exposure and sets the user property [Experiment] checkout-cta-copy to the variation's name.
Add the handler
Add a handler for the configEvaluated hook where you create the client, in the browser or in Node.js:
import * as amplitude from "@amplitude/analytics-browser";
import { createClient } from "@configdirector/client-sdk";
amplitude.init("YOUR-AMPLITUDE-API-KEY");
export const client = createClient("YOUR-CLIENT-SDK-KEY", {
hooks: {
configEvaluated: ({ evaluation }) => {
const variationName = evaluation.variation?.name;
if (!variationName) return;
amplitude.track("$exposure", { flag_key: evaluation.key, variant: variationName });
},
},
});
await client.initialize({ id: "user-42" });
import { init, track } from "@amplitude/analytics-node";
import { createClient } from "@configdirector/server-sdk";
init("YOUR-AMPLITUDE-API-KEY");
export const client = createClient("YOUR-SERVER-SDK-KEY", {
hooks: {
configEvaluated: ({ evaluation }) => {
const variationName = evaluation.variation?.name;
const userId = evaluation.context?.id;
if (!variationName || !userId) return;
track("$exposure", { flag_key: evaluation.key, variant: variationName }, { user_id: userId });
},
},
});
await client.initialize();
Only an experiment's evaluations carry a variation, so the check skips every other config, along with the in-code default value. It also skips a variation without a name, so name each one. Never send an exposure without a variant, because Amplitude takes that user out of the experiment.
In the browser, Amplitude attaches the exposure to the user you have identified to it. In Node.js, the handler passes the context's id as the user ID, so it has to be the ID your other Amplitude events use. A context without an id is skipped, since it does not take part in the split on a server.
The handler needs version 1.11.0 or later of the JavaScript SDK, or 1.13.0 or later of the Node.js SDK. React, Vue and React Native take the same handler in their hooks. The Experiments guide lists the hook for every other SDK.
With OpenFeature
In an OpenFeature application, a hook does the same job, with the variant as the variation's name. Every config has a variant, not only experiments: on any other config it is ConfigDirector's ID for the value. So attach the hook to the reads of your experiments instead of registering it for every read:
import * as amplitude from "@amplitude/analytics-browser";
import { OpenFeature, type Hook } from "@openfeature/web-sdk";
amplitude.init("YOUR-AMPLITUDE-API-KEY");
const reportExposure: Hook = {
after: (hookContext, details) => {
if (!details.variant) return;
amplitude.track("$exposure", { flag_key: hookContext.flagKey, variant: details.variant });
},
};
const client = OpenFeature.getClient();
const buttonLabel = client.getStringValue("checkout-cta-copy", "Start free trial", {
hooks: [reportExposure],
});
import { init, track } from "@amplitude/analytics-node";
import { OpenFeature, type Hook } from "@openfeature/server-sdk";
init("YOUR-AMPLITUDE-API-KEY");
const reportExposure: Hook = {
after: (hookContext, details) => {
const userId = hookContext.context.targetingKey;
if (!details.variant || !userId) return;
track("$exposure", { flag_key: hookContext.flagKey, variant: details.variant }, { user_id: userId });
},
};
const client = OpenFeature.getClient();
const buttonLabel = await client.getStringValue(
"checkout-cta-copy",
"Start free trial",
{ targetingKey: "user-42" },
{ hooks: [reportExposure] },
);
A variation without a name also has ConfigDirector's ID for the value as its variant, so name each one. The hook needs version 1.11.0 or later of the Web provider, or 1.13.0 or later of the Node.js provider.
When the handler runs
The handler runs once per evaluation, whenever your application reads the config. So read an experiment where the user reaches the change rather than at startup, or users who never see it count as exposed.
A config read on every render sends an event each time. That does not skew the results or add to your bill: Amplitude counts each user once per variant, and exposure events do not count toward your event volume or Monthly Tracked Users.
Compare the variations
The outcomes you compare are the events your application already sends to Amplitude, so there is nothing more to add to your code.
An Experiment Results chart, available on Amplitude's Growth and Enterprise plans, compares them per variation:
- Go to Create > Chart > Experiment Results.
- In the Metrics module, add the event you want to compare.
- In the Exposure module, add
[Experiment] Exposure, where[Experiment] Flag Keyis your config key. - In the Variants performed by module, add a variant for each variation, using the user property
[Experiment] checkout-cta-copy.
The handler also runs outside the split: before the run starts, after you ship and when a conditional rule serves a variation. So set the chart to the dates of the run, which the Experiment tab lists. A conditional rule above the split can still make Amplitude's numbers higher than the Exposures card, which counts only the contexts the split served.
Keep each variation's name for the length of the run, because Amplitude treats a new name as a new variant.
To mark each run's start, split change, ship and stop on these charts without code, set up an Amplitude integration.
Analytics integrations
Mark every experiment run on the charts of Amplitude, Mixpanel, Datadog, Grafana or PostHog. What an integration posts, how to set one up per tool, the endpoint URL override, delivery, and what happens when a tool stops accepting the markers.
Mixpanel
Report experiment exposures to Mixpanel from your application, so you can compare the variations next to the events you already track there.