Connexify is a modular WebRTC ecosystem built as a monorepo. It features a lightweight SDK, a dedicated core hardware layer, and a signaling service that enables real-time video calling in the browser using WebRTC's peer-to-peer (P2P) mesh architecture.
Designed with TypeScript project references, it strictly separates business logic (core-sdk) from browser APIs (webrtc-core) and shared types, making it a scalable foundation for building real-time communication apps.
This project is organized as a monorepo to ensure modularity and separation of concerns:
connexify/
├── apps/
│ ├── signaling-server/ # Node.js + Socket.IO signaling backend
│ └── demo/ # Vite + Vanilla TS frontend (consumer of the SDK)
├── packages/
│ ├── types/ # Shared TypeScript interfaces (Contract layer)
│ ├── utils/ # Shared helper functions
│ ├── webrtc-core/ # Low-level wrappers for RTCPeerConnection & Media (Hardware layer)
│ └── core-sdk/ # High-level Client SDK (Business Logic layer)
└── README.md
- ✅ Modular Architecture: Clean separation between types, hardware abstraction, and client SDK logic.
- ✅ P2P Mesh Topology: Supports 1:1 and small group video calls using native WebRTC.
- ✅ Event-Driven SDK: The
ConnexifyRTCClienthandles signaling events (offer,answer,ice-candidate) automatically. - ✅ Automatic Stream Handling: Manages local media capture and remote stream mapping internally.
- ✅ Hot-Pluggable Signaling: Uses Socket.io, but the logic is decoupled enough to swap protocols if needed.
- ✅ Vite Proxy Support: The demo app is configured to proxy WebSocket connections, eliminating CORS issues during local development.
While functional, this project is currently in a Prototype/Alpha stage. Please be aware of the following limitations:
- No Room Logic: The signaling server currently broadcasts
new-peerevents to all connected clients. There is no concept of "Rooms," meaning every connected user will try to connect to everyone else. - Hardcoded Signaling URL: The demo application currently relies on a hardcoded URL (e.g.,
loca.lttunnels) or localhost. This needs to be moved to environment variables for production use. - Basic Error Handling: Most errors currently trigger
alert()orconsole.error. A production-grade event emitter system for errors is needed. - Mesh Scaling Limits: As this uses a Mesh architecture, performance (CPU/Bandwidth) will degrade significantly beyond 4-5 participants.
- Node.js (v18+)
- PNPM (recommended) or NPM
Install dependencies for all packages and apps from the root:
pnpm installSince this uses TypeScript Project References, you must build the packages before running the apps:
# Run inside the root directory
pnpm run build --filter "./packages/**"cd apps/signaling-server
pnpm run dev
# Server listens on port 3000 by defaultcd apps/demo
pnpm run dev
# Vite runs on port 5173Note: Ensure your
vite.config.tsis proxying requests to your signaling server port.
Here is how to use the @connexify/core-sdk in your own application:
import { ConnexifyRTCClient } from '@connexify/core-sdk';
// 1. Initialize the client
const client = new ConnexifyRTCClient({
signalingURL: new URL('http://localhost:3000'), // Or your production URL
constraints: {
audio: true,
video: true
}
});
// 2. Handle incoming remote streams
client.onRemoteStream = (stream, peerId) => {
console.log(`Received stream from ${peerId}`);
const video = document.createElement('video');
video.srcObject = stream;
video.autoplay = true;
document.body.appendChild(video);
};
// 3. Initialize Socket Listeners
client.socketHandler();
// 4. Start Media and Signaling
// Best practice: Wait for socket connection before starting media
client.socket.on("connect", async () => {
await client.start();
// Attach local stream to your UI
if (client.localMediaStream) {
const localVideo = document.getElementById('my-video') as HTMLVideoElement;
localVideo.srcObject = client.localMediaStream;
}
});The immediate next steps for Connexify focus on scalability, security, and reliability.
Current State: Mesh Topology (P2P)
Future State: SFU (Selective Forwarding Unit)
We plan to migrate the core media transport to an SFU architecture, likely utilizing Mediasoup or Pion.
- Goal: Enable support for large-scale meetings (10+ participants).
- Benefit: Significantly reduce client-side CPU and bandwidth usage by sending streams once to the server rather than to every peer.
Current State: Global Broadcast
Future State: Strict Room Logic
We will implement strict room management within the signaling-server.
- Goal: Ensure that signaling events (
offer,answer,ice-candidate) are only broadcast to peers within the same specificroomId. - Benefit: Privacy and the ability to host multiple distinct meetings simultaneously on the same server instance.
Current State: alert() and console.log()
Future State: Event-Driven Error System
We will refactor the SDK to remove blocking alerts and implement a robust error event emitter.
- Goal: Allow consuming applications (UI) to gracefully handle failures (e.g., "Camera not found", "Connection failed").
- Benefit: Improved user experience and debuggability in production environments.
