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

# React

> One provider and one hook, with no hidden initialisation.

`@trevosdk/browser/react` wraps the browser SDK in a provider and a hook. `react` is an
optional peer dependency — install the SDK as normal:

```bash theme={null}
npm install @trevosdk/browser
```

## Provider

Wrap your app once, as high as you can:

```tsx theme={null}
import { TrevoProvider } from '@trevosdk/browser/react';

<TrevoProvider apiKey={process.env.NEXT_PUBLIC_TREVO_API_KEY}>
  {children}
</TrevoProvider>
```

The provider initialises the SDK synchronously on first render. `apiKey` should be stable
for the lifetime of the app.

Passing `apiKey={undefined}` disables the SDK entirely — a clean way to keep it off outside
production without branching your component tree.

## Hook

```tsx theme={null}
import { useExperiment } from '@trevosdk/browser/react';

function CheckoutButton() {
  const variant = useExperiment('checkout-cta');

  return variant === 'treatment' ? <NewCta /> : <CurrentCta />;
}
```

Exposure is recorded on the variant that actually renders.

### Typed variants

Pass an `Experiment` from `defineExperiment()` and the return type narrows to a union, so
an unhandled arm is a compile error:

```tsx theme={null}
import { defineExperiment, assertNever } from '@trevosdk/browser';
import { useExperiment } from '@trevosdk/browser/react';

const emailTiming = defineExperiment('email-capture-timing', [
  'control',
  'before-checkout',
  'after-payment',
]);

function Checkout() {
  const variant = useExperiment(emailTiming);

  switch (variant) {
    case 'control':         return <NoEmailCapture />;
    case 'before-checkout': return <EmailBeforeCheckout />;
    case 'after-payment':   return <EmailAfterPayment />;
    default:                return assertNever(variant);
  }
}
```

If the variants you declare here drift from the ones configured in Trevo, the SDK logs a
warning — which surfaces the mismatch instead of silently returning control.

## What renders on the first paint

This is the part worth understanding before you ship an experiment above the fold.

* **Returning visitors** resolve from a warm local-storage cache and render the correct
  variant immediately.
* **First-time visitors** have no cache. They render `control` for one paint, then swap to
  their assigned variant when config arrives.

Nothing is ever hidden, and exposure fires on the variant that actually rendered — so the
data stays correct either way. But a visible swap on a first visit can look like a glitch.

Two ways to avoid it:

1. **Resolve on the server.** See [Next.js](/install/nextjs) — the first paint is already
   correct for everyone, with nothing hidden.
2. **Use the anti-flicker snippet.** See [Browser](/install/browser#anti-flicker). Hides the
   page briefly rather than showing the wrong thing.

If neither applies, prefer experiments below the fold or behind an interaction, where a
first-paint swap is not visible.

## Accessing the client directly

```tsx theme={null}
import { useTrevo } from '@trevosdk/browser/react';

const trevo = useTrevo();      // the SDK instance, or null before init
trevo?.track('purchase_completed', { value: 49.99 });
```

Use this for `track()` and `identify()`. For reading variants, prefer `useExperiment()` —
it handles re-rendering when config arrives.

## Identifying users

Call `identify()` as soon as you know who the user is, typically in an effect after auth
resolves:

```tsx theme={null}
const trevo = useTrevo();

useEffect(() => {
  if (user) trevo?.identify(user.id);
}, [user, trevo]);
```

Because identity determines assignment, calling `identify()` after an experiment has
rendered can move the user to a different variant mid-session. Identify before rendering
anything under test.
