# @flagbearer/web

The browser SDK for Flagbearer. It works with any framework. For React, read
this page first, then [React](/sdks/react).

## Install

```sh
npm install @flagbearer/web
```

## Keys

Use a client key, which starts with `fbc_`. Client keys are public and safe to
include in browser code. Server keys, which start with `fbs_`, are secret and
belong only on your server, with [`@flagbearer/node`](/sdks/node).

## Set up one client

Create one client for the whole app, and keep it for the life of the page:

```ts
import { init } from "@flagbearer/web";

export const flags = init({
  clientKey: "fbc_...",
  user: { key: "123", email: "jane@example.com" },
});
```

## Users

Pass the current user to `init`, or leave it out for anonymous visitors. When
someone signs in, signs out, or switches account, call `identify`:

```ts
await flags.identify({ key: user.id, email: user.email });
```

The email is optional. Include it to turn flags on for testers by email.

For signed-out visitors, the SDK keeps a random ID in local storage under
`flagbearer:anon`. Cover it in your cookie or storage consent where your users'
laws require it.

## Defaults

Every check passes a default:

```ts
if (flags.isEnabled("advanced-search", false)) {
  showAdvancedSearch();
}
```

The default is used until the current user's flags have loaded, and when the
flag doesn't exist.

### Waiting for flags without a flash

`getStatus()` returns `loading` until the current user's flags have loaded,
then `ready`, or `failed` if they couldn't load. Hold back UI that mustn't flash
between the default and the real value:

```ts
if (flags.getStatus() === "loading") return; // not known yet
```

To wait for flags explicitly, `await flags.sync()`.

## Typed flag keys

In TypeScript, the [CLI](/sdks/cli) can write a file listing the application's
flags. Then a misspelled key is a type error, and editors autocomplete keys:

```sh
npx @flagbearer/cli generate types --app <app> --out src/flagbearer.d.ts
```

```ts
flags.isEnabled("new-checkout", false); // ok
flags.isEnabled("new-chekout", false); // type error: not a flag in this app
```

Commit the file, and run the command in its first line again after adding or
removing a flag. Without the file, any string is a flag key.

## Error reports

`allFlags()` returns every flag's current value, so error reports show exactly
which flags were on. It doesn't count as checking them.

```ts
Sentry.setContext("flags", flags.allFlags());
// { "new-checkout": true, "dark-mode": false }
```

## Subscriptions

`subscribe(listener)` calls the listener when the current user's flags or status
change. Read `isEnabled()` inside it, and once yourself after subscribing:

```ts
function render() {
  console.log(flags.isEnabled("advanced-search", false));
}

const unsubscribe = flags.subscribe(render);
render();
```

The returned function removes that subscription. Call `flags.close()` when the
client itself is no longer needed.
