# @sanity/bifur-client

> WebSocket client for Sanity's Bifur real-time service, communicating over JSON-RPC 2.0 and returning RxJS Observables

Latest version **2.0.2** (published 2026-08-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install @sanity/bifur-client
pnpm add @sanity/bifur-client
yarn add @sanity/bifur-client
bun add @sanity/bifur-client
```

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.0.2 |
| Published | 2026-08-19 |
| First published | 2020-04-24 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM |
| Node | >=22.12 |
| Dependencies | 2 |
| Unpacked size | 31.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| Author | Sanity.io <hello@sanity.io> |
| Maintainers | sanity-svc.npm, sanity-io |
| Keywords | bifur, json-rpc, observables, presence, real-time, realtime, rxjs, sanity, sanity-io, websocket |

## Links

- npm: https://www.npmjs.com/package/@sanity/bifur-client
- Repository: https://github.com/sanity-io/bifur-client
- Homepage: https://github.com/sanity-io/bifur-client#readme
- Issues: https://github.com/sanity-io/bifur-client/issues
- npm.io page: https://npm.io/package/@sanity/bifur-client

## Dependencies (2)

- [rxjs](https://npm.io/package/rxjs.md) ^7.8.2
- [nanoid](https://npm.io/package/nanoid.md) ^6.0.1

## Alternatives

- [@opentelemetry/exporter-zipkin](https://npm.io/package/@opentelemetry/exporter-zipkin.md) — 14.8M weekly downloads
- [pusher-js](https://npm.io/package/pusher-js.md) — 2.0M weekly downloads
- [browserify](https://npm.io/package/browserify.md) — 1.7M weekly downloads
- [sqs-consumer](https://npm.io/package/sqs-consumer.md) — 1.7M weekly downloads
- [@sanity/eventsource](https://npm.io/package/@sanity/eventsource.md) — 930.8K weekly downloads

## Recent versions

- 2.0.2 (latest) — 2026-08-19
- 0.4.0-canary.0 (canary) — 2024-05-08
- 0.4.0-1 (rxjs7) — 2023-01-06
- 0.4.0-0 (rxjs@7) — 2023-01-06
- 2.0.1 — 2026-08-19
- 2.0.0 — 2026-08-19
- 1.0.0 — 2026-03-06
- 0.4.1 — 2024-06-04
- 0.4.0 — 2024-05-13
- 0.3.1 — 2023-01-09
- 0.3.0 — 2022-07-08
- 0.2.0 — 2022-07-08
- 0.1.0 — 2022-06-30
- 0.0.8 — 2021-03-29
- 0.0.7 — 2020-09-23
- … 7 more at https://npm.io/package/@sanity/bifur-client/versions

## README

# @sanity/bifur-client

A WebSocket client for Sanity's Bifur real-time service. Communicates over JSON-RPC 2.0 and returns RxJS Observables.

## Installation

```sh
npm install @sanity/bifur-client
```

## Usage

### From a `@sanity/client` instance

The simplest way to get started if you already use `@sanity/client`:

```ts
import {fromSanityClient} from '@sanity/bifur-client'
import {createClient} from '@sanity/client'

const sanityClient = createClient({
  projectId: 'your-project-id',
  dataset: 'production',
  token: 'your-token',
})

const bifur = fromSanityClient(sanityClient)
```

### From a WebSocket URL

Connect directly to a Bifur WebSocket endpoint:

```ts
import {fromUrl} from '@sanity/bifur-client'
import {of} from 'rxjs'

const bifur = fromUrl('wss://example.sanity.io/socket/production', {
  timeout: 10_000,
  token$: of('your-token'),
})
```

#### Options

| Option    | Type                         | Description                                                                     |
| --------- | ---------------------------- | ------------------------------------------------------------------------------- |
| `timeout` | `number`                     | Milliseconds to wait before timing out the initial connection                   |
| `token$`  | `Observable<string \| null>` | Observable of auth tokens. Emitting a new value re-authenticates the connection |

### Presence example

Subscribe to presence events with `listen()`, and send requests with `request()`:

```ts
// Subscribe to presence events
bifur.listen('presence').subscribe((event) => {
  console.log(event.type, event) // 'rollCall', 'state', or 'disconnect'
})

// Respond to roll calls
bifur.request('presence_rollcall', {session: sessionId})

// Announce your location
bifur.request('presence_announce', {
  data: {sessionId, locations: [{documentId: 'my-doc', path: 'title'}]},
})

// Disconnect
bifur.request('presence_disconnect', {session: sessionId})
```

### Heartbeats

`heartbeats` is an Observable that emits a `Date` each time a message (including heartbeat pings) is received. Subscribing to it keeps the connection alive between requests:

```ts
bifur.heartbeats.subscribe((timestamp) => {
  console.log('Last activity:', timestamp)
})
```

### Request and subscribe methods

**Request methods:** `presence_rollcall`, `presence_announce`, `presence_disconnect`, `authorization`

**Subscribe methods:** `presence`, `authorization`

### Error codes

```ts
import {ERROR_CODES} from '@sanity/bifur-client'

// Connection-level
ERROR_CODES.BAD_REQUEST // 4000
ERROR_CODES.UNAUTHORIZED // 4001
ERROR_CODES.NOT_FOUND // 4004

// Application-level (JSON-RPC)
ERROR_CODES.INVALID_REQUEST // -32600
ERROR_CODES.METHOD_NOT_FOUND // -32601
ERROR_CODES.INVALID_PARAMS // -32602
ERROR_CODES.SUBSCRIPTION_NOT_FOUND // -32602
ERROR_CODES.PARSE_ERROR // -32700
```

## License

MIT - See LICENSE

---
_Source: https://npm.io/package/@sanity/bifur-client · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
