---
title: Browser client
description: sluurp.js, the client every page can import, and what each part of it does.
section: Data
order: 2
---

# Browser client

<p class="lead">Every Sluurp server serves its client, already in each app's import map: <code>import { Sluurp } from "sluurp"</code>. Nothing to install. It wraps the <a href="/docs/api">REST API</a> and manages auth.</p>

```ts title="app.ts"
import { Sluurp } from "sluurp";

const sluurp = new Sluurp();
const todos = sluurp.collection("todos");

const { items } = await todos.list({ filter: "done = false", sort: "-created" });
const todo = await todos.create({ title: "Milk" });
await todos.update(todo.id, { done: true }, { reason: "bought" });
```

`new Sluurp()` talks to the page's own server. Pass an origin, `new Sluurp("https://school.example.com")`, for another, and `{ project }` for a non-default project.

## Collections

`sluurp.collection(name)` has:

| | |
|---|---|
| `list({ page, perPage, sort, filter, asOf })` | One page: `{ items, page, perPage, totalItems, totalPages }` |
| `listAll(options)` | All pages as one array (served from [sync](/docs/sync#every-list-kept-current) after the first call) |
| `getOne(id)`, `getFirst(filter)` | A single record |
| `create(data)`, `update(id, data)`, `delete(id)` | Writes. Each accepts `{ reason }`, stored with the change |
| `history(id)`, `version(id, seq)`, `restore(id, seq)` | Past versions, if history is on |
| `changes(since)` | All changes after a sequence number, in order |

## Files

| | |
|---|---|
| `upload(id, field, file)` | Upload a `File` or `Blob` to a field |
| `createWithFile(data, field, file)` | Create the record and upload in one step |
| `fileUrl(id, field, { w, h, fit, format })` | A URL for an `<img>`, resized |
| `srcset(id, field, [400, 800, 1200])` | A `srcset` at those widths |
| `fileObjectUrl(id, field)`, `fileText(id, field)` | Fetch a private file with auth |

## Signing in

On the auth collection, usually `users`:

```ts title="app.ts"
const users = sluurp.collection("users");
await users.authWithPassword(email, password);

sluurp.authStore.isValid;   // signed in?
sluurp.authStore.record;    // the user
sluurp.logout();
```

Also: `signUp`, `requestPasswordReset`, `requestSigninLink` (magic link), `verifyTwoFactor`, `authRefresh`, and `oauthUrl("google")` with `captureOAuthToken(sluurp)` on the return page. The session is stored in `localStorage` and shared across the site's pages. `sluurp.onAuthFailure` fires when the server rejects the token.

## Permissions

```ts title="app.ts"
const may = await sluurp.permissions();
may.can("grades", "update");        // for some rows at least
may.certainly("grades", "delete");  // for every row
```

Evaluates the collections' [rules](/docs/rules) up front, so you can show only buttons that will work.

## Errors

Failed calls throw a `SluurpError` with `status`, `message` (from the server), `body`, and the helpers `isAuthError` (401) and `isForbidden` (403).

## Live

`sluurp.socket({ subscribe: ["messages"] })` opens a WebSocket that streams every change to those collections, filtered by your rules. `on(type, listener)` subscribes; `join(topic)` / `leave(topic)` handle presence; `emit(topic, event, data)` broadcasts without storing. For lists that stay current automatically, use [Sync](/docs/sync).

## Instant first render

`kept` renders immediately from the last response cached in this browser, then updates from the server's response if it differs (stale-while-revalidate):

```js title="app.js"
sluurp.kept("feeds", () => sluurp.social.feeds(), (r) => feeds.set(r.items));
```

A reload then shows the complete screen in the first frame instead of filling in piece by piece. The cache is per user, per browser, and cleared on `logout()`.

## And the rest

`sluurp.conversation(id)` and `sluurp.conversations` for chat, `sluurp.pages` for [Pages](/docs/pages), `sluurp.payments` and `sluurp.billing` for [Payments](/docs/payments), `sluurp.ai` for [AI](/docs/ai), `sluurp.social` for feeds. `sluurp.send(path, { method, body, query })` calls any endpoint with auth and app headers attached.
