Skip to content

SDK guide ​

Headless TypeScript SDK for your chat UI. Install from npm, keep your own screens and styling.

Install ​

bash
npm install @omnychat/client
# optional:
npm install @omnychat/react
npm install @omnychat/vue
npm install @omnychat/storage-sqlite
PackageRole
@omnychat/clientConnect, rooms, send, sync, outbox
@omnychat/reactuseOmnyChat, useRoom, useConnection
@omnychat/vueSame surface as React, for Vue 3
@omnychat/storage-sqliteSQLite storage for Expo / React Native

Core usage ​

ts
import {
  createOmnyChat,
  createMemoryStorage,      // tests / Node
  createIndexedDBStorage,  // browsers
} from '@omnychat/client';

const client = createOmnyChat({
  url: 'wss://chat.example.com/v1/ws',
  tokenProvider: () => fetchToken(), // your auth; JWT sub = user id
  storage: createIndexedDBStorage(),
});

await client.connect();
await client.joinRoom('team-engineering');
await client.sendMessage('team-engineering', 'hello');
await client.editMessage('team-engineering', serverMsgId, 'hello!');
await client.deleteMessage('team-engineering', serverMsgId);
client.subscribeRoom('team-engineering', (snap) => {
  // snap.messages ordered by seq
});

client.setTyping('team-engineering', true);
client.sendReadReceipt('team-engineering', lastSeq);

Create rooms once from your backend with POST /v1/rooms — not from the client SDK.

Group chat (and DMs) ​

Group and 1:1 use the same room API:

ts
// Your backend chose members and created room id "group-42"

await client.connect();
await client.joinRoom('group-42');
client.subscribeRoom('group-42', renderTimeline);
await client.sendMessage('group-42', 'hey team');

Everyone who has joined the room receives messages. Decide membership in your app (only give JWTs / room ids to allowed users).

React ​

tsx
import { OmnyChatProvider, useRoom, useConnection } from '@omnychat/react';

function Chat({ roomId }: { roomId: string }) {
  const state = useConnection();
  const snap = useRoom(roomId);
  return (
    <div>
      <p>{state}</p>
      <ul>
        {snap?.messages.map((m) => (
          <li key={m.clientMsgId}>
            {m.body} {m.status === 'pending' ? '…' : ''}
          </li>
        ))}
      </ul>
    </div>
  );
}

// <OmnyChatProvider client={client}><Chat roomId="group-42" /></OmnyChatProvider>

Vue 3 ​

ts
import { createApp } from 'vue';
import { createOmnyChat, createIndexedDBStorage } from '@omnychat/client';
import { OmnyChatPlugin, useRoom, useConnection } from '@omnychat/vue';

const client = createOmnyChat({
  url: 'wss://chat.example.com/v1/ws',
  tokenProvider: () => fetchToken(),
  storage: createIndexedDBStorage(),
});

createApp(App).use(OmnyChatPlugin, { client }).mount('#app');
vue
<script setup lang="ts">
import { useConnection, useRoom } from '@omnychat/vue';
const state = useConnection();
const snap = useRoom('group-42');
</script>

React Native ​

ts
import * as SQLite from 'expo-sqlite';
import { createOmnyChat } from '@omnychat/client';
import { createSqliteStorage } from '@omnychat/storage-sqlite';

const storage = await createSqliteStorage(SQLite.openDatabaseAsync);
const client = createOmnyChat({ url, tokenProvider, storage });

Also see How it works and Offline & sync.

Apache License 2.0