---
title: "Amplitude"
description: "Report experiment exposures to Amplitude from your application, so you can compare the variations next to the events you already track there."
canonical_url: "https://docs.configdirector.com/integrations/analytics/amplitude"
---
# Amplitude

> Report experiment exposures to Amplitude from your application, so you can compare the variations next to the events you already track there.

## Introduction

To compare an [experiment](https://docs.configdirector.com/getting-started/experiments)'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](https://amplitude.com/docs/feature-experiment/under-the-hood/event-tracking#exposure-events) with two properties:

<table>
<thead>
  <tr>
    <th>
      Property
    </th>
    
    <th>
      What you send
    </th>
    
    <th>
      Example
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        flag_key
      </code>
    </td>
    
    <td>
      The config key
    </td>
    
    <td>
      <code>
        checkout-cta-copy
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        variant
      </code>
    </td>
    
    <td>
      The variation's name
    </td>
    
    <td>
      <code>
        treatment-a
      </code>
    </td>
  </tr>
</tbody>
</table>

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](https://docs.configdirector.com/sdks/browser/javascript#hooks) or in [Node.js](https://docs.configdirector.com/sdks/server/node-js#hooks):

<code-group>

```ts [Browser]
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" });
```

```ts [Node.js]
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();
```

</code-group>

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](https://docs.configdirector.com/getting-started/experiments#create-the-experiment). 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](https://docs.configdirector.com/getting-started/experiments#send-exposures-to-your-analytics-tool) 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:

<code-group>

```ts [Web]
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],
});
```

```ts [Node.js]
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] },
);
```

</code-group>

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](https://docs.configdirector.com/sdks/openfeature/web#evaluation-details-and-hooks), or 1.13.0 or later of the [Node.js provider](https://docs.configdirector.com/sdks/openfeature/node-js#evaluation-details-and-hooks).

## 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](https://amplitude.com/docs/feature-experiment/advanced-techniques/cumulative-exposure-change-slope), and [exposure events do not count](https://amplitude.com/docs/feature-experiment/under-the-hood/event-tracking) 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](https://amplitude.com/docs/analytics/charts/experiment-results/experiment-results-dig-deeper), available on Amplitude's Growth and Enterprise plans, compares them per variation:

1. Go to **Create** > **Chart** > **Experiment Results**.
2. In the **Metrics** module, add the event you want to compare.
3. In the **Exposure** module, add `[Experiment] Exposure`, where `[Experiment] Flag Key` is your config key.
4. 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](https://docs.configdirector.com/getting-started/experiments#read-the-exposures) 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](https://docs.configdirector.com/integrations/analytics-integrations#amplitude).


## Sitemap

See the full [sitemap](https://docs.configdirector.com/sitemap.md) for all pages.
