A modern **React SIP.js toolkit** for building web softphones and SIP clients. Supports **audio/video calls**, **call recording**, **screen sharing**, and **device management**, all with a clean, extensible, TypeScript-first architecture.
npm install react-sip-kitbash
npm install react-sip-kit
or
yarn add react-sip-kit
``
---
š Quick Start
$3
`tsx
// main.tsx
import App from './App';
import { SipManager } from 'react-sip-kit';
import { StrictMode, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
export const SipConnection = new SipManager();
const Providers = () => {
const configs = [
{
key: 'support-01', // Optional ā If omitted, defaults to account.username
account: {
domain: 'sip.example.com',
username: '1010',
password: 'password',
wssServer: 'sip.example.com',
webSocketPort: '8089',
serverPath: '/ws',
},
},
];
useEffect(() => {
configs.forEach((config) => SipConnection.add(config));
}, []);
return (
);
};
createRoot(document.getElementById('root')!).render( );
`
---
š Resolving Accounts & Sessions
All lookups use one of the following keys:
| Key | Purpose | Example |
| -------------- | ------------------------------------------------------------- | --------------------------------------------------- |
| configKey | Refers to a specific SIP account instance | { configKey: 'support-01' } |
| lineKey | Refers to an active call / line | { lineKey: 1 } |
| remoteNumber | Refers to peer phone number ā must be paired with configKey | { configKey: 'support-01', remoteNumber: '1001' } |
---
$3
`tsx
// Using configKey
const { dialByNumber } = SipConnection.getSessionMethodsBy({ configKey: 'support-01' });
dialByNumber('audio', '1002');
// Using lineKey (after a call is active)
SipConnection.getSessionMethodsBy({ lineKey: 1 }).hold();
`
---
$3
`tsx
const { watch, status } = SipConnection.getAccountBy({ configKey: 'support-01' });
const account = watch(); // contains lines, registration, media devices, etc.
`
---
$3
`tsx
const isRecording = SipConnection.useWatchSessionData({
key: { lineKey: 1 },
name: 'recordMedia.recording',
});
const [mediaStatus, isMuted] = SipConnection.useWatchSessionData({
key: { configKey: 'support-01', remoteNumber: '1002' },
name: ['localMediaStreamStatus', 'localMediaStreamStatus.muted'],
});
`
---
$3
`ts
SipConnection.getLineBy({ lineKey: 1 });
SipConnection.getLineBy({ configKey: 'support-01', remoteNumber: '1002' });
SipConnection.getSessionBy({ lineKey: 1 });
SipConnection.getUsernameBy({ configKey: 'support-01', remoteNumber: '1002' });
`
---
$3
`tsx
import { VideoStream, AudioStream } from 'react-sip-kit';
`
---
$3
`tsx
const configs = SipConnection.useWatchConfigs();
// ā [{ key: 'support-01', account: {...} }, { key: 'sales-02', ... }]
`
ā
When to use useWatchConfigs()
| Scenario | Should you use it? | Reason |
| ------------------------------------------------------ | ----------------------- | ------------------------------------------------------------------------------- |
| Static single account | ā Not required | configKey is constant |
| You manually track configs in your own state | ā Optional | You already control the list |
| Rendering UI for each config account dynamically | ā
Yes ā recommended | Ensures you always use the correct configKey, even if keys are auto-generated |
| Configs can be added or removed at runtime | ā
Always | Prevents mismatched lookups or stale references |
> ā Best Practice:
> Always call useWatchConfigs() when rendering lists of lines or accounts, to ensure that each component receives the correct and current configKey.
---
Example (Rendering a phone UI for every config dynamically):
`tsx
const App = () => {
const configs = SipConnection.useWatchConfigs();
return (
<>
{configs.map((config) => (
))}
>
);
};
`
---
āļø Configuration Schema
`ts
{
key?: string; // optional ā falls back to account.username
account: {
domain: 'your.sip.domain',
username: 'user',
password: 'secret',
wssServer: 'your.sip.domain',
webSocketPort: '8089',
serverPath: '/ws',
},
features?: { enableVideo?: boolean },
media?: {
audioInputDeviceId?: string;
audioOutputDeviceId?: string;
videoInputDeviceId?: string;
},
registration?: { registerExpires?: number },
}
`
---
ā
Best Practices
| Task | Recommended Approach |
| ---------------------- | --------------------------------- |
| Reference active call | Use lineKey when available |
| Reference account | Use configKey |
| Lookup by phone number | Use { configKey, remoteNumber } |
| Track config keys | Use useWatchConfigs() |
| Watch configs state | useWatchConfigs() |
| Watch account state | getAccountBy().watch() |
| Watch session props | useWatchSessionData() |
---
š Examples
Check /example` for: