juv-ksip-softphone
v1.0.53
Published
A React WebRTC SIP softphone component for FreePBX/Asterisk with audio/video calls, auto-recording, connection monitoring, and API upload support
Maintainers
Readme
juv-ksip-softphone
A professional, draggable, resizable, transparent React WebRTC SIP softphone component for FreePBX / Asterisk. Supports audio and video calls, incoming call handling, codec selection, and a global ksipcall API for triggering calls from anywhere in your app.
WEB DOCUMENTATION
Visit Documentation: php-ksip-telnet & juv-ksip-softphone Documentation
Author: Kenneth H. Gimpao
Published: April 21, 2026
What is this?
juv-ksip-softphone is a React-based WebRTC SIP softphone designed to be dropped into any existing web application as a transparent floating overlay. It connects to a FreePBX / Asterisk PBX server using the SIP protocol over WebSocket (ws:// or wss://) and enables real-time audio and video calling directly from the browser — no plugins, no downloads required.
What is it for?
This component is built for developers who need to add VoIP calling capabilities to their existing React web applications without rebuilding their UI from scratch. Common use cases include:
- Call center dashboards — agents can make and receive calls directly from their browser-based CRM or ticketing system
- Customer support portals — embed a softphone into a helpdesk app so support staff can call customers with one click
- Dispatch and operations systems — field coordinators can communicate via audio/video without switching applications
- Healthcare platforms — doctors and staff can conduct audio/video consultations from within a patient management system
- Any web app that needs calling — simply drop
<Softphone />into your app and it floats transparently on top
How does it work?
SIP over WebSocket — The component connects to your FreePBX/Asterisk server via a WebSocket connection (
ws://orwss://). FreePBX listens on port8088(ws) or8089(wss) for WebSocket SIP traffic.WebRTC for media — Once a call is established, the browser uses WebRTC (built into all modern browsers) to handle the actual audio and video streams. This means no additional software is needed — the browser handles microphone, camera, and speaker access natively.
SIP registration — On connect, the component registers your extension with the PBX just like a physical desk phone would. Once registered, you can make outgoing calls and receive incoming calls.
Transparent overlay — The softphone renders as a
position: fixedtransparent layer on top of your existing app. Your app's UI is completely unaffected — the softphone simply floats above it.Global
ksipcallAPI — A globalwindow.ksipcallobject is exposed so you can trigger calls from anywhere in your codebase — even from plain JavaScript, Vue, Angular, or any other framework running on the same page.
Browser ──WebSocket──▶ FreePBX/Asterisk ──SIP──▶ Other Phone/Extension
(SIP/WS) (PBX) (IP Phone, Softphone)
Browser ◀──WebRTC──▶ FreePBX/Asterisk ◀──RTP──▶ Other Phone/Extension
(Audio/Video) (Media) (Audio/Video Stream)Screenshots
Features
- 🎙 Audio & video calls via WebRTC + SIP (FreePBX / Asterisk)
- 📞 Incoming call notifications with accept/reject
- 🪟 Draggable + resizable floating video panel (expandable to fullscreen)
- 🔢 Draggable dialpad panel
- 💾 Auto-saves config to
localStorageand auto-connects on reload - 🔄 Auto-reconnects on WebSocket disconnect
- 🌐 Transparent background — overlays any existing app
- 🎛 Floating messenger-style FAB nav (settings, dialer, opacity)
- 📡 Global
ksipcallAPI — trigger calls from plain JS or any framework - 🔒 ws:// / wss:// protocol selector
- 🎚 Audio & video codec selection
- ⚙ Fully configurable via props and in-app settings panel
- 🔔 Ringtones for incoming and end call
Installation
npm install juv-ksip-softphoneQuick Start
import { Softphone } from 'juv-ksip-softphone';
import 'juv-ksip-softphone/styles';
function App() {
return (
<>
<YourExistingApp />
<Softphone />
</>
);
}The softphone renders as a transparent overlay with a floating phone button (top-right). Click it to open the nav menu.
Props
SIP Connection Props
| Prop | Type | Default | Description |
|---|---|---|---|
| server | string | "" | FreePBX server IP or hostname |
| wsProtocol | "ws" | "wss" | "ws" | WebSocket protocol. Use wss for HTTPS pages |
| wsPort | string | "8088" | WebSocket port (8088 for ws, 8089 for wss) |
| extension | string | "" | SIP extension number |
| password | string | "" | SIP extension password |
| displayName | string | "" | Caller ID display name (optional) |
Recording Props
| Prop | Type | Default | Description |
|---|---|---|---|
| autoRecord | boolean | false | Enable automatic recording of all calls |
| recordingDir | string | "video/recordings/Ksip" | Directory path for saved recordings |
| uploadApiUrl | string | "" | API endpoint URL for uploading recordings (optional) |
Settings Configuration Props
| Prop | Type | Default | Description |
|---|---|---|---|
| settingConfigToggles | object | all true | Controls which toggles are visible in settings UI |
| settingConfigTogglesActiveState | object | varies | Sets initial active state for toggles |
| settingConfigCodecs | object | all visible | Controls codec visibility and available options |
UI Props
| Prop | Type | Default | Description |
|---|---|---|---|
| enabledBubble | boolean | true | Show or hide the entire softphone bubble |
| showDialer | boolean | true | Show the dialer button in the FAB nav |
| showSetting | boolean | true | Show the settings button in the FAB nav |
| showOpacity | boolean | true | Show the opacity button in the FAB nav |
| answerwithVideoCall | boolean | false | Auto-answer incoming calls with video. Forces ShowIncomingCallAudio to false |
| ShowIncomingCallVideoBtn | boolean | true | Show the video answer button on incoming calls |
| ShowIncomingCallAudio | boolean | true | Show the audio answer button on incoming calls. Forced false when answerwithVideoCall=true |
Priority Order
Props are used as initial defaults. If the user has previously saved a config via the settings panel, localStorage takes priority. This allows the user to override props from within the app.
Examples
Basic — manual config via settings panel
<Softphone />Pre-configured — auto-connect on load
<Softphone
server="192.168.1.100"
wsProtocol="ws"
wsPort="8088"
extension="1001"
password="mypassword"
displayName="John Doe"
/>Full configuration
<Softphone
// SIP Connection
server="192.168.1.100"
wsProtocol="ws"
wsPort="8088"
extension="1001"
password="mypassword"
displayName="John Doe"
// UI
enabledBubble={true}
showDialer={true}
showSetting={true}
showOpacity={true}
answerwithVideoCall={false}
ShowIncomingCallVideoBtn={true}
ShowIncomingCallAudio={true}
/>Audio-only mode (no video answer button)
<Softphone
ShowIncomingCallVideoBtn={false}
ShowIncomingCallAudio={true}
/>Auto-answer with video
<Softphone
answerwithVideoCall={true}
// ShowIncomingCallAudio is automatically false
/>wss:// for HTTPS pages
<Softphone
server="pbx.yourdomain.com"
wsProtocol="wss"
wsPort="8089"
extension="1001"
password="mypassword"
/>Settings Configuration
<Softphone
settingConfigToggles={{
bubble: true,
dialer: true,
settings: false, // Hide settings toggle
opacity: true,
autoAnswerVideo: true,
answerButtonVideo: false, // Hide video answer button toggle
answerButtonAudio: true,
fullscreen: true,
autoRecording: true,
}}
settingConfigTogglesActiveState={{
bubble: true,
dialer: true,
settings: true,
opacity: true,
autoAnswerVideo: true, // Start with auto-answer video ON
answerButtonVideo: true,
answerButtonAudio: false,
fullscreen: false,
autoRecording: true, // Start with recording ON
}}
settingConfigCodecs={{
audio: { visible: true, codecs: ["PCMU", "PCMA"] }, // Only show these 2
video: { visible: false, codecs: ["VP8", "H264"] }, // Hide video codecs section
}}
/>Auto Recording with API Upload
<Softphone
autoRecord={true}
recordingDir="video/recordings/Ksip"
uploadApiUrl="https://your-domain.com/api/recordings/upload"
/>Complete Example with All Features
<Softphone
// SIP Connection
server="192.168.1.100"
wsProtocol="ws"
wsPort="8088"
extension="1001"
password="mypassword"
displayName="John Doe"
// UI Controls
enabledBubble={true}
showDialer={true}
showSetting={true}
showOpacity={true}
answerwithVideoCall={false}
ShowIncomingCallVideoBtn={true}
ShowIncomingCallAudio={true}
fullscreen={false}
// Recording
autoRecord={true}
recordingDir="video/recordings/Ksip"
uploadApiUrl="https://your-domain.com/api/recordings/upload"
// Settings Configuration
settingConfigToggles={{
bubble: true,
dialer: true,
settings: true,
opacity: true,
autoAnswerVideo: true,
answerButtonVideo: true,
answerButtonAudio: true,
fullscreen: true,
autoRecording: true,
}}
settingConfigTogglesActiveState={{
bubble: true,
dialer: true,
settings: true,
opacity: true,
autoAnswerVideo: false,
answerButtonVideo: true,
answerButtonAudio: true,
fullscreen: false,
autoRecording: true,
}}
settingConfigCodecs={{
audio: { visible: true, codecs: ["PCMU", "PCMA", "opus"] },
video: { visible: true, codecs: ["VP8", "H264"] },
}}
/>ksipcall API
The ksipcall global lets you trigger calls from anywhere — plain JavaScript, Vue, Angular, or any other framework.
Audio Call
ksipcall.audio("123");Video Call
ksipcall.video("123");Via window (plain HTML / vanilla JS)
<button onclick="ksipcall.audio('123')">Call Support</button>
<button onclick="ksipcall.video('456')">Video Call</button>Import in React / other frameworks
import { ksipcall } from 'juv-ksip-softphone';
ksipcall.audio("123");
ksipcall.video("123");Settings Panel
The in-app settings panel (accessible via the ⚙ button) has a 3-column layout:
Column 1 — SIP Configuration
| Field | Description | Example |
|---|---|---|
| FreePBX Server IP | IP or hostname | 192.168.1.100 |
| Extension | SIP extension number | 1001 |
| Password | Extension SIP password | mypassword |
| Display Name | Caller ID name (optional) | John Doe |
| Protocol | ws:// or wss:// | ws:// |
| Port | WebSocket port | 8088 |
Column 2 — Codecs
Audio Codecs: PCMU, PCMA, G722, G729, opus
Video Codecs: VP8, VP9, H264, H265, AV1
Opacity: FAB bubble opacity slider (min 30%)
Column 3 — UI Preferences
All UI props are configurable as toggles:
- Show Bubble
- Show Dialer Button
- Show Settings Button
- Show Opacity Button
- Answer with Video
- Show Video Answer Button
- Show Audio Answer Button
CDN Usage (Browser)
You can use this package directly in the browser via CDN — no build tools required.
1. Include scripts
<!-- Styles -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/juv-ksip-softphone.css">
<!-- Softphone — fully self-contained, no other scripts needed -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/juv-ksip-softphone.cdn.js"></script>2. Mount the softphone
The CDN build exposes window.JuvKsipSoftphone with Softphone, createRoot, and ksipcall all included.
<div id="softphone"></div>
<script>
const { Softphone, createRoot, createElement } = window.JuvKsipSoftphone;
createRoot(document.getElementById('softphone')).render(
createElement(Softphone, {
server: "192.168.1.100",
wsProtocol: "ws",
wsPort: "8088",
extension: "1001",
password: "mypassword",
displayName: "John Doe"
})
);
</script>Minimal (zero-config — use the settings panel)
<div id="softphone"></div>
<script>
const { Softphone, createRoot, createElement } = window.JuvKsipSoftphone;
createRoot(document.getElementById('softphone')).render(
createElement(Softphone)
);
</script>3. Trigger calls via ksipcall (CDN)
Once the softphone is mounted, window.ksipcall is automatically available:
<button onclick="window.ksipcall.audio('1002')">Audio Call</button>
<button onclick="window.ksipcall.video('1002')">Video Call</button>Notes:
- No React or ReactDOM scripts needed — everything is bundled in
juv-ksip-softphone.cdn.js.- Use
wss://when your page is served over HTTPS.- All props from the Props section work the same way via
React.createElement.
WebSocket Protocol
| Protocol | Port | Use Case |
|---|---|---|
| ws:// | 8088 | Local network, HTTP pages |
| wss:// | 8089 | Production, HTTPS pages (requires SSL cert on FreePBX) |
Note: Browsers block
ws://(insecure) when the page is served overhttps://. Usewss://with a valid SSL certificate for production.
FreePBX / Asterisk Requirements
For WebRTC to work, each SIP extension must have these settings:
| Setting | Value |
|---|---|
| webrtc | yes |
| use_avpf | yes |
| media_encryption | dtls |
| ice_support | yes |
| bundle | yes |
| rtcp_mux | yes |
| dtls_setup | actpass |
Enable via FreePBX Admin UI
- Applications → Extensions → [your extension]
- Tab: Advanced
- Set WebRTC →
Yes - Submit → Apply Config
Enable via CLI (pjsip.endpoint_custom.conf)
[1001](+)
webrtc=yesasterisk -rx "pjsip reload"Floating Nav Controls
| Button | Action | |---|---| | 📞 Phone (FAB) | Open / close the nav menu | | ⊞ Grid | Toggle dialpad panel | | ⚙ Settings | Toggle settings & SIP config panel | | ≡ Sliders | Quick opacity adjustment (min 30%) |
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl + Shift + K | Toggle settings panel |
Status Toast Notification
A floating status indicator appears at the top-center of the screen showing the current connection state:
| Status | Color | Behavior | |---|---|---| | Connected | 🟢 Green | Auto-hides after 5 seconds | | Reconnecting | 🟡 Yellow | Stays visible until connected | | Not Connected | 🔴 Red | Stays visible until connected |
- The status toast includes a settings icon button for quick access to the settings panel
- Automatically appears when the app loads
- Shows real-time connection status updates
- Always visible even when bubble is hidden (can be accessed via
Ctrl + Shift + K)
Connection Monitoring
The softphone includes robust connection monitoring to detect server failures:
- Automatic Re-registration: SIP registration refreshes every 10 minutes to maintain active connection
- Disconnect Detection: Immediately detects when WebSocket connection is lost
- Auto-reconnect: Attempts to reconnect every 3 seconds when connection is lost
- Unexpected Unregistration: Automatically attempts to re-register if server rejects registration
- Long-running Sessions: Maintains connection health even after hours of being connected without page reload
Example Scenario:
- App connected at 9:00 AM
- Server goes down at 9:30 AM (30 minutes later)
- Status toast immediately shows "Reconnecting..." (yellow)
- Auto-retry every 3 seconds
- When server comes back online → auto-reconnects → "Connected" (green)
localStorage
Config is automatically saved under the key sip_softphone_config and restored on next page load, including:
- SIP credentials (server, extension, password, display name)
- WebSocket protocol and port
- Selected audio/video codecs
- UI preferences (all toggle states including "Show Bubble")
- Recording settings (autoRecord, recordingDir, uploadApiUrl)
- Fullscreen preference
- Directory access permission state
showSettingis never saved to localStorage — it is always controlled by props.
Example localStorage data:
{
"server": "192.168.1.100",
"extension": "1001",
"password": "mypassword",
"displayName": "John Doe",
"wsProtocol": "ws",
"wsPort": "8088",
"audioCodecs": ["PCMU", "PCMA"],
"videoCodecs": ["VP8", "H264"],
"enabledBubble": true,
"showDialer": true,
"showOpacity": true,
"answerwithVideoCall": false,
"ShowIncomingCallVideoBtn": true,
"ShowIncomingCallAudio": true,
"fullscreen": false,
"autoRecord": true,
"recordingDir": "video/recordings/Ksip",
"uploadApiUrl": "https://api.example.com/upload",
"hasDirectoryAccess": true
}Auto Recording Feature
Overview
The softphone now supports automatic recording of audio and video calls with configurable save directory.
Features
- ✅ Auto-record toggle in settings panel
- ✅ Configurable recording directory
- ✅ Saves as WebM format (video/webm or audio/webm)
- ✅ Automatic download after call ends
- ✅ Filename format:
{directory}_{timestamp}.webm - ✅ Props support for default configuration
- ✅ localStorage persistence
Props
autoRecord (boolean)
- Default:
false - Description: Enable automatic recording of all calls
- Example:
<Softphone autoRecord={true} />recordingDir (string)
- Default:
"video/recordings/Ksip" - Description: Directory path for saved recordings (browser will suggest this path in download dialog)
- Example:
<Softphone
autoRecord={true}
recordingDir="video/recordings/Ksip"
/>Settings Panel
Toggle
- Location: Settings → UI Preferences → "Auto Record Calls"
- Behavior: Enable/disable automatic recording
Directory Input
- Location: Appears below toggle when auto-record is enabled
- Placeholder: "video/recordings/Ksip"
- Default: "video/recordings/Ksip"
- Note: Browser downloads use this as suggested filename path. Actual folder creation depends on browser settings.
How It Works
- Directory Selection: When auto-record is enabled for the first time, a modal appears asking to select a directory
- Browser Permission: User selects a folder using the File System Access API (Chrome/Edge)
- Recording Start: When a call is established (state = "active"), recording starts automatically if enabled
- Recording Stop: When call ends (state = "idle"), recording stops and saves directly to the selected directory
- File Format: WebM container with VP8/Opus codecs (or fallback to audio-only)
- File Naming:
{ISO-timestamp}.webm- Example:
2024-04-21T14-30-45-123Z.webm
- Example:
- Persistent Access: Browser remembers the directory permission for future recordings
Technical Details
MediaRecorder API
- Uses browser's native MediaRecorder API
- Captures both local and remote audio/video tracks
- Collects chunks every 1 second
- Creates downloadable blob on stop
Codec Support
- Preferred:
video/webm;codecs=vp8,opus - Fallback 1:
video/webm - Fallback 2:
audio/webm
Browser Compatibility
- Chrome/Edge: Full support
- Firefox: Full support
- Safari: Limited (may require polyfill)
Usage Examples
Basic Usage
<Softphone autoRecord={true} />Custom Directory
<Softphone
autoRecord={true}
recordingDir="video/recordings/Ksip"
/>Full Configuration
<Softphone
server="192.168.1.100"
extension="1001"
password="secret"
autoRecord={true}
recordingDir="video/recordings/Ksip"
/>Runtime Toggle
Users can enable/disable recording via the settings panel without reloading the page.
Storage
Settings are saved to localStorage under key sip_softphone_config:
{
"autoRecord": true,
"recordingDir": "video/recordings/Ksip",
...
}Notes
File System Access API (Chrome/Edge 86+, Opera):
- Modal prompts user to select directory on first use
- Files save directly to selected folder without download prompts
- Browser remembers permission (persists across sessions)
- User can revoke permission in browser settings
Fallback for unsupported browsers (Firefox, Safari):
- Uses traditional download method
- Files download to default Downloads folder
- No automatic directory creation
Security:
- User must explicitly grant directory access
- Permission can be revoked anytime
- No access to files outside selected directory
File size depends on call duration and quality
WebM format is widely supported and efficient
To convert to MP3, use external tools like FFmpeg:
ffmpeg -i recording.webm -vn -ar 44100 -ac 2 -b:a 192k output.mp3
Author
Kenneth H. Gimpao Published: 2026
GitHub Repository: https://github.com/kitenebie/SoftPhone-FreePBX
php-ksip-telnet (laravel): https://github.com/kitenebie/FreePBX-Console.git
License
MIT
