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

# Add A/B test

> Create an A/B test.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Create an A/B test" href="/doc/libraries/sdk/methods/abtesting/add-ab-tests" />

**Required ACL:** `editSettings`

You can set an A/B test on two different indices with different settings,
or on the same index with different search parameters by providing a [`customSearchParameters`](/doc/libraries/sdk/v1/methods/add-ab-test#param-custom-search-parameters) setting on one of the variants.

## Examples

<CodeGroup>
  ```cs C# theme={"system"}
  var abTest = new ABTest
  {
      Name = "myABTest",
      Variants = new List<Variant>
      {
          new Variant
          {
              Index = "indexName1",
              TrafficPercentage = 90,
              Description = "a description"
          },
          new Variant
          {
              Index = "indexName1-alt",
              TrafficPercentage = 10,
              Description = "a description"
          }
      },
      EndAt = DateTime.UtcNow.AddDays(1)
  };

  // Add a new A/B Test
  AnalyticsClient analytics = new AnalyticsClient("YourApplicationID", "YourWriteAPIKey");
  analytics.AddABTest(abtest);

  // Asynchronous
  await analytics.AddABTestAsync(abtest);
  ```

  ```go Go theme={"system"}
  abTest := analytics.ABTest{
  	Name: "myABTest",
  	Variants: []analytics.Variant{
  		{
  			Index:             "indexName1",
  			TrafficPercentage: 90,
  			Description:       "a description",
  		},
  		{
  			Index:             "indexName1-alt",
  			TrafficPercentage: 10,
  		},
  	},
  	EndAt: time.Now().Truncate(time.Hour).Add(24 * time.Hour),
  }

  client := analytics.NewClient("YourApplicationID", "YourWriteAPIKey")
  res, err := client.AddABTest(abTest)
  ```

  ```java Java theme={"system"}
  OffsetDateTime utcNow = 
    OffsetDateTime.now(ZoneOffset.UTC)
    .withNano(0)
    .withSecond(0);

  ABTest abtest = new ABTest(
          "myABTest",
          Arrays.asList(
                  new Variant("indexName1", 90, "a description"),
                  new Variant("indexName1-alt", 10, null)),
          utcNow.plusDays(1));

  // Add a new AB Test
  AnalyticsClient analytics = 
  DefaultAnalyticsClient.create("YourApplicationID", "YourWriteAPIKey");

  analytics.addABTest(abtest);

  // Asynchronous
  analytics.addABTestAsync(abtest);
  ```

  ```js JavaScript theme={"system"}
  const endAt = new Date();
  endAt.setDate(endAt.getDate() + 1);

  const abTest = {
    name: "myABTest",
    variants: [
      {
        index: "indexName1",
        trafficPercentage: 90,
      },
      {
        index: "indexName1-alt",
        trafficPercentage: 10,
        description: "a description",
      },
    ],
    endAt: endAt.toISOString().replace(/\.[0-9]{3}/, ""),
  };

  const analytics = client.initAnalytics({
    // optional parameters
    region: "de",
    appId: "YourApplicationID",
    apiKey: "YourWriteAPIKey",
  });
  analytics.addABTest(abTest).then(({ abTestID }) => {
    console.log(abTestID);
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val dayInMilliseconds = 60 * 60 * 24 * 1000
  val abTest = ABTest(
      name = "myABTest",
      variantA = Variant(
          indexName = indexName1,
          trafficPercentage = 90,
          description = "a description"
      ),
      variantB = Variant(
          indexName = indexName2,
          trafficPercentage = 10,
          description = "a description"
      ),
      endAt = ClientDate(Time.getCurrentTimeMillis() + dayInMilliseconds)
  )

  clientAnalytics.addABTest(abTest)
  ```

  ```php PHP theme={"system"}
  $endDate = new \DateTime('tomorrow');
  $endDate = $endDate->format('Y-m-d\TH:i:s\Z');


  $analytics = AnalyticsClient::create(
    'YourApplicationID',
    'YourWriteAPIKey'
  );

  $analytics->addABTest([
    'name' => 'myABTest',
    'variants' => [
      [
        'index' => 'indexName1',
        'trafficPercentage' => 90,
        'description' =>  'a description'
      ],
      [
        'index' => 'indexName1-alt',
        'trafficPercentage' => 10
      ],
    ],
    "endAt" => $endDate,
  ]);
  ```

  ```python Python theme={"system"}
  ab_test = {
      "name": "myABTest",
      "variants": [
          {
              "index": "indexName1",
              "trafficPercentage": 90,
              "description": "a description",
          },
          {"index": "indexName1-alt", "trafficPercentage": 10},
      ],
      "endAt": datetime.datetime.utcnow().replace(day=29).strftime("%Y-%m-%dT%H:%M:%SZ"),
  }

  analytics = AnalyticsClient.create("YourApplicationID", "YourWriteAPIKey")

  analytics.add_ab_test(ab_test)
  ```

  ```ruby Ruby theme={"system"}
  tomorrow = Time.now + 24 * 60 * 60

  abtest = {
    name: "myABTest",
    variants: [
      {
        index: "indexName1",
        trafficPercentage: 90,
        description: "a description"
      },
      {
        index: "indexName1-alt",
        trafficPercentage: 10
      }
    ],
    endAt: tomorrow.strftime("%Y-%m-%dT%H:%M:%SZ")
  }

  analytics = Algolia::Analytics::Client.create("YourApplicationID", "YourWriteAPIKey")
  analytics.add_ab_test(abtest)
  ```

  ```scala Scala theme={"system"}
  val abTest = ABTest(
    "myABTest",
    Seq(
      ABTestVariant("indexName1", 90, Some("a description")),
      ABTestVariant("indexName1-alt", 10, None)
    ),
    LocalDateTime.now().plusDays(1)
  )

  client.execute {
    add abTest abTest
  }
  ```

  ```swift Swift theme={"system"}
  let analyticsClient = AnalyticsClient(appID: "YourApplicationID", apiKey: "YourWriteAPIKey")

  let abTest = ABTest(name: "myABTest",
                      endAt: Date().addingTimeInterval(.day),
                      variantA: .init(indexName: "indexName1",
                                      trafficPercentage: 90,
                                      description: "a description"),
                      variantB: .init(indexName: "indexName2",
                                      trafficPercentage: 10,
                                      description: "a description"))

  analyticsClient.addABTest(abTest) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

### Add an A/B test on a single index with custom search parameters

<CodeGroup>
  ```cs C# theme={"system"}
  var abTest = new ABTest
  {
      Name = "myABTest",
      Variants = new List<Variant>
      {
          new Variant
          {
              Index = "indexName1",
              TrafficPercentage = 90
          },
          new Variant
          {
              Index = "indexName1",
              TrafficPercentage = 10,
              CustomSearchParameters = new Query { IgnorePlurals = true }
          }
      },
      EndAt = DateTime.UtcNow.AddDays(1)
  };

  var response = analytics.AddABTest(abTest);
  ```

  ```go Go theme={"system"}
  abTest := analytics.ABTest{
  	Name: "myABTest",
  	Variants: []analytics.Variant{
  		{
  			Index:             "indexName1",
  			TrafficPercentage: 90,
  		},
  		{
  			Index:             "indexName1",
  			TrafficPercentage: 10,
  			CustomSearchParameters: &search.QueryParams{
  				IgnorePlurals: opt.IgnorePlurals(true),
  			},
  		},
  	},
  	EndAt: time.Now().Truncate(time.Hour).Add(24 * time.Hour),
  }

  client := analytics.NewClient("YourApplicationID", "YourWriteAPIKey")
  res, err := client.AddABTest(abTest)
  ```

  ```java Java theme={"system"}
  OffsetDateTime utcNow = 
      OffsetDateTime.now(ZoneOffset.UTC)
      .withNano(0)
      .withSecond(0);

  Variant variantWithSearchParam = new Variant("indexName1", 10, null);

  variantWithSearchParam.setCustomSearchParameters(
          new Query().setIgnorePlurals(IgnorePlurals.of(true)));

  ABTest abtest =
        new ABTest(
                "myABTest",
                new Variant("indexName1", 90, null), variantWithSearchParam),
                utcNow.plusDays(1));

  analytics.addABTest(abtest);

  // Asynchronous
  analytics.addABTestAsync(abtest);
  ```

  ```js JavaScript theme={"system"}
  const endAt = new Date();
  endAt.setDate(endAt.getDate() + 1);

  const abTest = {
    name: "myABTest",
    variants: [
      {
        index: "indexName1",
        trafficPercentage: 90,
      },
      {
        index: "indexName1",
        trafficPercentage: 10,
        description: "a description",
        customSearchParameters: { ignorePlurals: true },
      },
    ],
    endAt: endAt.toISOString().replace(/\.[0-9]{3}/, ""),
  };

  const analytics = client.initAnalytics({
    // optional parameters
    region: "de",
    appId: "YourApplicationID",
    apiKey: "YourWriteAPIKey",
  });
  analytics.addABTest(abTest).then(({ abTestID }) => {
    console.log(abTestID);
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val dayInMilliseconds = 60 * 60 * 24 * 1000
  val abTest = ABTest(
      name = "myABTest",
      variantA = Variant(
          indexName = indexName1,
          trafficPercentage = 90,
          description = "a description"
      ),
      variantB = Variant(
          indexName = indexName1,
          trafficPercentage = 10,
          description = "a description",
          customSearchParameters = Query(ignorePlurals = IgnorePlurals.True)
      ),
      endAt = ClientDate(Time.getCurrentTimeMillis() + dayInMilliseconds)
  )

  clientAnalytics.addABTest(abTest)
  ```

  ```php PHP theme={"system"}
  $endAt = new DateTime('tomorrow');

  $abTest = [
      'name' => 'myABTest',
      'variants' => [
          ['index' => 'indexName1', 'trafficPercentage' => 90],
          [
              'index' => 'indexName1',
              'trafficPercentage' => 10,
              'customSearchParameters' => ['ignorePlurals' => true],
          ],
      ],
      'endAt' => $endAt->format('Y-m-d\TH:i:s\Z'),
  ];

  $response = $analyticsClient->addABTest($abTest);
  ```

  ```python Python theme={"system"}
  end_at = datetime.date.today() + datetime.timedelta(days=1)

  ab_test = {
      "name": "myABTest",
      "variants": [
          {"index": "indexName1", "trafficPercentage": 90},
          {
              "index": "indexName1",
              "trafficPercentage": 10,
              "customSearchParameters": {"ignorePlurals": True},
          },
      ],
      "endAt": end_at.strftime("%Y-%m-%dT%H:%M:%SZ"),
  }

  analytics.add_ab_test(ab_test)
  ```

  ```ruby Ruby theme={"system"}
  tomorrow = Time.now + 24 * 60 * 60

  abtest = {
    name: "myABTest",
    variants: [
      {
        index: "indexName1",
        trafficPercentage: 90,
        description: "a description"
      },
      {
        index: "indexName1",
        trafficPercentage: 10,
        customSearchParameters: {ignorePlurals: true}
      }
    ],
    endAt: tomorrow.strftime("%Y-%m-%dT%H:%M:%SZ")
  }

  analytics = client.init_analytics
  analytics.add_ab_test(abtest)
  ```

  ```scala Scala theme={"system"}
  val abTest = ABTest(
    "myABTest",
    Seq(
      ABTestVariant("indexName1", 90),
      ABTestVariant("indexName1", 10,
                      customSearchParameters =
                        Some(Query(ignorePlurals = Some(IgnorePlurals.`true`)))),
    ),
    LocalDateTime.now().plusDays(1)
  )

  client.execute {
    add abTest abTest
  }
  ```

  ```swift Swift theme={"system"}
  let analyticsClient = AnalyticsClient(appID: "YourApplicationID", apiKey: "YourWriteAPIKey")

  let abTest = ABTest(name: "myABTest",
                      endAt: Date().addingTimeInterval(.day),
                      variantA: .init(indexName: "indexName1",
                                      trafficPercentage: 90,
                                      description: "a description"),
                      variantB: .init(indexName: "indexName2",
                                      trafficPercentage: 10,
                                      customSearchParameters: Query()
                                        .set(\.ignorePlurals, to: true)
                                      description: "a description"))

  analyticsClient.addABTest(abTest) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

## Parameters

<ParamField body="abTest" type="object" required>
  The definition of the A/B test.

  <Expandable defaultOpen>
    <ParamField body="name" type="string" required>
      Name of the A/B test.
    </ParamField>

    <ParamField body="variants" type="object[]" required>
      A and B variants: the base index and a variant you want to test.

      <Expandable>
        <ParamField body="index" type="string" required>
          Index name
        </ParamField>

        <ParamField body="trafficPercentage" type="integer" required>
          Percentage of the search traffic that should be routed to this variant.
          The sum of percentages for both variants should be 100.
        </ParamField>

        <ParamField body="customSearchParameters" type="object">
          Applies search parameters to this variant.
          This parameter can only be used of both variants use the same index.

          <Accordion title="Supported parameters">
            Search:

            * [`advancedSyntax`](/doc/api-reference/api-parameters/advancedSyntax)
            * [`alternativesAsExact`](/doc/api-reference/api-parameters/alternativesAsExact)
            * [`distinct`](/doc/api-reference/api-parameters/distinct)
            * [`enableRules`](/doc/api-reference/api-parameters/enableRules)
            * [`exactOnSingleWordQuery`](/doc/api-reference/api-parameters/exactOnSingleWordQuery)
            * [`ignorePlurals`](/doc/api-reference/api-parameters/ignorePlurals)
            * [`minProximity`](/doc/api-reference/api-parameters/minProximity)
            * [`queryType`](/doc/api-reference/api-parameters/queryType)
            * [`removeStopWords`](/doc/api-reference/api-parameters/removeStopWords)
            * [`removeWordsIfNoResults`](/doc/api-reference/api-parameters/removeWordsIfNoResults)
            * [`sumOrFiltersScores`](/doc/api-reference/api-parameters/sumOrFiltersScores)

            Typo tolerance:

            * [`allowTyposOnNumericTokens`](/doc/api-reference/api-parameters/allowTyposOnNumericTokens)
            * [`disableTypoToleranceOnAttributes`](/doc/api-reference/api-parameters/disableTypoToleranceOnAttributes)
            * [`minWordSizefor1Typo`](/doc/api-reference/api-parameters/minWordSizefor1Typo)
            * [`minWordSizefor2Typos`](/doc/api-reference/api-parameters/minWordSizefor2Typos)
            * [`typoTolerance`](/doc/api-reference/api-parameters/typoTolerance)

            Facets:

            * [`facetingAfterDistinct`](/doc/api-reference/api-parameters/facetingAfterDistinct)
            * [`sortFacetValuesBy`](/doc/api-reference/api-parameters/sortFacetValuesBy)

            Synonyms:

            * [`replaceSynonymsInHighlight`](/doc/api-reference/api-parameters/replaceSynonymsInHighlight)
            * [`synonyms`](/doc/api-reference/api-parameters/synonyms)

            Personalization:

            * [`enablePersonalization`](/doc/api-reference/api-parameters/enablePersonalization)
            * [`personalizationImpact`](/doc/api-reference/api-parameters/personalizationImpact)

            Geo search:

            * [`aroundPrecision`](/doc/api-reference/api-parameters/aroundPrecision)
            * [`aroundRadius`](/doc/api-reference/api-parameters/aroundRadius)
            * [`minimumAroundRadius`](/doc/api-reference/api-parameters/minimumAroundRadius)
          </Accordion>
        </ParamField>

        <ParamField body="description" type="string">
          Description of the variant.
          This is useful when seeing the results in the dashboard or via the API.
        </ParamField>

        <ParamField body="estimatedSampleSize" type="integer">
          The estimated number of searches that will need to be run to achieve the desired confidence level and statistical power.
          A `minimumDetectableEffect` must be set in the configuration for this to be used.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField bods="endAt" type="string">
      Date when the A/B test automatically ends.

      **Format:** `Y-m-d\TH:i:s\Z`
    </ParamField>

    <ParamField body="configuration" type="object">
      Configuration settings for this A/B test.

      <Expandable>
        <ParamField body="emptySearch" type="object">
          <Expandable>
            <ParamField body="exclude" type="boolean" default={false}>
              Whether to exclude empty searches from the A/B test results.
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="minimumDetectableEffect" type="object">
          Options for calculating the minimum detectable effect.
          This requires setting the `estimatedSampleSize` parameter on one of the variants.

          <Expandable>
            <ParamField body="effect" type="enum<string>" required>
              The effect that you want to detect.
              One of:

              * `conversionRate`
              * `clickThroughRate`
              * `purchaseRate`
              * `addToCartRate`
            </ParamField>

            <ParamField body="size" type="number" required>
              The smallest relative difference between the variants that you want to detect.
              For example, to detect a 10% difference between the variants,
              set this to 0.1. The size must be between 0 and 1.
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="outliers" type="object">
          <Expandable>
            <ParamField body="exclude" type="boolean" default={true}>
              Whether to exclude outliers from the A/B test results.
              To *include* outliers in the statistics, set this option to `false`.
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="abTestID" type="integer">
  Generated Id of the A/B test.
</ResponseField>

<ResponseField name="index" type="string">
  Base index name for the A/B test.
</ResponseField>

<ResponseField name="taskID" type="integer">
  The task ID used with the [`waitTask`](/doc/libraries/sdk/v1/methods/wait-task) method.
</ResponseField>

### Response as JSON

This section shows the JSON response returned by the API.
Each API client wraps this response in language-specific objects, so the structure may vary.
To view the response, use the `getLogs` method.
Don't rely on the order of properties—JSON objects don't preserve key order.

```jsonc JSON icon=braces theme={"system"}
{
  "abTestID": 78,
  "taskID": 111885720
  "index": "atis-abtest-default",
}
```
