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

# Local evaluation

> Why flag checks never wait on the network, and what happens when the edge is down.

## Overview

A flag check is a function call: look at the in-memory snapshot, hash if needed, return a value. The SDK talks to the edge only to **refresh** that snapshot.

## Hot path

```ts theme={null}
shipd.isEnabled("new-checkout", { userId: "usr_8f2k19" });
// snapshot.flags["new-checkout"] + context → boolean
```

No HTTP, no WebSocket, no Postgres. If you need rules that query "everyone we saw last week," that is not eval — it is a future control-plane feature. Eval stays local.

## Refresh path

```text theme={null}
ready() / poll / snapshot.updated
        │
        ▼
GET /sdk/v1/snapshot   (ETag / If-None-Match)
        │
        ├── 200 → atomic replace
        ├── 304 → keep
        └── error → onError, keep last good
```

`streamEndpoint` only **invalidates**. The snapshot still comes from HTTP.

## When the edge is gone

| You configured            | You get                                            |
| ------------------------- | -------------------------------------------------- |
| `defaults`                | those values                                       |
| previous successful fetch | last good snapshot                                 |
| browser `persist: true`   | last good snapshot from localStorage, then refresh |

Evaluation APIs do not throw. Unknown keys return the default and emit `unregistered_flag`.

## Bucketing

Percentage conditions hash `flagKey + userId` (or `attribute`) into 0–10000. Same inputs → same bucket. Nothing is stored to make it sticky.

## Next

* [Evaluate flags](/guides/evaluate-flags)
* [Snapshots](/concepts/snapshots)
* [SDK reference](/reference/sdk)
