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

# SDK

> shipdit runtime: createClient, evaluation, identify, React, versions.

## Overview

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

| Import                 | Runtime                                        |
| ---------------------- | ---------------------------------------------- |
| `shipdit`              | Server / Node / Worker                         |
| `shipdit/client`       | Browser (`localStorage` cache + `anonymousId`) |
| `shipdit/client/react` | `createShipdReact`                             |
| `shipdit/config`       | `defineFlags`                                  |

Evaluation never throws. Missing snapshot → `defaults`.

## createClient

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

const shipd = createClient<FlagDefinitions>({
  sdkKey: process.env.SHIPD_SDK_KEY!,
  endpoint: "https://edge.useshipd.com",
  streamEndpoint: "https://ws.useshipd.com",
  defaults: { "new-checkout": false },
});

await shipd.ready();
```

### Options

<ParamField path="sdkKey" type="string" required>
  Environment-scoped SDK key (`shipd_sdk_server_…` or `shipd_sdk_client_…`).
</ParamField>

<ParamField path="endpoint" type="string" required>
  Data-plane origin, e.g. `https://edge.useshipd.com`.
</ParamField>

<ParamField path="defaults" type="PartialDefaults">
  Per-key fallbacks used before a snapshot exists and for unknown keys.
</ParamField>

<ParamField path="context" type="EvaluationContext">
  Default `{ userId, attributes, segmentIds }`.
</ParamField>

<ParamField path="refreshIntervalMs" type="number" default="30000">
  Poll interval. `0` = fetch once.
</ParamField>

<ParamField path="readyTimeoutMs" type="number" default="5000">
  How long `ready()` waits. Resolves on success, bootstrap, or timeout — never rejects for network errors.
</ParamField>

<ParamField path="fetchTimeoutMs" type="number" default="10000">
  Per-request HTTP timeout. `0` disables.
</ParamField>

<ParamField path="bootstrap" type="FlagSnapshot">
  In-memory snapshot until the first successful fetch.
</ParamField>

<ParamField path="onError" type="(error: unknown) => void">
  Fetch / schema / stream failures.
</ParamField>

<ParamField path="events" type="boolean" default="true">
  Batch to `POST /sdk/v1/events`.
</ParamField>

<ParamField path="eventsFlushAt" type="number" default="50">
  Flush when the buffer reaches this size.
</ParamField>

<ParamField path="eventsFlushIntervalMs" type="number" default="5000">
  Flush interval. `0` disables timer flush.
</ParamField>

<ParamField path="cache" type="SnapshotCache">
  Durable cache. Browser default is `localStorage`.
</ParamField>

<ParamField path="streamEndpoint" type="string">
  WebSocket gateway origin (`https://ws.useshipd.com`). Omit for polling only.
</ParamField>

<ParamField path="remoteTraits" type="boolean" default="true">
  After `identify()`, GET `/sdk/v1/identity` and merge under session traits.
</ParamField>

<ParamField path="anonymousId" type="string">
  Stable anonymous id. Browser generates one if omitted.
</ParamField>

Browser-only (`shipdit/client`): `persist` (default `true`), `storageKey`, `anonymousStorageKey` (default `shipdit:anonymousId`).

## Client methods

```ts theme={null}
await shipd.ready();
shipd.isEnabled("new-checkout", context?);
shipd.getVariant("search-variant", context?);
shipd.getNumber("max-retries", context?);
shipd.getJson("checkout-payload", context?);
shipd.getVersion();      // number | null
shipd.getRevision();     // monotonic, for useSyncExternalStore
shipd.subscribe(() => { /* snapshot or identity changed */ });
shipd.identify({ userId, name?, traits?, anonymousId? });
shipd.reset();
shipd.getAnonymousId();
shipd.close();
```

`EvaluationContext`: `{ userId?, attributes?, segmentIds? }`.

## Polling + stream

1. `GET /sdk/v1/snapshot` (`If-None-Match`)
2. Optional `ws(s)://…/sdk/v1/stream` → `subscribe` with `environmentId` + `lastKnownVersion`
3. On `snapshot.updated` / `snapshot.resync`, refetch with minVersion retries
4. Polling stays on

Reconnect: `1s → 2s → 4s → … → 60s` + jitter, reset after a successful connection. Ignore snapshot bodies with `version < local`. Gaps fetch **current** only.

## React

```ts theme={null}
import { createShipdReact } from "shipdit/client/react";

export const { ShipdProvider, useFlag, useVariant, useNumber, useJson, useReady, useShipdClient } =
  createShipdReact<FlagDefinitions>();
```

Call once in a client-only module. Hooks re-render on snapshot apply and `identify` / `reset`.

## Versions

```ts theme={null}
import { VERSIONS } from "shipdit";
// { snapshotSchema, streamProtocol, sdkPackage, controlPlaneApi }
```

| Surface            | Constant                      | Current           |
| ------------------ | ----------------------------- | ----------------- |
| Snapshot schema    | `SNAPSHOT_SCHEMA_VERSION`     | `1`               |
| WebSocket protocol | `SDK_STREAM_PROTOCOL_VERSION` | `1`               |
| npm package        | `SDK_PACKAGE_VERSION`         | `shipdit` version |
| Control-plane API  | `CONTROL_PLANE_API_VERSION`   | `1` (`/api/v1`)   |

Guides: [Evaluate](/guides/evaluate-flags) · [Target](/guides/target-users) · [React](/guides/react).
