Documentation | Issues | Discord
PulseBeam is an open source, general-purpose WebRTC SFU server for connecting browsers, mobile, and IoT clients. We believe real-time application development shouldn't be complicated, nor should it rely on heavy architectures with many moving parts. PulseBeam reduces this friction by adhering to these core design goals:
- Support all WebRTC clients.
- Keep the architecture simple, but not simpler.
- Natively support vertical and horizontal scaling.
- Provide client SDKs strictly for convenience, not necessity.
- Require minimal configuration.
If your client device speaks WebRTC, it can communicate with PulseBeam.
- CPU induced p99 jitter: <2ms
PulseBeam is opinionated about media handling to prioritize battery efficiency, hardware support, and predictable performance:
- Video: H.264 Baseline profile up to Level 4.1
- Audio: Opus
- Data Channel: Planned
This is a thread-per-core system that isolates the data plane from the control plane. It follows a shared-nothing design, keeping the fast path lock-free and cache-local.
Bazel owns compilation, dependency/tool provisioning, generated bindings, checks, and tests. Normal development and browser acceptance support Linux x86_64. Install the baseline OS prerequisites, then:
./bazel test //:fast # Static checks and fast tests
./bazel test //:test # Complete non-privileged acceptance
./bazel build //:server //:native //:web //:react //:meet //:docsThe checksum-verified launcher bootstraps the pinned Bazel version. Bazel supplies Rust 1.92.0, native compilation tools, Node/pnpm, matching WASM generators/runtime, protobuf, Go, Python, and the pinned Chrome/Firefox executables and drivers. Initial downloads require network access; tests use local application fixtures. No pre-existing language/browser cache or independent tool installation is required.
See build and development, editor-neutral LSP setup, and distribution. Cargo/pnpm metadata remains authoritative for dependencies and editor maintenance, not a supported parallel build/test workflow.
The following quickstart assumes that you have a Linux machine. As a fallback, you can go to https://pulsebeam.dev/#quickstart and check the "fallback" toggle.
Docker/Podman (recommended):
docker run --rm --net=host ghcr.io/pulsebeamdev/pulsebeam:pulsebeam-v0.4.5 --devOpen Port Requirements:
- TCP/7070: HTTP signaling
- TCP/6060: Internal CPU & Memory profilers
- UDP/3478: WebRTC traffic (Multiplexed)
- TCP/3478: WebRTC over TCP fallback (Multiplexed)
Note: The
--devflag used above configures PulseBeam to use port 3478 to avoid requiring root privileges. In production (running without--dev), WebRTC traffic defaults to standard port 443 (UDP/TCP).
Other options:
- Binary: download from Releases
- Source:
./bazel run --config=release //:server -- --dev
Mint a development token, then paste it into the browser-console snippet below:
./bazel run //:cli -- token --room demo --participant publisherconst token = "paste the development token here";
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const transceiver = pc.addTransceiver("video", {
direction: "sendonly",
// Define scalability layers (low, medium, high)
sendEncodings: [
{ rid: "q", scaleResolutionDownBy: 4, maxBitrate: 150_000 },
{ rid: "h", scaleResolutionDownBy: 2, maxBitrate: 400_000 },
{ rid: "f", scaleResolutionDownBy: 1, maxBitrate: 1_250_000 },
],
});
transceiver.sender.replaceTrack(stream.getVideoTracks()[0]);
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
if (pc.iceGatheringState !== "complete") {
await new Promise((resolve) => {
pc.addEventListener("icegatheringstatechange", function gathered() {
if (pc.iceGatheringState === "complete") {
pc.removeEventListener("icegatheringstatechange", gathered);
resolve();
}
});
});
}
// WHIP publishes media without the native protobuf signaling channel.
const res = await fetch("http://localhost:7070/api/v1/whip", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/sdp",
},
body: pc.localDescription.sdp,
});
if (res.status !== 201) throw new Error(await res.text());
await pc.setRemoteDescription({ type: "answer", sdp: await res.text() });Mint a second token with a distinct participant and connect another client to
the same demo room.
Mint participant tokens locally with explicit project ID, API key ID, signing secret, room/participant external IDs, and mandatory absolute Unix expiration:
- TypeScript / Node.js:
@pulsebeam/server - Go:
github.com/PulseBeamDev/pulsebeam/server/go - Python:
pulsebeam-server - Rust:
pulsebeam-server
These server-only SDKs use native Ed25519, with no PulseBeam connectivity or Rust/WASM runtime. Keep signing secrets on your server, never in client code. The packages are locally installable; public registry publication is deferred. Their shared auth profile and vectors are exercised by the ordinary Bazel acceptance gates and the Rust authorization verifier.
PulseBeam exposes an internal debug HTTP server on http://localhost:6060.
- Metrics (Prometheus):
http://localhost:6060/metrics - CPU profile (pprof):
http://localhost:6060/debug/pprof/profile?seconds=30 - CPU flamegraph:
http://localhost:6060/debug/pprof/profile?seconds=30&flamegraph=true - Memory profile:
http://localhost:6060/debug/pprof/allocs
CPU profiling measures CPU usage, not wall time. For meaningful results, profile while the server is under load.
View CPU profiles with:
./bazel run @rules_go//go -- tool pprof -http=:8080 cpu.pprofOr view as a flamegraph on a browser by specifying flamegraph=true to the URL query.
You can view the full roadmap here.
