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

# React helpers

> @joinbankroll/sdk/react — host status that doesn't flash the wrong screen, a token-carrying fetch, and a development overlay.

`@joinbankroll/sdk/react` is the client-side glue that behaves identically in
every app: reading host status without flashing the wrong screen through
hydration, a `fetch` that carries the session token, and a development overlay.
Your app's own product surface stays in your app.

`react` is an optional peer (`>= 18`), installed only if you use this entry.

## Host status

```tsx theme={null}
import { useBankrollStatus, useBankrollChecked } from "@joinbankroll/sdk/react";

function Gate({ children }: { children: React.ReactNode }) {
  const checked = useBankrollChecked();
  const status = useBankrollStatus();

  if (!checked) return <Loading />;
  if (status === "unavailable") return <GetTheApp />;
  if (status === "update_required") return <UpdateTheApp />;
  return children;
}
```

`useBankrollStatus()` is [`bankroll.status()`](/build/quickstart#step-1--install-the-sdk-and-detect-the-host)
as a hook. The host is injected before your page loads and never changes
afterwards, so there is nothing to subscribe to — the work these do is agreeing
across the hydration boundary.

`useBankrollChecked()` is why the pair exists. It is `false` during the server
render and the first client paint, and `true` after. **Render a loading state on
it rather than deciding**, or a phone already inside Bankroll sees "get the
Bankroll app" until hydration corrects it. Server and client deliberately agree
on `'unavailable'` for the same reason: the wrong screen briefly is worse than
no screen briefly.

## Fetch with the session token

```ts theme={null}
import { bankrollFetch } from "@joinbankroll/sdk/react";

await bankrollFetch("/api/orders", { method: "POST", body });
```

[`withBankrollToken(fetch)`](/build/session#send-it-to-your-server), already
built and bound. Binding matters — `fetch` throws when called detached from the
window — and on the server it resolves to the bare global, so importing this
module never crashes a render that doesn't use it. In a plain browser the
request goes out bare and your server answers 401.

## Sending a user through verification

```ts theme={null}
import { verifyIdentity } from "@joinbankroll/sdk/react";

if (!(await verifyIdentity())) return; // declined — leave them where they are
```

`session({ identity: true })` reduced to the question a UI actually asks:
`true` once the user is verified, `false` if they declined or the host refused.
Anything that is not a host rejection propagates. Use it for an explicit "verify
to continue" button; for gating a paid action, check
[`session.user.identity`](/build/session#gating-eligibility) on your server,
which is the only place the answer is trustworthy.

## Development overlay

```tsx theme={null}
import { DevTools } from "@joinbankroll/sdk/react";

{process.env.NODE_ENV === "development" && (
  <DevTools
    rows={[
      { label: "Origin", value: origin, ok: true },
      { label: "Treasury", value: treasury, ok: Boolean(treasury), copy: true },
      { label: "RPC", value: rpcUrl, ok: !usingPublicRpc },
    ]}
  />
)}
```

A floating panel reporting how the app is configured — the manifest's origin,
the treasury address, the RPC endpoint, whatever you pass. Rows marked
`ok: false` render in amber, and `copy: true` truncates the display while
putting the **full** value on the clipboard, since a shortened address you can't
copy is useless.

<Warning>
  Render it only when you mean to. It carries addresses and endpoints, so gate it
  on your own development check — the component does not gate itself.
</Warning>

| Field     | Type      | Description                                                       |
| --------- | --------- | ----------------------------------------------------------------- |
| `label`   | `string`  | Row label, and the key.                                           |
| `value`   | `string`  | The full value — what gets copied.                                |
| `ok`      | `boolean` | `false` renders the value as a warning.                           |
| `display` | `string`  | Shown instead of `value` when the real thing is too long to read. |
| `copy`    | `boolean` | Offer a copy button; `value` is what lands on the clipboard.      |

In a Next.js app the overlay also hides Next's own dev badge, which otherwise
stacks with it in a phone-sized viewport, and offers it back behind a toggle.
