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

> ## Agent Instructions
> Official FireWeave SDK documentation.
> Product noun is control point. OpenFeature and the wire protocol use flagKey — do not invent controlPointKey.
> Do not invent APIs, packages, env vars, or endpoints. Guardrails are a typed stub (UnsupportedCapability). OpenFeature Tracking (spec section 6) is not implemented.
> registerTarget and identify exist on Node, Python, and Web only. Go and Java have no target-registration API on master.
> sendExposure defaults to false. Java close() does not flush exposures.

# Browser

> Install and use @fireweaveai/web-sdk for synchronous control-point reads, identify(), STALE lifecycle, and unload flush. Not a Node SDK.

`@fireweaveai/web-sdk` is the FireWeave **browser** binding. It evaluates **control points** synchronously from a prefetched cache, registers targets via `identify()`, and records **exposures** and **signals**. OpenFeature and the wire protocol still use `flagKey`.

This is a different surface from [`@fireweaveai/sdk`](/sdks/node). It is not a Node, Bun, or Deno server target.

<Note>
  `@fireweaveai/web-sdk@2.1.0` is on npm (verified 2026-08-17; tarball `gitHead` matches `master` `dfeb478`). There is no web-specific README install command in the SDK tree. Pin `@2.1.0`, or build from checkout for an unreleased tree.
</Note>

<Warning>
  Today's constructor key is still a `project-api-key_…` / attest family. Spec/ADR-0009: a scoped `fw_public_…` key with `flags:evaluate` + `events:write` is **required before production browser use**. Whether fw-server already issues `fw_public_…` is **NEEDS VERIFICATION** (platform work). Do not bake `attest:write` keys into a frontend bundle as if they were public.
</Warning>

## Supported runtime

|              | Value                           |
| ------------ | ------------------------------- |
| Package      | `@fireweaveai/web-sdk` `2.1.0`  |
| Target       | Browser                         |
| Peer         | `@openfeature/web-sdk` `^1.9.0` |
| Runtime deps | **none**                        |
| CI           | Bun + happy-dom only            |

It ships no server entry point, reads **no environment**, and imports no runtime built-ins. Node and Deno are **not** target runtimes.

## Install

<Tabs>
  <Tab title="npm 2.1.0">
    Verified 2026-08-17 on npm (`@fireweaveai/web-sdk@2.1.0`).

    ```bash theme={null}
    npm install @fireweaveai/web-sdk@2.1.0 @openfeature/web-sdk
    ```
  </Tab>

  <Tab title="From checkout">
    Same pattern as the Node package (no web-specific README command exists):

    ```bash theme={null}
    git clone https://github.com/FireWeave-HQ/fireweave-sdk && cd fireweave-sdk
    (cd sdks/web && bun install && bun run build)
    ```

    Workspace `package.json` scripts use Bun (`bun run build` → `packages/sdk`). Then depend on `sdks/web/packages/sdk` by path.
  </Tab>
</Tabs>

## Initialize

Reads are **synchronous**. `initialize()` and `setContext()` prefetch asynchronously; `evaluate` / OpenFeature resolvers read the cache.

```ts theme={null}
import { OpenFeature } from '@openfeature/web-sdk';
import {
  FireweaveRemoteWebAdapter,
  FireweaveWebProvider,
  FireweaveWebRuntime,
} from '@fireweaveai/web-sdk';

const runtime = new FireweaveWebRuntime(
  new FireweaveRemoteWebAdapter({ apiUrl, apiKey }),
  { globalContext: { targetingKey: 'anonymous' } }
);
await OpenFeature.setProviderAndWait(new FireweaveWebProvider(runtime));

// SYNCHRONOUS — no await, safe inside render.
const on = OpenFeature.getClient().getBooleanValue('new-checkout', false);
```

`FireweaveWebProvider` metadata default name: `fireweave-web`. `runsOn = 'client'`. `resolve*Evaluation` returns `ResolutionDetails`, **never a Promise**.

## Lifecycle and STALE

States include **`STALE`**: prefetch raced `DEFAULT_FLAGS_READY_TIMEOUT_MS` (`5000`) and lost. Reads are defaults with reason `STALE`. Collapsing STALE into READY is rejected in the runtime — a timed-out boot must stay distinguishable from a successful one where every control point is off.

The provider emits OpenFeature `Stale` and, on context change, `ConfigurationChanged` with only keys whose decisions moved.

## Configuration and authentication

`FireweaveRemoteWebAdapterOptions`: **`apiUrl` and `apiKey` are required constructor fields.** The package **reads no environment**.

```ts theme={null}
const adapter = new FireweaveRemoteWebAdapter({
  apiUrl: 'https://app-server.fireweave.ai', // allowlisted name; live customer URL NEEDS VERIFICATION
  apiKey: 'project-api-key_…',
});
```

Rejects `phc_` / `phs_` / `phx_` key shapes (`assertNotSecretKey`) with `Configuration`. Default allowlist matches Node: `app-server.fireweave.ai`, `staging-app-server.fireweave.ai`, loopback. `https` off-loopback; `http` on loopback only.

Auth: `Authorization: Bearer <key>`. Paths: `/v1/flags/evaluate`, `/v1/capture`, `/v1/targets/register`. `localEvaluation` is structurally **false**.

See [Configuration and auth](/production/configuration).

## Targets: `identify` (not `registerTarget` on the client)

Web exposes **`FireweaveWebClient.identify`**. It calls `runtime.registerTarget`, then `setContext({ targetingKey })` so the next prefetch buckets on that id.

```ts theme={null}
import { FireweaveWebClient } from '@fireweaveai/web-sdk';

const client = new FireweaveWebClient(runtime);
const result = await client.identify('user_42', {
  kind: 'user',
  properties: { plan: 'pro' },
});
```

This is **not** OpenFeature `identify` and not analytics `identify`. Options match `RegisterTargetOptions`: `kind?: 'user' | 'device'`, `properties?`, `environment?`.

See [Targeting and targets](/concepts/targeting).

## Control points (synchronous)

`ExpectedFlagType`: `'boolean' | 'string' | 'number' | 'object'` — same number model as Node (IEEE-754 double).

```ts theme={null}
const on = client.controlPoints.getBooleanValue('new-checkout', false, { targetingKey: 'user_42' });
const theme = client.controlPoints.getStringValue('copy', 'classic', { targetingKey: 'user_42' });
const decision = client.controlPoints.evaluate('new-checkout', 'boolean', false, { targetingKey: 'user_42' });
```

Helpers: `getBooleanValue`, `getStringValue`, `getNumberValue`, `getObjectValue`. All **sync**. Evaluation **never throws**.

See [Control points](/concepts/control-points).

## Releases, exposures, signals, capabilities

Same extension set as the server client: `releases`, `exposures`, `signals`, `capabilities`, plus the `guardrails` stub.

Exposures flush on `visibilitychange → hidden` and `pagehide` via `keepalive` / `sendBeacon` (`autoFlushOnUnload` defaults **on**; pass `{ autoFlushOnUnload: false }` in tests). Dedup is per `(flagKey, targetingKey, variant)` in web tests.

```ts theme={null}
const client = new FireweaveWebClient(runtime, { autoFlushOnUnload: false });
client.exposures.record({
  flagKey: 'new-checkout',
  targetingKey: 'user_42',
  value: true,
  variant: 'on',
});
await client.shutdown(); // flushes, then shuts down
```

`sendExposure` on evaluate defaults to **false** (same ruling as server SDKs).

See [Releases](/concepts/releases), [Exposures](/concepts/exposures), [Signals](/concepts/signals), [Capabilities](/concepts/capabilities).

## Adapters

| Adapter                     | Use                               |
| --------------------------- | --------------------------------- |
| `FireweaveRemoteWebAdapter` | Production. Only network adapter. |
| `InMemoryWebAdapter`        | Tests / fixtures.                 |
| `FireweaveLocalWebAdapter`  | Dev `devFlags` boolean map.       |

There is **no** PostHog / vendor adapter and **no** in-process local evaluation.

```ts theme={null}
import { FireweaveLocalWebAdapter, FireweaveWebRuntime } from '@fireweaveai/web-sdk';

const runtime = new FireweaveWebRuntime(
  new FireweaveLocalWebAdapter({ devFlags: { 'new-checkout': true } }),
);
```

See [Adapters](/concepts/adapters).

## OpenFeature

`FireweaveWebProvider` + `@openfeature/web-sdk` `^1.9.0`. Resolvers are **sync**. Options: `{ name? }` (default `fireweave-web`). Tracking is **not implemented**.

See [OpenFeature](/openfeature).

## Errors

Same 15-kind `FireweaveError` taxonomy as the Node SDK. Evaluation never throws.

See [Errors](/production/errors).

## Testing

`InMemoryWebAdapter` + optional `{ autoFlushOnUnload: false }`. CI uses Bun and happy-dom. happy-dom cannot prove bfcache restore, beacon size limits, or that an unload request leaves the socket.

See [Testing](/testing).

## Shutdown

```ts theme={null}
await client.shutdown(); // flushes, then runtime.shutdown()
```

A tab has no process shutdown hook; unload flush is the substitute.

See [Initialize, ready, shutdown](/production/lifecycle).

## Not in this SDK

* Environment-variable configuration
* PostHog / vendor adapter
* In-process local evaluation (`localEvaluation` cannot become true)
* Server entry point / Node-as-target
* A client method named `registerTarget` (use `identify`)
* Working guardrails
* OpenFeature Tracking

## Next

<Card title="Quickstart" href="/quickstart">
  Offline evaluate in every language.
</Card>

<Card title="Node server SDK" href="/sdks/node">
  Async server counterpart (`@fireweaveai/sdk`).
</Card>

<Card title="Compatibility" href="/sdks/compatibility">
  Type split, adapters, and conformance.
</Card>
