If you've ever used a browser-based softphone, a click-to-call widget, or a web-based contact center agent interface, you've used SIP over WebSockets and the browser's real-time media stack together, whether you knew it or not. These two technologies solve complementary halves of the same problem: how do you make a real phone call from inside a web browser?
The answer is more interesting than you might expect, because browsers were never designed for real-time communications. Every piece of this stack exists because of a specific constraint that browsers impose.
The fundamental problem
SIP was designed for a world where endpoints could open UDP or TCP sockets on arbitrary ports. A SIP phone typically listens on UDP port 5060. It sends and receives SIP messages directly. It opens separate UDP ports for RTP media. This is fine for hardware phones and softphone applications running on a desktop operating system.
Browsers can't do any of that.
A web page running in Chrome or Firefox has no ability to open raw UDP or TCP sockets. It can make HTTP requests, open WebSocket connections, and use a handful of other browser APIs, but it cannot send a UDP packet to port 5060 on some SIP server. This is a security feature, not a bug. Letting arbitrary web pages open raw network sockets would be a catastrophe. But it means that traditional SIP transport (UDP, TCP, or TLS over TCP) is completely unavailable from a browser context.
So if you want SIP signaling in a browser, you need a transport that browsers actually support. That transport is WebSockets.
SIP over WebSockets: RFC 7118
RFC 7118, published in 2014, defines how to carry SIP messages over WebSocket connections, registering two transports: plain WebSocket (WS) and secure WebSocket (WSS). The concept is straightforward: the browser opens a WebSocket connection (in practice almost always WSS, the TLS-encrypted variant) to a SIP server that supports WebSocket transport. Once the connection is established, standard SIP messages are sent and received as WebSocket text frames.
The SIP messages themselves are the same SIP messages you'd see on any other transport. A REGISTER is still a REGISTER. An INVITE still contains SDP. The authentication challenges work the same way. The only difference is the transport layer carrying those messages.
A SIP message over WebSocket includes a Via header that indicates the transport:
Via: SIP/2.0/WSS df7jal23ls0d.invalid;branch=z9hG4bK56sdasks
That WSS tells every SIP entity in the path that this message arrived via a secure WebSocket connection. The domain in the Via header is typically a random identifier rather than a real hostname, since the browser doesn't have a routable address where it can receive inbound connections.
This is an important difference from traditional SIP. A desk phone has an IP address and a port. You can send it a SIP message at any time. A browser-based client is reachable only through its WebSocket connection to the server. The server acts as the anchor point, maintaining that persistent connection and routing messages to the browser through it.
How the browser's media stack fits in
SIP over WebSockets solves the signaling problem, but signaling is only half of a phone call. The other half is the actual audio. You need a way to capture audio from the user's microphone, encode it, encrypt it, send it across the network in real time, receive audio from the other party, decode it, and play it through the speakers. All with latency low enough for a conversation to feel natural.
This is what the browser's real-time media stack does.
Every modern browser ships one: a standardized API and protocol suite for capturing, encoding, encrypting, and transporting live audio and video. When a browser-based softphone places a call, SIP over WebSockets handles the call setup and teardown, while that stack handles everything about the actual audio stream.
The two are connected through SDP. When the browser's SIP stack sends an INVITE, the SDP body is generated by the browser's media engine. That SDP contains the media parameters that engine will use: codecs, ICE candidates for NAT traversal, DTLS fingerprints for encryption, and the ports where the browser wants to receive media.
Here's a simplified view of what the SDP in a browser-originated INVITE looks like:
v=0
o=- 4858522468 2 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE audio
m=audio 9 UDP/TLS/RTP/SAVPF 111 0 8
c=IN IP4 0.0.0.0
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=ice-ufrag:aR9l
a=ice-pwd:fE82jkS03bq1mMdoZ8Gy6f
a=fingerprint:sha-256 D1:2B:3C:...
a=setup:actpass
a=candidate:1 1 udp 2113937151 192.168.1.50 54321 typ host
a=candidate:2 1 udp 1845501695 203.0.113.50 62432 typ srflx raddr 192.168.1.50 rport 54321
A few things stand out compared to traditional SIP SDP. The media line specifies UDP/TLS/RTP/SAVPF rather than plain RTP/AVP, because browser media mandates encryption via DTLS-SRTP. The ICE candidates appear directly in the SDP (or are trickled in afterward). The a=fingerprint line provides the DTLS certificate fingerprint for end-to-end encryption verification. And the first codec listed is almost always Opus.
How a browser-based call actually flows
Let's trace a complete call from a browser-based softphone to a traditional SIP desk phone. This involves several systems working together.
1. WebSocket connection and registration
When the web softphone loads, it opens a WSS connection to the SIP server (e.g., wss://sip.example.com/ws). Over this connection, it sends a SIP REGISTER to authenticate and announce its presence:
REGISTER sip:example.com SIP/2.0
Via: SIP/2.0/WSS j4k8s9d2f.invalid;branch=z9hG4bK74bf9
Contact: <sip:[email protected];transport=ws>
Authorization: Digest username="alice", ...
The server authenticates the request and responds with 200 OK. Alice's browser is now registered and can make and receive calls.
2. The INVITE
Alice clicks a button to call Bob. The browser's SIP library creates a peer connection, generates an SDP offer from the browser's media engine, wraps it in a SIP INVITE, and sends it over the WebSocket:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/WSS j4k8s9d2f.invalid;branch=z9hG4bKnew1
Contact: <sip:[email protected];transport=ws>
Content-Type: application/sdp
[Browser-generated SDP with ICE candidates, DTLS fingerprint, Opus codec]
3. The gateway problem
If Bob is on a traditional desk phone, there's a mismatch. The browser is offering browser-style media (Opus, DTLS-SRTP, ICE), and Bob's phone expects traditional RTP (G.711, SRTP or plain RTP, no ICE). Something needs to bridge that gap.
This is where Session Border Controllers (SBCs) and browser-calling gateways come in. The SIP server or an SBC in the path terminates the browser media session on one side and establishes a traditional RTP session on the other. It transcodes Opus to G.711, terminates DTLS-SRTP and re-encrypts (or doesn't) as SRTP or plain RTP, and handles the ICE negotiation on the browser side while using a simple static media address toward the desk phone.
4. Media flows
Once the call is established (200 OK, ACK), audio flows. On the browser side, the media stack handles everything: ICE connectivity checks complete, the DTLS handshake establishes encryption keys, and SRTP audio packets start flowing directly between the browser and the SBC or media gateway. On the desk phone side, standard RTP flows as it always has.
5. Hangup
Either side sends a BYE through the signaling path. The browser sends it over WebSocket, the desk phone sends it over UDP or TCP. The gateway handles the translation in both directions.
Browser SIP stacks
You don't implement SIP over WebSockets from scratch. Several mature JavaScript libraries handle the SIP protocol and its integration with the browser's media stack:
JsSIP is one of the original browser SIP stacks, lightweight and focused on the core SIP functionality. It handles SIP message parsing, transaction management, dialog management, and media session integration. It's been around since the early days of browser calling and is well-understood.
SIP.js is a more actively maintained library with a cleaner API and better TypeScript support. It abstracts more of the complexity of coordinating SIP signaling with browser media, making it the more common choice for new projects.
Both libraries handle the same fundamental task: they manage the SIP state machine (registrations, sessions, subscriptions) and coordinate with the browser's media API to generate SDP, handle ICE candidates, and manage the media session lifecycle. They send and receive SIP messages over a WebSocket connection and translate between SIP session events and peer connection state.
There are also commercial SDKs from VoIP platform providers that wrap these open-source libraries with additional features like call queuing, presence, and analytics.
Session Border Controllers and browser-calling gateways
In practice, browser-based SIP clients rarely talk directly to a traditional SIP PBX. There's usually a browser-aware component in the path, either a standalone browser-calling gateway or an SBC with browser support built in.
This component does several things:
- Transport translation: Converts between SIP over WebSocket and SIP over UDP/TCP/TLS for communication with traditional SIP infrastructure.
- Media bridging: Terminates browser media (ICE, DTLS-SRTP, Opus) on one side and establishes traditional RTP sessions on the other.
- Codec transcoding: Converts between Opus and G.711/G.729 when necessary.
- ICE handling: Participates in ICE negotiation with the browser, acting as the media endpoint that the browser's media engine connects to.
Major SBC vendors (AudioCodes, Oracle, Ribbon) all support browser endpoints now. Open-source options like Asterisk with its built-in browser support, or Kamailio with the WebSocket module, provide the same functionality. FreeSWITCH has supported browser media for years and is commonly deployed as a browser-calling gateway.
NAT traversal: how browser calling changes everything
One of the most painful aspects of traditional SIP is NAT traversal. SIP embeds IP addresses inside message bodies and headers, and NAT devices don't rewrite those embedded addresses, leading to one-way audio, registration failures, and hours of troubleshooting.
The browser stack sidesteps this problem almost entirely by building ICE (Interactive Connectivity Establishment) into the core protocol. ICE is mandatory there, not optional. Every browser media session uses it.
Here's how it works in the browser context:
- The browser gathers its local network interface addresses (host candidates).
- It queries a STUN server to discover its public-facing address (server-reflexive candidates).
- If configured, it allocates a relay address on a TURN server (relay candidates).
- All of these candidates are included in the SDP (or sent as trickle candidates).
- Both sides perform connectivity checks by sending STUN binding requests on each candidate pair.
- The pair that works best is selected for media.
Because ICE tests actual connectivity before sending media, it doesn't matter what NAT type is between the browser and the network. If direct connectivity works, ICE will find it. If it doesn't, ICE falls back to TURN relay. This is a fundamentally more robust approach than the traditional SIP methods of STUN-based address discovery or SIP ALGs, which guess at what might work based on incomplete information.
The result is that browser-based VoIP calls have far fewer NAT-related audio problems than traditional SIP deployments. The one common exception is corporate networks that block UDP entirely or restrict TURN traffic, which can prevent browser media from flowing at all.
Quality considerations
RFC 7874 requires browser real-time audio endpoints to implement Opus along with G.711 (PCMU and PCMA); so Opus is mandatory to implement, not mandatory on every negotiated call, but browser-to-browser and browser-to-gateway calls almost always pick it. Opus operates at up to a 48 kHz sample rate and supports everything from narrowband to fullband audio. Compared to the G.711 (narrowband, 8 kHz, 64 kbps) that dominates traditional VoIP, Opus sounds dramatically better. It's also far more bandwidth-efficient, the same audio quality can be achieved at lower bitrates, and it adapts dynamically to network conditions by adjusting bitrate, frame size, and complexity in real time.
This adaptability is one of the browser stack's under-appreciated strengths. When network conditions degrade, the Opus encoder reduces its bitrate before packets start getting dropped. The stack also includes built-in bandwidth estimation (REMB or Transport-CC) that continuously measures the available network capacity and feeds that information back to the encoder.
That said, browser-based VoIP introduces its own quality variables. The browser shares the network stack with everything else the user is doing. Background tabs downloading files, OS updates, other applications competing for bandwidth, all of these affect the browser's media stream. And WiFi adds latency and jitter that a wired desk phone on a properly configured VLAN would never see.
The codec advantage and the network disadvantage roughly cancel out for many deployments. Browser-based calls on a stable network sound better than desk phones. Browser-based calls on congested WiFi can sound worse.
Where this is headed
The browser media stack has effectively won the browser and mobile client battle. Every major UCaaS and CCaaS platform (Webex, Zoom, RingCentral, Genesys, Five9) uses it for browser-based and increasingly for native desktop and mobile clients too. The traditional SIP desk phone isn't disappearing from conference rooms and front desks anytime soon, but new endpoints are overwhelmingly browser-based.
SIP over WebSockets remains the most common signaling mechanism for these browser clients, though some platforms have moved to proprietary signaling over REST or gRPC. The SIP/WS + browser media combination has the advantage of interoperability. A browser client using SIP.js talking to a FreeSWITCH server can interoperate with any SIP-compliant PBX, trunk provider, or carrier. Proprietary signaling locks you into a single platform.
The trend is clear: the browser is becoming the default softphone, and SIP over WebSockets is the bridge that connects it to the existing telephone network.
For the traditional SIP fundamentals that underpin browser-based VoIP, see What SIP Actually Is and Your First Call Flow: INVITE to BYE. For the NAT traversal problems that the browser's mandatory-ICE approach largely eliminates, see NAT Traversal: Why SIP and NAT Don't Get Along. For more on how SDP and codec negotiation work, see SDP and Media Negotiation. And if you're running browser-based softphones on WiFi, Wired vs. WiFi for VoIP covers the quality implications.
Frequently Asked Questions
How does SIP work in a web browser?+
Browsers cannot send raw UDP or TCP to arbitrary ports, so SIP messages are carried over a WebSocket connection (in practice the secure WSS variant) to a SIP server. The browser opens a secure WebSocket connection, then sends and receives standard SIP messages as WebSocket text frames. The media (actual audio) is handled separately by the browser's built-in real-time media stack.
What is the relationship between SIP and the browser's media stack?+
In browser-based VoIP, SIP over WebSockets handles the signaling (setting up, modifying, and tearing down calls), while the browser's real-time media stack handles the media (encoding, encrypting, and transporting audio and video). SIP carries the call control, and the SDP within SIP messages describes those media parameters, including ICE candidates for NAT traversal.
Do browser-based VoIP calls sound as good as desk phones?+
Often better. Browser real-time media endpoints are required to implement the Opus codec (RFC 7874), and browser calls usually negotiate it. Opus is wideband and adapts dynamically to network conditions, while most desk phones use narrowband G.711 or G.729. The main quality variable for browser calls is the user's network and whether they are on WiFi, not the technology itself. Run a VoIP quality test to verify your network can support real-time media.
Share
Want to know when we publish new articles? Sign up for updates