WHIP (WebRTC-HTTP Ingestion Protocol)
WHIP (WebRTC-HTTP Ingestion Protocol) is a standard HTTP-based signaling protocol for ingesting live media into WebRTC endpoints. Instead of requiring a custom WebSocket or proprietary signaling server, WHIP uses three HTTP Methods (POST to create a session, PATCH to update ICE candidates, and DELETE to terminate), making WebRTC ingestion as simple as pointing an encoder at a URL with a stream key.
Usage
WebRTC provides the transport layer for real-time media (ICE, DTLS, SRTP) but deliberately leaves signaling unspecified. Every WebRTC deployment builds a custom signaling mechanism, typically a WebSocket server exchanging SDP offers and answers between peers. This fragmentation prevents interoperability between encoders and media platforms.
WHIP standardizes the signaling for unidirectional media ingestion (encoder to server). A WHIP-compliant encoder sends an SDP offer via HTTP POST, receives an SDP answer in the Response, and begins Streaming. The entire session lifecycle maps to standard HTTP semantics, working with existing load balancers, CDN infrastructure, and Authentication proxies.
The model resembles RTMP ingest (a URL plus a stream key) but with WebRTC's sub-second latency instead of RTMP's multi-second delay. OBS Studio, GStreamer, Cloudflare Stream, LiveKit, and other tools and platforms support WHIP natively.
Ingest only
WHIP handles the ingest direction (encoder to server). The playback direction (server to viewer) is addressed by WHEP (WebRTC-HTTP Egress Protocol), a companion protocol from the same IETF working group currently in draft status.
How WHIP works
Session creation
The WHIP client sends an HTTP POST to the
WHIP endpoint URL with an SDP offer in the
Request body. The
Content-Type is application/sdp.
POST /whip/endpoint HTTP/1.1
Host: whip.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=sendonly
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=sendonly
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=sendonly, meaning the
client sends media, not receives. The max-bundle
policy is
mandatory, requiring a=rtcp-mux-only on every
media section. A single MediaStream with at most one
audio and one video track is allowed.
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://whip.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=recvonly
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=recvonly
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 WHIP session URL. All subsequent operations (Trickle ICE, ICE restart, termination) target this URL. The ETag header identifies the current ICE session for conditional updates.
Link headers with rel="ice-server" provide
STUN and TURN server configuration. TURN entries
include username and credential attributes for
authentication. The server gathers all ICE
candidates before responding, with no server-side
trickle.
Trickle ICE
After receiving the 201 response, the client
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: whip.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.
Clients 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 client 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: whip.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.
If the restart fails, the server returns an error but does not terminate the session. Existing ICE connectivity continues. The client retries or sends a DELETE to end the session.
Session termination
The client terminates the session with HTTP DELETE on the session URL:
DELETE /session/abc123 HTTP/1.1
Host: whip.example.re
HTTP/1.1 200 OK
This frees all server resources and terminates the ICE and DTLS sessions. For server-initiated termination, the server revokes STUN consent, causing the client-side ICE agent to detect the loss.
Headers
WHIP uses standard HTTP headers throughout:
| Header | Direction | Purpose |
|---|---|---|
| Content-Type | Both | application/sdp or application/trickle-ice-sdpfrag |
| Location | Response | WHIP 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) |
| Accept-Patch | Response | application/trickle-ice-sdpfrag |
| Retry-After | Response | Wait time when server returns 503 |
Status codes
| Code | Context |
|---|---|
| 201 Created | Session created successfully |
| 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 |
| 405 Method Not Allowed | Trickle ICE not supported |
| 412 Precondition Failed | ETag mismatch |
| 422 Unprocessable Content | Unsupported configuration |
| 428 Precondition Required | Missing If-Match |
| 503 Service Unavailable | Server overloaded |
WHIP 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. Platforms provide the WHIP endpoint URL and a stream key or token through their dashboard, similar to RTMP ingest credentials. Tokens are JWTs, shared secrets, or URL-embedded values depending on the platform.
HTTPS is mandatory for all WHIP communication.
Extensions
WHIP supports protocol extensions discovered through
Link headers in the 201 response:
Link: <https://whip.example.re/session/abc123/layer>; rel="urn:ietf:params:whip:ext:example:simulcast"
Extension rel values use the
urn:ietf:params:whip:ext namespace. IANA maintains
a registry of WHIP extension URNs. Clients ignore
unknown extensions, and servers do not require
extensions for basic operation.
CORS
WHIP endpoints support CORS to enable
browser-based encoders. The OPTIONS
preflight response includes
Accept-Post: application/sdp. STUN/TURN server
configuration is not included in preflight responses
to avoid latency from external ICE server lookups.
Example
A complete WHIP session lifecycle: creating a stream, sending ICE candidates, and stopping the broadcast.
1. Create session
POST /whip/live HTTP/1.1
Host: whip.example.re
Authorization: Bearer stream-key-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=sendonly
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://whip.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=recvonly
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: whip.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. End broadcast
DELETE /session/s7k2m HTTP/1.1
Host: whip.example.re
HTTP/1.1 200 OK
The encoder (OBS Studio, a browser, or a hardware device) streams live video to the media server for the duration of the session. Viewers receive the stream through a separate distribution mechanism (WHEP, HLS, DASH, or a proprietary player).
Takeaway
WHIP replaces custom WebRTC signaling with standard HTTP Methods: POST to create a session with an SDP exchange, PATCH for Trickle ICE and ICE restarts, and DELETE to terminate. The protocol makes WebRTC media ingestion interoperable across encoders and platforms, bringing RTMP-like simplicity to sub-second latency live streaming.
See also
- RFC 9725: WebRTC-HTTP Ingestion Protocol (WHIP)
- RFC 8840: A Session Initiation Protocol (SIP) Usage for Incremental Provisioning of Candidates for the Interactive Connectivity Establishment (Trickle ICE)
- RFC 8445: Interactive Connectivity Establishment (ICE)
- RFC 9429: JavaScript Session Establishment Protocol (JSEP)
- WebSocket
- HTTP Streaming
- Authentication
- HTTPS
- CORS
- HTTP headers