> ## 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.

# Browser

> Install the JavaScript SDK in any web app, with or without a bundler.

`@trevosdk/browser` assigns variants and records events in the browser. It never touches
the DOM — your own code branches on the variant it returns.

Under 10kb gzipped, no dependencies.

## Install

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

### Without a bundler

The CDN build exposes a global called `Trevo`. **Pin the exact version in production** —
the floating channels change under you with no deploy on your side.

```html theme={null}
<script src="https://cdn.trevosdk.com/browser/v0.2.4/trevo.min.js"></script>
<script>
  Trevo.init({ apiKey: 'tsk_live_…' });
</script>
```

| URL                             | Updates                      | Cache     |
| ------------------------------- | ---------------------------- | --------- |
| `…/browser/v0.2.4/trevo.min.js` | never                        | 1 year    |
| `…/browser/v0/trevo.min.js`     | patches and minors within v0 | 5 minutes |
| `…/browser/latest/trevo.min.js` | every release                | 5 minutes |

Use `v0` or `latest` for prototyping only.

## Initialise

```ts theme={null}
import trevo from '@trevosdk/browser';

trevo.init({ apiKey: process.env.NEXT_PUBLIC_TREVO_API_KEY });
```

The key is publishable (`tsk_live_…`) and belongs in your client bundle. Server keys
(`tsk_secret_…`) are rejected from browsers.

`init()` is re-entrant — calling it again reconfigures rather than duplicating.

### Options

| Option         | Default | Notes                                                                                                   |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| `apiKey`       | —       | Required                                                                                                |
| `bootstrap`    | —       | Pre-resolved `{ experimentKey: variantName }` for a correct first paint. See [Next.js](/install/nextjs) |
| `manualReveal` | `false` | With the anti-flicker snippet, wait for your `reveal()` instead of revealing automatically              |

## Identify the user

```ts theme={null}
trevo.identify(currentUser.id);
```

Before this, users are bucketed on an anonymous id stored in local storage. After it, they
are bucketed on your user id — which means **`identify()` can change a user's variant**.
Call it as early as you can, and before rendering anything under test.

Anonymous ids are per browser, so the same person on a phone and a laptop is two
participants until they sign in.

On logout:

```ts theme={null}
trevo.reset();
```

## Read a variant

```ts theme={null}
const variant = trevo.getVariant('checkout-cta');
```

Synchronous, no network call, and deterministic — the same identity and key always produce
the same variant. Unknown keys return `'control'`, so this is safe to ship before the
experiment exists.

Each call records an **exposure**. To read without recording one:

```ts theme={null}
trevo.getVariant('checkout-cta', { trackExposure: false });
```

### Typed variants

`defineExperiment()` returns a typed union and turns an unhandled variant into a compile
error — so a variant added in Trevo that your code does not handle fails the build instead
of silently falling through:

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

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

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

## Track conversions

```ts theme={null}
trevo.track('purchase_completed', { value: 49.99, plan: 'pro' });
```

Batched automatically — up to 50 events per request, flushed every couple of seconds and
on page unload. `trevo.flush()` forces a send if you need one.

Limits: event names up to 500 characters, properties up to 8KB serialised.

## Waiting for config

On a first visit the SDK has no cached config, so `getVariant()` returns `'control'` until
the first fetch lands. Returning visitors read from a warm cache and are correct
immediately.

```ts theme={null}
if (trevo.isReady()) {
  // safe to read synchronously during render
}

await trevo.ready();  // resolves when config loads, or the first fetch fails
```

Config is polled every 60 seconds and cached in local storage for 24 hours, so a slow
network delays the first visit only.

To avoid the flash of control on a first visit entirely, either resolve variants on the
server ([Next.js](/install/nextjs)) or use the anti-flicker snippet below.

## Anti-flicker

Hides the page until variants are resolved, with a safety timeout so a blocked or failed
SDK can never leave your page blank:

```ts theme={null}
import { ANTI_FLICKER_SNIPPET } from '@trevosdk/browser';
```

Inline it in a `<script>` in `<head>`, before anything renders. It reveals automatically
after 1 second by default:

```html theme={null}
<script>window.__trevoConfig = { timeout: 2000 };</script>
```

With `manualReveal: true`, call `trevo.reveal()` once you have committed the variant.

Server-side bootstrapping is better where you can do it — nothing is hidden and there is
no timeout to tune.

## Consent and opt-out

```ts theme={null}
trevo.optOut();   // stops everything, clears identity, drops queued events
trevo.reset();    // clears the user, keeps the anonymous id
```

`optOut()` is idempotent and safe to call before `init()`.

## API summary

| Method                        | Purpose                                             |
| ----------------------------- | --------------------------------------------------- |
| `init(options)`               | Start the SDK                                       |
| `identify(userId)`            | Set the authenticated user                          |
| `getVariant(key, options?)`   | Resolve a variant, recording an exposure by default |
| `trackExposure(key, variant)` | Record an exposure explicitly                       |
| `track(name, properties?)`    | Queue a conversion event                            |
| `flush()`                     | Send queued events now                              |
| `isReady()` / `ready()`       | Whether config has loaded                           |
| `reset()`                     | Clear the user (logout)                             |
| `optOut()`                    | Stop all activity (consent withdrawal)              |
| `reveal()`                    | Reveal the anti-flicker overlay                     |
| `destroy()`                   | Tear down entirely                                  |
