# Getting Started with Headless

This guide covers the shared setup steps for integrating Elevate A/B Testing into any headless storefront — Shopify Hydrogen, Next.js, or Remix. Complete these steps first, then follow the guide for your specific framework.

> **Using a standard Shopify theme?** This section is for headless storefronts only. For standard Shopify theme integration, see [Setup & Installation](https://docs.elevateab.com/elevate-helpcenter/getting-started/setup-and-installation).

### Installation

Install the SDK via npm:

```bash
npm install @elevateab/sdk
```

If you run into peer dependency conflicts (common with stores using older package versions), use the `--legacy-peer-deps` flag:

```bash
npm install @elevateab/sdk --legacy-peer-deps
```

**Peer dependencies:**

* `react` >= 18.0.0
* `@shopify/hydrogen` >= 2023.10.0 (Hydrogen only)
* `next` >= 13.0.0 (Next.js only)

### Storefront Access Token

The Storefront Access Token allows the SDK to tag cart attributes with A/B test data so that orders are attributed to the correct variant. Without it, your experiments will still run (visitors will see variants), but you won't be able to measure conversion lift per variant in your dashboard.

#### How to find your token

1. In your Shopify Admin, go to **Settings → Apps and sales channels → Develop apps**.
2. If you don't have a custom app yet, click **Create an app** and give it a name.
3. Under **Configuration**, make sure the app has the **Storefront API** access scope enabled with at least `unauthenticated_read_product_listings` and `unauthenticated_write_checkouts` permissions.
4. Go to the **API credentials** tab and copy the **Storefront API access token**.

This token is safe to use client-side. It's a public Shopify token with limited, read-only permissions — it cannot access admin data, customer information, or anything sensitive.

#### Where to store it

We recommend using environment variables rather than hardcoding the token:

```env
# .env
PUBLIC_STOREFRONT_API_TOKEN=your-storefront-access-token
```

How you reference this variable depends on your framework:

* **Hydrogen:** `context.env.PUBLIC_STOREFRONT_API_TOKEN`
* **Next.js:** `process.env.NEXT_PUBLIC_STOREFRONT_TOKEN`
* **Remix:** Access via your loader context

### Anti-Flicker

Set `preventFlickering={true}` on your `ElevateProvider` to prevent visitors from briefly seeing the wrong variant before the test configuration loads. This is especially important for above-the-fold content like hero banners, headlines, and pricing.

When enabled, the SDK briefly hides the page content (up to 3 seconds by default) until the test configuration is loaded and the visitor is assigned a variant. If the configuration fails to load within the timeout, the page renders normally with the control experience.

You can customize the timeout with the `flickerTimeout` prop:

```tsx
<ElevateProvider
  storeId="your-store.myshopify.com"
  storefrontAccessToken="your-token"
  preventFlickering={true}
  flickerTimeout={2000} // 2 seconds instead of the default 3
>
```

### Creating an Experiment

Experiments are created and configured on the Elevate dashboard. The SDK doesn't run experiments on its own — it reads the experiment configuration from Elevate, which handles visitor assignment, traffic allocation, and result tracking.

Elevate supports three experiment types that work with headless storefronts:

* **Split URL Experiment** — Redirects visitors between different URLs (e.g., `/products/shirt` vs `/products/shirt-v2`).
* **Custom Code Experiment** — Runs custom JavaScript on the page.
* **Content Editor Experiment** — Uses the Elevate visual editor to modify on-page content.

All three experiment types work out of the box once you've set up the provider. You create the experiment on Elevate, configure your variants there, and the SDK handles the rest. No code changes are needed in your storefront for these experiments.

### Using the useExperiment Hook (Optional)

The `useExperiment` hook is **completely optional**. You only need it if you want to conditionally render content directly in your codebase rather than configuring the experiment entirely through Elevate.

For example, if you want to test two different hero banner components that live in your code, you could create an empty custom code experiment on Elevate (no custom code needed — just set up the variations), then use the hook to render different content based on the assigned variant.

#### Finding your experiment ID

After creating an experiment, you can find its ID in the URL on your Elevate dashboard:

```
https://elevateab.app/<test-id>
```

This test ID is what you pass to the `useExperiment` hook.

#### Basic usage

```tsx
import { useExperiment } from "@elevateab/sdk";

function HeroBanner() {
  const { isControl, isA, isB, isLoading } = useExperiment("abc123");

  if (isLoading) return <HeroBannerSkeleton />;

  if (isControl) return <h1>Welcome to Our Store</h1>;
  if (isA) return <h1>Shop Our Spring Collection</h1>;
  if (isB) return <h1>Free Shipping on Orders Over $50</h1>;

  return <h1>Welcome to Our Store</h1>;
}
```

#### Available variant flags

The hook supports up to five variants:

| Flag        | Description                         |
| ----------- | ----------------------------------- |
| `isControl` | Visitor is in the control group     |
| `isA`       | Visitor is in Variant A             |
| `isB`       | Visitor is in Variant B             |
| `isC`       | Visitor is in Variant C             |
| `isD`       | Visitor is in Variant D             |
| `isLoading` | Test configuration is still loading |

#### Handling the loading state

While the SDK fetches the test configuration, `isLoading` will be `true` and all variant flags will be `false`. You have a few options for handling this:

**Show a skeleton/placeholder** — Best for above-the-fold content where layout shift would be noticeable:

```tsx
if (isLoading) return <Skeleton />;
```

**Show the control as default** — Works well for minor content changes where a brief flash is acceptable:

```tsx
if (isA) return <VariantA />;
if (isB) return <VariantB />;
return <Control />; // Shown during loading and for control group
```

**Use `preventFlickering`** — If you've enabled `preventFlickering` on the provider, the page is hidden until loading completes, so `isLoading` will effectively never be `true` when your component renders.

#### Accessing the full variant object

For advanced use cases, you can access the full variant object:

```tsx
const { variant } = useExperiment("abc123");

console.log(variant?.id);       // variant ID
console.log(variant?.name);     // variant name
console.log(variant?.isControl); // boolean
```

### Next Steps

Now that you've installed the SDK and understand the basics, follow the setup guide for your framework:

* [Shopify Hydrogen](https://docs.elevateab.com/elevate-helpcenter/headless-integration/shopify-hydrogen) — Automatic event tracking via Hydrogen's analytics system
* [Next.js & Remix](https://docs.elevateab.com/elevate-helpcenter/headless-integration/next.js-and-remix) — Manual event tracking with helper functions

For a full list of props, hooks, and tracking functions, see the SDK Reference.
