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

# React Native Experiments

> A/B test with deterministic, offline-capable bucketing

The experiments module assigns users to variants using a deterministic hash. No server call is needed -- assignment is instant, works offline, and the same user always gets the same variant.

## Get Variant

```typescript theme={null}
const variant = AppDNA.experiments.getVariant("paywall-test");

if (variant === "variant_a") {
  showNewPaywall();
} else {
  showStandardPaywall(); // Always handle the default case
}
```

Returns the variant string or `null` if the experiment is not found, not running, or the user is not in the target audience.

<Warning>
  Always handle the `null` / default case. Experiments can be archived or stopped at any time from the Console.
</Warning>

## Module Access

```typescript theme={null}
const experiments = AppDNA.experiments;
```

### Module Methods

| Method          | Signature                                                                                 | Description                      |
| --------------- | ----------------------------------------------------------------------------------------- | -------------------------------- |
| `getVariant`    | `getVariant(experimentId: string, options?: { trackExposure?: boolean }): string \| null` | Get the assigned variant         |
| `trackExposure` | `trackExposure(experimentId: string): void`                                               | Manually track an exposure event |

## Exposure Tracking

### Automatic (Default)

The SDK tracks an `experiment_exposure` event **once per session** the first time `getVariant()` is called for a given experiment.

### Manual

Disable automatic tracking and track when the UI is actually visible:

```typescript theme={null}
const variant = AppDNA.experiments.getVariant("paywall-test", {
  trackExposure: false,
});

// Later, when the paywall is actually displayed
function onPaywallVisible() {
  AppDNA.experiments.trackExposure("paywall-test");
}
```

## Listen for Assignment Changes

```typescript theme={null}
const unsubscribe = AppDNA.experiments.onAssignmentChanged(
  (experimentId: string, newVariant: string | null) => {
    console.log(`Experiment ${experimentId} now: ${newVariant ?? "none"}`);
  }
);

// Clean up
unsubscribe();
```

<Note>
  Assignment changes are rare. They occur only when the experiment definition changes on the server, not on every session start.
</Note>

## Experiment Lifecycle

| Status        | `getVariant()` returns        |
| ------------- | ----------------------------- |
| **Draft**     | `null` -- not visible to SDKs |
| **Running**   | Assigned variant string       |
| **Completed** | Winning variant for all users |
| **Archived**  | `null` -- removed from config |

## Full Example

```typescript theme={null}
import { AppDNA } from "@appdna-ai/react-native-sdk";
import React, { useEffect } from "react";

function PaywallScreen() {
  useEffect(() => {
    const unsubscribe = AppDNA.experiments.onAssignmentChanged(
      (experimentId, newVariant) => {
        // Handle mid-session assignment change (rare)
      }
    );
    return () => unsubscribe();
  }, []);

  function showPaywall() {
    const variant = AppDNA.experiments.getVariant("paywall_redesign");
    const paywallId = variant === "new_design" ? "paywall_v2" : "paywall_v1";

    AppDNA.paywall.present(paywallId, {
      placement: "settings",
      customData: {
        experiment: "paywall_redesign",
        variant: variant ?? "control",
      },
    });
  }

  return <Button title="Upgrade" onPress={showPaywall} />;
}
```

<Info>
  Experiments are created in the Console under **Experiments**. The SDK uses MurmurHash3 for deterministic assignment -- the same user always gets the same variant across sessions, platforms, and offline.
</Info>
