Client SDK
Documentation
Client SDK
Connect, send, and subscribe to real-time chat events with @emb-chat/react-native-sdk.
@emb-chat/react-native-sdk is the universal client. Despite the name it runs unchanged in browsers, React Native, and Node 20+ — its only dependency is socket.io-client. It handles the WebSocket connection, auto-reconnect, sender hydration, the presence heartbeat, and typing timers for you.
npm install @emb-chat/react-native-sdk
import { ChatClient } from '@emb-chat/react-native-sdk';
Connect
Create a client with the URL and the token your backend signed, then connect(). It resolves once the socket has received the ready signal.
const chat = new ChatClient({
url: 'https://chat.acme.com',
token,
// fetchImpl?: a custom fetch (defaults to global fetch)
// timeoutMs?: REST request timeout
});
await chat.connect();
// …later…
chat.disconnect();
Reconnects
The socket reconnects automatically. Subscribe to know when it happens (e.g. to refetch missed history):
chat.on('reconnect', () => {
// re-sync any state you care about
});
Channels
chat.channels is the channel collection; chat.channel(id) returns a cached per-channel handle.
const channels = await chat.channels.list();
const channel = await chat.channels.create({ type: 'group', name: 'Engineering' });
await chat.channels.update(channel.id, { name: 'Eng' });
await chat.channels.delete(channel.id);
await chat.channels.addMembers(channel.id, ['user_xyz789']);
await chat.channels.removeMember(channel.id, 'user_xyz789');
await chat.channels.setMemberRole(channel.id, 'user_xyz789', 'admin');
const members = await chat.channels.members(channel.id);
What a token client may do here depends on the app’s group mode. In
externalmode, channel management is API-key only;internalandhybridopen it up behind role gates. See the group-mode overview on the home page.
Real-time events
Subscribe per channel with channel.on(event, cb). Event names use the colon namespace.
const channel = chat.channel(channelId);
channel.on('message:new', (msg) => render(msg));
channel.on('message:edited', (msg) => update(msg));
channel.on('message:deleted', (msg) => remove(msg.id));
channel.on('typing:update', (t) => {
// { channel_id, user_id, typing }
});
channel.on('presence:update', (p) => {
// { user_id, status: 'online' | 'offline' }
});
channel.on('member:added', (m) => {});
channel.on('member:removed', (m) => {});
channel.on('member:role-updated', (m) => {});
channel.on('channel:updated', (c) => {});
Sending messages
sendMessage resolves on the server ack, so you know the message was accepted.
const msg = await channel.sendMessage({
body: 'Hello, world',
type: 'text',
metadata: { client_id: 'optimistic-42' }, // optional
});
If the ack fails, the SDK throws ChatApiError with code: 'ws_error':
import { ChatApiError } from '@emb-chat/react-native-sdk';
try {
await channel.sendMessage({ body: 'hi', type: 'text' });
} catch (err) {
if (err instanceof ChatApiError && err.code === 'ws_error') {
showToast('Send failed — check your connection');
}
}
History & pagination
History is cursor-based: pass the oldest message’s id back as before.
let { messages, hasMore } = await channel.getMessages({ limit: 50 });
if (hasMore) {
const older = await channel.getMessages({ limit: 50, before: messages[0].id });
messages = [...older.messages, ...messages];
}
Mark a channel read up to a given message for unread counts — pass the message id:
channel.markRead(messages[messages.length - 1].id);
Typing indicators
startTyping() emits typing:start and arms a 3-second auto-stop timer; calling it again debounce-extends. stopTyping() clears it immediately — call it on send or blur.
composer.addEventListener('input', () => channel.startTyping());
composer.addEventListener('blur', () => channel.stopTyping());
async function send(body: string) {
channel.stopTyping();
await channel.sendMessage({ body, type: 'text' });
}
Presence
Presence is automatic — the client pings every 15 seconds while connected; the server treats a user as online for a 30-second TTL and broadcasts presence.offline shortly after a real disconnect. Read a user’s presence on demand:
const { status } = await chat.users.presence('user_abc123'); // 'online' | 'offline'
const user = await chat.users.get('user_abc123');