WHEP (WebRTC-HTTP Egress Protocol)
Watching a WebRTC stream traditionally means building custom signaling for every player. WHEP (WebRTC-HTTP Egress Protocol) standardizes the playback side using standard HTTP Methods, where a viewer sends an SDP offer via POST, receives an SDP answer and a session URL, and ends playback with DELETE. It is the egress counterpart to WHIP, which handles ingestion.
Draft specification
WHEP is defined by the IETF WISH working group
Internet-Draft draft-ietf-wish-whep, intended as a
Proposed Standard. The latest revision has expired and
the working group has it under revision, so specific
details may shift before publication as an RFC. The
protocol is already widely implemented. Track the
current revision through the link in See also.
Usage
WHEP standardizes the signaling for media egress, the path from a media server to a viewer. WebRTC supplies the transport (ICE, DTLS, SRTP) but leaves signaling undefined, so every player integration historically built its own SDP exchange over WebSocket or a vendor API. That fragmentation blocked interoperability between streaming services and the devices playing their content.
A WHEP player sends an SDP offer via HTTP POST, receives an SDP answer in the Response, and begins Streaming with sub-second latency. The session lifecycle maps to standard HTTP semantics, so it works with existing load balancers, CDN infrastructure, and Authentication proxies. The same approach makes WHEP suitable for devices that run no custom JavaScript, such as smart TVs and set-top boxes.
WHEP mirrors the design of WHIP for the opposite
direction. WHIP ingests media from an encoder into a
server. WHEP delivers media from a server to a player.
The two share the same HTTP method flow, the same
Link header mechanism for ICE servers, and the same
bearer-token authentication, which lets a single platform
expose both ingest and playback over one consistent API.
Egress only
WHEP handles the egress direction (server to viewer). The ingest direction (encoder to server) is addressed by WHIP, a companion protocol from the same IETF working group, published as an RFC.
How WHEP works
Session creation
The WHEP player sends an HTTP POST to the WHEP
endpoint URL with an SDP offer in the Request body.
The Content-Type is application/sdp.
POST /whep/endpoint HTTP/1.1
Host: whep.example.re
Authorization: Bearer eyJhbGciOiJIUz...
Content-Type: application/sdp
v=0
o=- 5228595038118931041 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=ice-options:trickle ice2
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:0
a=recvonly
a=rtcp-mux-only
a=rtpmap:111 opus/48000/2
a=ice-ufrag:EsAw
a=ice-pwd:bP+XJMM09aR8AiX1jdukzR6Y
a=fingerprint:sha-256 DA:7B:57:DC:28:CE:04...
a=setup:actpass
m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:1
a=recvonly
a=rtcp-mux-only
a=rtpmap:96 VP8/90000
a=ice-ufrag:EsAw
a=ice-pwd:bP+XJMM09aR8AiX1jdukzR6Y
a=fingerprint:sha-256 DA:7B:57:DC:28:CE:04...
a=setup:actpass
The SDP offer uses a=recvonly, meaning the player
receives media rather than sends it. This is the main
distinction from WHIP, where the encoder offers
a=sendonly. A WHEP player may offer a=sendrecv when it
also returns audio or video, though playback-only viewers
use recvonly.
The server responds with 201 Created, an SDP answer in the body, and a Location header pointing to the newly created session resource:
HTTP/1.1 201 Created
Content-Type: application/sdp
Location: https://whep.example.re/session/abc123
ETag: "xyzzy"
Link: <stun:stun.example.re>; rel="ice-server"
Link: <turn:turn.example.re?transport=udp>; rel="ice-server"; username="user"; credential="pass"
v=0
o=- 1657793490019 1 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=ice-lite
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:0
a=sendonly
a=rtcp-mux-only
a=rtpmap:111 opus/48000/2
a=ice-ufrag:38sdf4fdsf54
a=ice-pwd:2e13dde17c1cb009202f627fab90cbec
a=candidate:1 1 UDP 2130706431
198.51.100.1 39132 typ host
a=fingerprint:sha-256 F7:EB:F3:3E:AC:D2...
a=setup:passive
m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:1
a=sendonly
a=rtcp-mux-only
a=rtpmap:96 VP8/90000
a=ice-ufrag:38sdf4fdsf54
a=ice-pwd:2e13dde17c1cb009202f627fab90cbec
a=candidate:1 1 UDP 2130706431
198.51.100.1 39132 typ host
a=fingerprint:sha-256 F7:EB:F3:3E:AC:D2...
a=setup:passive
The Location header URL becomes the WHEP session URL. All subsequent operations (Trickle ICE, ICE restart, termination) target this URL. The ETag header identifies the current ICE session for conditional updates and is present when the server supports ICE restarts.
Link headers with rel="ice-server" provide STUN and
TURN server configuration. TURN entries carry username
and credential attributes for authentication.
Server-offered playback
WHEP also supports a mode where the server provides the SDP offer. When a player POSTs an offer the server cannot satisfy, the server returns 406 Not Acceptable and supplies its own SDP offer instead. The player then processes that offer and returns an answer. A compliant WHEP player supports both receiving an SDP answer to its own offer and receiving an SDP offer from the server.
Trickle ICE
After receiving the 201 response, the player sends
newly gathered ICE candidates to the server via HTTP
PATCH on the session URL. The
Content-Type is
application/trickle-ice-sdpfrag.
PATCH /session/abc123 HTTP/1.1
Host: whep.example.re
If-Match: "xyzzy"
Content-Type: application/trickle-ice-sdpfrag
a=ice-ufrag:EsAw
a=ice-pwd:bP+XJMM09aR8AiX1jdukzR6Y
m=audio 9 RTP/AVP 0
a=mid:0
a=candidate:1 1 UDP 2130706431
203.0.113.1 9 typ host
a=end-of-candidates
The If-Match header carries the ETag from the 201 response, binding the update to the correct ICE session. The server returns 204 No Content on success.
Players buffer candidates gathered before the 201
response arrives and send them in a single aggregated
PATCH. The a=end-of-candidates attribute
signals gathering is complete.
ICE restart
When connectivity degrades, the player requests an ICE
restart by sending a PATCH with If-Match: "*"
(a wildcard indicating a restart rather than a regular
candidate update):
PATCH /session/abc123 HTTP/1.1
Host: whep.example.re
If-Match: "*"
Content-Type: application/trickle-ice-sdpfrag
a=ice-ufrag:ysXw
a=ice-pwd:vw5LmwG4y/e6dPP/zAP9Gp5k
m=audio 9 RTP/AVP 0
a=mid:0
a=candidate:1 1 UDP 2130706431
203.0.113.1 9 typ host
The server responds with 200 and a new SDP fragment containing fresh ICE credentials and candidates. A new ETag identifies the restarted session. Both sides discard old candidates and use the new set exclusively.
Session termination
The player ends playback with HTTP DELETE on the session URL:
DELETE /session/abc123 HTTP/1.1
Host: whep.example.re
HTTP/1.1 200 OK
This removes the WHEP session and frees all server resources, terminating the ICE and DTLS sessions.
Headers
WHEP uses standard HTTP headers throughout:
| Header | Direction | Purpose |
|---|---|---|
| Content-Type | Both | application/sdp or application/trickle-ice-sdpfrag |
| Location | Response | WHEP session URL (201 response) |
| ETag | Response | ICE session identifier |
| If-Match | Request | ETag validation on PATCH |
| Authorization | Request | Bearer token for Authentication |
| Link | Response | STUN/TURN servers (rel="ice-server") and extensions |
| Accept-Post | Response | application/sdp (on OPTIONS) |
| Retry-After | Response | Wait time when server returns 503 |
Status codes
| Code | Context |
|---|---|
| 201 Created | Session created, SDP answer returned |
| 200 OK | ICE restart response or session deleted |
| 204 No Content | Trickle ICE candidates accepted |
| 307 Temporary Redirect | Load balancing to another server |
| 400 Bad Request | Malformed SDP |
| 406 Not Acceptable | Server returns its own SDP offer |
| 412 Precondition Failed | ETag mismatch |
| 422 Unprocessable Content | Trickle ICE or ICE restart not supported |
| 503 Service Unavailable | Server overloaded |
WHEP endpoints use 307 for redirects (not 301 or 302) to preserve the POST method and body across the redirect.
Authentication
Bearer token Authentication is the mandatory-to-implement mechanism. The token is sent in the Authorization header on every Request except CORS preflight:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Token distribution is out of scope for the protocol. Platforms provide the WHEP endpoint URL and a token through their dashboard or a content entitlement service. Tokens are JWTs, shared secrets, or URL-embedded values depending on the platform. HTTPS is required for all WHEP communication to preserve the WebRTC security model.
Extensions
WHEP supports protocol extensions discovered through
Link headers in the 201 response. Extension
rel values use the urn:ietf:params:whep:ext namespace,
and IANA maintains a registry of WHEP extension URNs.
Common extensions cover server-sent events for stream
status, video layer selection for bandwidth adaptation,
and playback control for time-shifted content. Players
ignore unknown extensions, and servers do not require
extensions for basic playback.
Example
A complete WHEP playback session: starting playback, sending ICE candidates, and stopping.
1. Start playback
POST /whep/live HTTP/1.1
Host: whep.example.re
Authorization: Bearer viewer-token-abc123
Content-Type: application/sdp
v=0
o=- 0 0 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=ice-options:trickle
m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:0
a=recvonly
a=rtcp-mux-only
a=rtpmap:96 H264/90000
a=ice-ufrag:abcd
a=ice-pwd:efghijklmnopqrstuvwx
a=fingerprint:sha-256 AA:BB:CC:DD:EE:FF...
a=setup:actpass
HTTP/1.1 201 Created
Location: https://whep.example.re/session/s7k2m
ETag: "v1"
Content-Type: application/sdp
Link: <stun:stun.example.re>; rel="ice-server"
v=0
o=- 1 1 IN IP4 198.51.100.1
s=-
t=0 0
a=group:BUNDLE 0
a=ice-lite
m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:0
a=sendonly
a=rtcp-mux-only
a=rtpmap:96 H264/90000
a=ice-ufrag:wxyz
a=ice-pwd:1234567890abcdef
a=candidate:1 1 UDP 2130706431
198.51.100.1 10000 typ host
a=fingerprint:sha-256 11:22:33:44:55:66...
a=setup:passive
2. Send ICE candidates
PATCH /session/s7k2m HTTP/1.1
Host: whep.example.re
If-Match: "v1"
Content-Type: application/trickle-ice-sdpfrag
a=ice-ufrag:abcd
a=ice-pwd:efghijklmnopqrstuvwx
m=video 9 RTP/AVP 0
a=mid:0
a=candidate:1 1 UDP 2130706431
203.0.113.5 50000 typ host
a=end-of-candidates
HTTP/1.1 204 No Content
3. Media flows via WebRTC (ICE, DTLS, SRTP)
4. Stop playback
DELETE /session/s7k2m HTTP/1.1
Host: whep.example.re
HTTP/1.1 200 OK
The player (a browser, a smart TV app, or a hardware device) receives live media from the server for the duration of the session. The matching ingest side, where an encoder feeds the server, is handled by WHIP.
See also
- WebRTC-HTTP Egress Protocol (draft-ietf-wish-whep)
- RFC 9725: WebRTC-HTTP Ingestion Protocol (WHIP)
- RFC 8840: Trickle ICE for SDP
- RFC 8445: Interactive Connectivity Establishment (ICE)
- RFC 9429: JavaScript Session Establishment Protocol (JSEP)
- WHIP
- HTTP streaming
- Authentication
- HTTPS
- CORS
- HTTP headers