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

Last updated: March 6, 2026