Browser SDK (@rymi/web)
Add AI voice conversations to any website with a small browser SDK.
How It Works
Option A: Publishable Keys (Recommended)
The simplest way to integrate. Connect directly from your frontend using a scoped publishable key tied to a specific agent.
Your Frontend Rymi API
│ │
├── call.connect() with sb_publishable_... ─► │
│ (Handshake) │
│ │
│ ◄──── Stream Audio ──────────┤
│ Voice ⇄ AI │Option B: Backend Proxy (Advanced)
If you need dynamic agent selection or custom logic before a call starts, your backend can fetch a short-lived token and pass it to the SDK.
Install
Via NPM (Recommended)
npm install @rymi/webVia Script Tag (CDN)
The simplest way to use Rymi is via our auto-updating CDN. This is always in sync with our latest stable release.
<script src="https://cdn.rymi.live/rymi.js"></script>
<script>
// Rymi is available on the global window object
const call = Rymi.createCall({ publishableKey: '...' });
call.on('started', () => console.log('Connected'));
await call.connect();
</script>Quick Start (Publishable Key)
1. Generate a Key
Generate a publishable key for your agent via the dashboard or the API.
2. Connect from the Browser
import { Rymi } from '@rymi/web';
async function startCall() {
// Create a prepared call using your publishable key
const call = Rymi.createCall({
publishableKey: 'sb_publishable_deadbeef...'
});
// Listen for events before connecting so no handshake event is missed
call.on('started', () => {
console.log('🎙️ Connected! Speak now.');
});
call.on('transcript', ({ role, text }) => {
console.log(`${role}: ${text}`);
});
call.on('ended', ({ reason }) => {
console.log('Call ended:', reason);
});
await call.connect();
}Advanced: Backend Proxy
If you prefer to keep your agent logic strictly server-side, your backend can generate the token for the SDK:
- Backend:
POST /v1/callswith{ agent_id: "...", participants: [{ transport: "webrtc", identity: "browser" }] }. - Frontend: Pass the resulting
urlandtokento the SDK:tsconst call = Rymi.createCall({ url: accessUrl, token: accessToken }); call.on('transcript', ({ role, text }) => console.log(role, text)); await call.connect();
API Reference
Rymi.createCall(config)
Create a prepared call using either a publishable key or pre-fetched LiveKit credentials. Attach event listeners before calling call.connect().
| Property | Type | Description |
|---|---|---|
publishableKey | string | Your key starting with sb_publishable_; legacy rymi_pk_ keys are still accepted |
url | string | LiveKit URL from POST /v1/calls response when using backend-proxy mode |
token | string | Access token from POST /v1/calls response when using backend-proxy mode |
autoMic | boolean | Start with mic on (default: true) |
apiUrl | string | Optional: Override API endpoint. Defaults to https://api.rymi.live |
identity | string | Optional browser participant identity. Defaults to browser |
Rymi.connect(config)
Convenience one-shot helper equivalent to const call = Rymi.createCall(config); await call.connect();. Prefer createCall() for production UI so listeners are attached before the network/WebRTC handshake starts.
RymiCall Methods
| Method | Description |
|---|---|
call.mute() | Mute the user's microphone |
call.unmute() | Unmute the user's microphone |
call.connect() | Start the prepared call |
call.end() | End the call |
call.isMuted | boolean — is mic muted? |
call.status | 'idle' | 'connecting' | 'connected' | 'ended' | 'error' |
RymiCall Events
| Event | Payload | Description |
|---|---|---|
started | — | Mic connected, call is live |
transcript | { role, text } | Speech-to-text output |
thinking | — | AI is processing |
ended | { reason } | Call terminated |
error | Error | Something went wrong |
diagnostic | { stage, status, message, timestamp } | Connection lifecycle progress |
audioPlayback | { blocked } | Browser autoplay blocked/unblocked agent audio |
Security
Scoped Protection
Publishable keys are write-only. They can only initiate WebRTC calls for the specific agent they are assigned to. They cannot be used to read call history or access account data.
Secret Keys
Never use your secret rymi_... keys in frontend code. Use them only on your backend.

