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

# Experiments SDK

> @embeddables/experiments — sticky A/B test variant assignment

## Overview

Experiments puts each visitor into a variant of an A/B test and keeps it stable — the same visitor always sees the same variant on later visits, without asking the server again.

The walkthrough below covers install and setup. For every option, hook, and the `experiment:assigned`
event, open the [reference](/sdks/experiments/reference#methods).

## Implementation

### Install

<CodeGroup>
  ```bash npm theme={null}
  npm install @embeddables/core @embeddables/experiments
  ```

  ```bash pnpm theme={null}
  pnpm add @embeddables/core @embeddables/experiments
  ```

  ```bash yarn theme={null}
  yarn add @embeddables/core @embeddables/experiments
  ```
</CodeGroup>

Your experiment setup lives on Core (it comes from your generated config), so you never pass a separate `experiments` option to `initExperiments`. Install once, then pick your setup:

<Tabs>
  <Tab title="React">
    Follow the example below: wrap your app once, then read each visitor's test variant with `useExperiment`.

    ```tsx lines theme={null}
    import { EmbeddablesProvider } from '@embeddables/core/react'
    import { useExperiment } from '@embeddables/experiments/react'
    import { config } from './embeddables/_dist'
    import { modules } from './embeddables/_dist/modules'

    function Hero() {
      // Pass the experiment id — no type arguments needed.
      const { assignedVariantKey, assignedVariantTitle, status } = useExperiment({
        experimentId: 'exp-hero',
      })

      if (status === 'pending') return <p>Loading…</p>

      return <h1>{assignedVariantTitle ?? assignedVariantKey}</h1>
    }

    export function Root() {
      return (
        <EmbeddablesProvider
          config={{ ...config, publishableKey: 'pk_sandbox_<your-key>' }}
          modules={modules}
        >
          <Hero />
        </EmbeddablesProvider>
      )
    }
    ```

    If you used the CLI, the `modules` import in the example already turns Experiments on — you rarely
    need extra setup. For optional React details, see [`experiments()`](/sdks/experiments/reference#experiments-module)
    in the reference; for `useExperiment` and `useAssignExperiment`, see
    [hooks](/sdks/experiments/reference#hooks).

    <Warning>
      If Experiments is missing from your setup, `useExperiment` will error. Add the SDK with the CLI so
      it is included in the generated `modules` file.
    </Warning>

    #### Assign on demand

    `useExperiment` assigns the variant as soon as it renders. To assign at a specific moment instead, use `useAssignExperiment`:

    ```tsx lines theme={null}
    import { useAssignExperiment } from '@embeddables/experiments/react'

    function StartTrial() {
      const { assignExperiment, isPending } = useAssignExperiment()

      return (
        <button
          disabled={isPending}
          onClick={() => {
            void assignExperiment({ experimentId: 'exp-hero' }).then((assigned) => {
              if (assigned) console.log(assigned.variantKey, assigned.variantTitle)
            })
          }}
        >
          Start
        </button>
      )
    }
    ```

    A later `useExperiment({ experimentId: 'exp-hero' })` reads that same assignment back without another request. `assignExperiment` returns `undefined` if Experiments isn't set up, and rejects if the request fails.
  </Tab>

  <Tab title="JavaScript">
    ```typescript lines theme={null}
    import { initEmbeddables } from '@embeddables/core'
    import { initExperiments } from '@embeddables/experiments'
    import { config } from './embeddables/_dist'

    const embeddables = initEmbeddables({
      ...config,
      publishableKey: 'pk_sandbox_<your-key>',
    })

    const experiments = initExperiments({ core: embeddables })

    // `experimentId` must match an experiment in your config
    const hero = experiments.initExperiment({ experimentId: 'exp-hero' })
    const variantKey = await hero.getAssignedVariantKey()
    const variantTitle = await hero.getAssignedVariantTitle()
    ```

    The first time a visitor hits an experiment, it asks the Embeddables API, saves the result, and returns the variant. After that it reuses the saved value with no extra request. `getAssignedVariantKey()` is typed, so an invalid variant key is caught while you write code, not at runtime.

    Assignment requests send the project ID and experiment key — never the visitor's identity.

    Pass your initialized Core instance to `initExperiments`. Optional `serverAssignments` and Analytics wiring are listed in the [reference](/sdks/experiments/reference#options).
  </Tab>

  <Tab title="Server">
    ```typescript lines theme={null}
    import { initEmbeddablesServer } from '@embeddables/core/server'
    import { initExperimentsServer } from '@embeddables/experiments/server'
    import { config } from './embeddables/_dist'

    const server = initEmbeddablesServer({
      ...config,
      publishableKey: 'pk_sandbox_<your-key>',
      cookies: { get: (key) => request.cookies.get(key) ?? null },
    })

    const experiments = initExperimentsServer({ server })

    const hero = experiments.initExperiment({ experimentId: 'exp-hero' })
    const variantKey = await hero.getAssignedVariantKey()
    ```

    On the server, Experiments reads assignment cookies on the request; anything it fetches stays in memory
    for that request only (it does not set response cookies). To keep the same variant on the next load,
    set cookies yourself, use a custom `cookieStorage`, or pass `serverAssignments` in the browser — see
    the [reference](/sdks/experiments/reference#server).
  </Tab>
</Tabs>

### Analytics

Experiments never imports Analytics. In non-React code, create an Analytics client yourself and pass it in:

```typescript lines theme={null}
import { initAnalytics } from '@embeddables/analytics'

const analytics = initAnalytics({ core: embeddables })

const experiments = initExperiments({
  core: embeddables,
  analytics,
})
```

In React, adding both SDKs with the CLI connects Analytics to Experiments for you — no extra steps.

When Analytics is on, each **new** assignment fires one `experiment:assigned` event — a variant already saved from before doesn't fire again. If that event fails to send, the assignment is unaffected; it was already saved first.
