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

# Target users

> Identify a user, pass traits, and evaluate flags with sticky bucketing.

## Overview

Fieldkit wants `new-checkout` on for Pro subscribers first, then a 10% slice of everyone else. Targeting rules live in the dashboard; the SDK only sends **who is asking**.

This guide is the story of `usr_8f2k19` (Jordan, plan `pro`) hitting checkout.

## Identify

```ts theme={null}
shipd.identify({
  userId: "usr_8f2k19",
  name: "Jordan Chen",
  traits: { plan: "pro", seat: 12, beta: true },
});

shipd.isEnabled("new-checkout");
// uses usr_8f2k19 + traits until reset()
```

```ts theme={null}
// logout
shipd.reset();
```

`identify` merges into later checks. Pass a per-call context to override:

```ts theme={null}
shipd.isEnabled("new-checkout", {
  userId: "usr_8f2k19",
  attributes: { plan: "pro" },
});
```

Browser clients keep a stable `anonymousId` (default key `shipdit:anonymousId`) so pre-login and post-login traffic correlate. The same `userId` from server and client maps to one evaluated-entity row per environment.

After `identify()`, the SDK fetches last-seen traits from `GET /sdk/v1/identity` and merges them **under** this session's traits (request wins). Disable with `remoteTraits: false`.

This is the same shape the dashboard uses:

```ts apps/web/src/lib/shipd.ts theme={null}
client.identify({
  userId: input.userId,
  name: input.name,
  traits: {
    organizationId: input.organizationId,
    role: input.role,
    plan: input.plan,
  },
});
```

## What the evaluator sees

```ts theme={null}
type EvaluationContext = {
  userId?: string;
  attributes?: Record<string, string | number | boolean | null>;
  segmentIds?: string[];
};
```

Dashboard rules match on attributes (`plan eq pro`), percentage rollouts, and audiences (segments). Evaluation stays local — no Postgres on the check.

## Percentage rollouts

A 10% rollout hashes `flagKey + userId` (unless the rule buckets on another attribute). The assignment is sticky with no stored state.

```ts theme={null}
// Same user, same flag → same bucket forever
shipd.isEnabled("new-checkout", { userId: "usr_8f2k19" });
```

No `userId` (and no bucket attribute) → the percentage condition does not match → fallthrough (the flag default).

## Audiences

Project-scoped segments compile into the snapshot. Rules reference them (`kind: "segment"`). Membership is **not** a server lookup; the SDK evaluates the segment's conditions from context attributes.

## Events

Identify (and evaluations in production) batch to `POST /sdk/v1/events`. `identify` upserts `evaluated_entities` asynchronously. Turn the pipeline off with `events: false`.

```ts theme={null}
const shipd = createClient<FlagDefinitions>({
  sdkKey: process.env.SHIPD_SDK_KEY!,
  endpoint: "https://edge.useshipd.com",
  events: false,
});
```

## Next

* How-to: [Identify users](/how-to/identify-users)
* [Local evaluation](/concepts/local-evaluation)
* [SDK reference](/reference/sdk)
