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

# Browser

> Evaluate flags in the browser with shipdit/client, a client SDK key, identify, and subscribe.

## Overview

In this guide you evaluate flags in a browser app with `shipdit/client`. It has the same evaluation API as the server client, plus a `localStorage` snapshot cache, a stable anonymous id, and automatic location traits. Using React? Read [React](/sdks/react) after this page.

## Install

```bash theme={null}
pnpm add shipdit
```

## Use a client SDK key

In the [dashboard](https://app.useshipd.com), go to **SDK keys**, click **Create SDK key**, and set **Key type** to `client`. Client keys (`shipd_sdk_client_…`) are safe to embed in browser bundles.

> [!WARNING]
>
> Never ship a server SDK key (`shipd_sdk_server_…`) to a browser. See [Keys](/concepts/keys).

## Create the client

```ts src/lib/shipd.ts theme={null}
import { createClient } from "shipdit/client";
import type { FlagDefinitions } from "../generated/flags";

export const shipd = createClient<FlagDefinitions>({
  sdkKey: import.meta.env.VITE_SHIPD_SDK_KEY,
  stream: true,
  defaults: {
    "new-checkout": false,
    "search-variant": "control",
  },
});
```

The browser client adds these behaviors to the [`createClient`](/reference/sdk#createclient) options:

| Behavior | Default | Turn off or change |
| - | - | - |
| Persist the last good snapshot in `localStorage` and load it on the next visit | On | `persist: false` or a custom `cache` |
| Generate a stable `anonymousId` under `shipdit:anonymousId` | On | `anonymousId`, `anonymousStorageKey` |
| Add `country`, `region`, `city`, and `timezone` to the evaluation context | On | `automaticTraits: false` |

Location traits come from edge geolocation and the browser's time zone. Traits you pass yourself win. See [Target users](/flags/targeting).

## Identify on login, reset on logout

```ts src/auth.ts theme={null}
import { shipd } from "./lib/shipd";

export function onLogin(user: { id: string; name: string; plan: string }) {
  shipd.identify({
    userId: user.id,
    name: user.name,
    traits: { plan: user.plan },
  });
}

export function onLogout() {
  shipd.reset(); // clears the identity and rotates the anonymousId
}
```

Later checks reuse that identity, so you can call `shipd.isEnabled("new-checkout")` with no arguments. See [Identify users](/flags/identify-users).

## Re-render on changes

Flag values change when a new snapshot arrives or when `identify()` or `reset()` runs. `subscribe()` calls your listener on each change and returns an unsubscribe function.

```ts src/main.ts theme={null}
import { shipd } from "./lib/shipd";

function render() {
  const checkout = document.querySelector("#checkout-link")!;
  checkout.setAttribute(
    "href",
    shipd.isEnabled("new-checkout") ? "/checkout/new" : "/checkout",
  );
}

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

## Avoid a flash of default content

The first render may use `defaults` while the snapshot loads. Pick one approach:

* **Wait for `ready()`** before rendering flag-dependent UI. It resolves when the snapshot or cached snapshot loads, or after `readyTimeoutMs` (5 seconds by default).
* **Rely on the persisted cache.** Returning visitors start from the snapshot saved in `localStorage`.
* **Pass `bootstrap`.** If your server already has a snapshot for the same environment, embed it in the page and pass it to `createClient`. The client serves it immediately and `ready()` resolves at once.

```ts theme={null}
await shipd.ready();
render();
```

```ts src/lib/shipd.ts theme={null}
import { createClient, type FlagSnapshot } from "shipdit/client";
import type { FlagDefinitions } from "../generated/flags";

const bootstrap = (window as { __SHIPD_SNAPSHOT__?: FlagSnapshot }).__SHIPD_SNAPSHOT__;

export const shipd = createClient<FlagDefinitions>({
  sdkKey: import.meta.env.VITE_SHIPD_SDK_KEY,
  bootstrap,
  defaults: { "new-checkout": false, "search-variant": "control" },
});
```

The snapshot format is documented in the [Edge API reference](/reference/edge-api).

## Next

* [React](/sdks/react)
* [Identify users](/flags/identify-users)
* [Local evaluation](/concepts/local-evaluation)
* [SDK reference](/reference/sdk)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.