> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useshipd.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run an A/B test

> Split users across variants of a variant flag with sticky assignment, read the variant, and record exposure in your analytics.

## Overview

An experiment in shipd is a [variant flag](/flags/variants.md) whose rules split users across variants. Assignment is deterministic and sticky per user. shipd assigns variants; it does not compute experiment results, so you record each exposure in your own analytics.

## Define the variants

```ts TypeScript theme={null}
// shipd.config.ts
import { defineFlags } from "shipdit/config";

export default defineFlags({
  "search-variant": {
    type: "variant",
    variants: ["control", "semantic", "hybrid"] as const,
    default: "control",
    description: "Search ranking experiment",
    tags: ["search", "experiment"],
  },
});
```

```go Go theme={null}
// Entries inside config.ShipdConfig (import github.com/alasti-company/useshipd.com/sdks/go/config).
"search-variant": {Type: "variant", Default: "control",
    Variants: []string{"control", "semantic", "hybrid"},
    Description: "Search ranking experiment", Tags: []string{"search", "experiment"}},
```

For Go, add definitions to `Config` in `shipd.config.go`, then run `shipd push`. See [Define flags in code](/config-as-code/define-flags.md#go-definitions) for the complete file.

```bash theme={null}
shipd push --project web-app --env production
```

## Split traffic

Percentage conditions on the same flag share one bucket per user, so stacked rules with increasing **Rollout** values split users into slices. For a three-way split:

| Rule | Condition | Serve |
| - | - | - |
| 1 | **Percentage**, **Rollout** `33` | `semantic` |
| 2 | **Percentage**, **Rollout** `66` | `hybrid` |
| Fallthrough | | `control` |

Buckets 0–3299 get `semantic`, 3300–6599 get `hybrid` (rule 1 already matched the lower buckets), and the rest fall through to `control`.

**1. Open the flag**

In the [dashboard](https://app.useshipd.com), open the project, click `search-variant`, and select the environment.

**2. Add the rules**

Click **Add rule**, then **Percentage**, and set **Rollout** and **Serve** as in the table. Repeat for the second rule. Keep them in this order.

**3. Save**

Set **Fallthrough** to `control` and click **Save environment**.

Users without a `userId` never match a percentage condition, so they get `control`. Don't change the **Rollout** values or **Seed** mid-experiment; that moves users between variants. See [how bucketing works](/flags/percentage-rollouts.md#how-bucketing-works).

> [!NOTE]
>
> Rules and **Fallthrough** can also use a weighted serve (`kind: "weighted"`) that splits by weights in a single serve. The dashboard editor keeps existing weighted serves but doesn't edit their weights; set them through the [control-plane API](/reference/control-plane-api.md).

## Read the variant and record exposure

```ts TypeScript theme={null}
// src/search.ts
import { shipd } from "./lib/shipd";
import { analytics } from "./lib/analytics";

export function search(userId: string, query: string) {
  const variant = shipd.getVariant("search-variant", { userId });

  analytics.track("experiment_exposure", {
    userId,
    experiment: "search-variant",
    variant,
  });

  switch (variant) {
    case "semantic":
      return semanticSearch(query);
    case "hybrid":
      return hybridSearch(query);
    default:
      return controlSearch(query);
  }
}
```

```go Go theme={null}
// search.go
variant := client.GetVariant("search-variant", shipd.EvaluationContext{UserID: userID})
analytics.Track("experiment_exposure", map[string]any{
    "userId": userID, "experiment": "search-variant", "variant": variant,
})
// Use variant to choose the search implementation.
```

Log the exposure where the user actually sees the variant, and send your outcome metric (searches, conversions) to the same analytics tool. Compare metrics by `variant` there.

SDKs also send evaluation events from production environments. The flag page's **Traffic** section uses them to show recent evaluations. They are not experiment analysis.

## End the experiment

Set **Fallthrough** to the winning variant, remove the percentage rules, and click **Save environment**. Then update `default` in your flag definitions to match, or remove the flag from code and [archive it](/flags/naming-and-lifecycle.md).

## Related

* [Create a variant flag](/flags/variants.md)
* [`getVariant`](/reference/sdk#getvariant)
* [Roll out a flag to a percentage of users](/flags/percentage-rollouts.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.