skip to content

With trickle ICE (RFC 8838) in WebRTC, how do candidates travel over the signalling channel, and what must the receiver do with ones arriving early?

level: middleimportance: should knowfreq 22%

answer

  1. don't wait for gathering to end
  2. one message per icecandidate event
  3. candidate line, sdpMid, ufrag
  4. no remote description yet
  5. exactly once, in order

basics

~20 s

The offer goes out at once; each candidate follows as its own message carrying its candidate line, sdpMid and ufrag. The receiver feeds them to addIceCandidate, queueing any that arrive before its remote description is set.

solid answer

~50 s

Without trickle, a peer waits for gathering to finish and puts every candidate in its SDP. With trickle ICE (RFC 8838, advertised by `a=ice-options:trickle`), the offer leaves immediately with zero or a few candidates, and each `icecandidate` event's candidate is sent as its own signalling message: the candidate string, the `sdpMid` or `sdpMLineIndex` naming its `m=` section, and the `usernameFragment` naming its ICE generation. The receiver passes each one to `addIceCandidate`. That call rejects with `InvalidStateError` while `remoteDescription` is null, and candidates can reach a callee that has not applied the offer yet, for instance while it waits for the user to accept, so the receiver buffers them and drains the queue right after `setRemoteDescription`. RFC 8838 requires the channel to deliver every candidate, and the end-of-candidates indication, exactly once and in the order sent. The ufrag lets the agent recognise stale candidates from before an ICE restart.

go deeper

for a junior

Recall that trickle sends the offer immediately and each candidate later as its own message over the signalling channel, where the peer hands it to addIceCandidate.

for a middle

Explain what a candidate message carries (candidate line, sdpMid or index, ufrag) and why early arrivals must be queued until the remote description is set.

for a senior

Show you treat the channel's ordering and exactly-once delivery as requirements, handle stale generations after a restart, and never drop queued candidates silently.

for a principal

Weigh full trickle against waiting for gathering when interoperating with endpoints whose trickle support is unknown, and how signalling design affects setup time.

## Why trickle exists Before two WebRTC peers can exchange media, ICE has to find a working network path between their **candidates** (the addresses each side gathered; what they are and how pairs are checked is ICE's own subject). Gathering can take a while: some candidates need a round trip to a STUN or TURN server. **Trickle ICE** (RFC 8838) stops call setup waiting for that. The description goes out at once, and candidates follow one by one as they are found, so connectivity checks can start as soon as the first candidates are known. | Mode | What the initial description holds | Who can receive it | |---|---|---| | No trickle | every candidate, sent after gathering completes | any ICE agent | | Half trickle | the initiator's full generation of candidates; the responder may still trickle | also regular, non-trickle agents | | Full trickle | any number of candidates, even zero | only trickle-capable agents | Support is advertised in SDP with `a=ice-options:trickle`; RFC 9429 has a JSEP endpoint put it in every initial offer, and in an initial answer when the offer carried it. ## What one trickled candidate carries Each `icecandidate` event on an `RTCPeerConnection` hands the application one `RTCIceCandidate`. The application serialises it and sends it over the same signalling channel as the descriptions. Only four members matter to the receiving `addIceCandidate`: | Member | Purpose | |---|---| | `candidate` | the SDP `candidate-attribute` line, without the `a=` prefix | | `sdpMid` | the MID of the `m=` section the candidate belongs to | | `sdpMLineIndex` | the zero-based index of that section, an alternative to the MID | | `usernameFragment` | the ICE ufrag, naming which **generation** (ICE session) the candidate belongs to | With BUNDLE negotiated, candidates are gathered and sent only for the section whose MID is the BUNDLE tag. ## Receiving: queue until the remote description exists The W3C `addIceCandidate` steps reject with `InvalidStateError` while `remoteDescription` is null, and reject a candidate whose `sdpMid` matches no section of the remote description. A candidate can only be paired once the receiver knows which section and generation it belongs to. Candidates often outrun the description they belong to in practice: the callee may hold the offer unapplied while the user decides whether to answer. The receiving side therefore follows a simple discipline: 1. On a candidate message, if no remote description is set, append it to a queue. 2. Otherwise call `addIceCandidate` at once. 3. Right after `setRemoteDescription` succeeds, drain the queue in arrival order. 4. Never discard a queued candidate silently. A dropped candidate can leave the call stuck on a worse path or unable to connect. ## The delivery contract RFC 8838 puts on your channel RFC 8838 calls the signalling protocol the **using protocol**, and it is the application's. It must: - deliver each trickled candidate **exactly once and in the same order** it was conveyed, hiding any retransmissions from the ICE agent; - let both parties agree which **ICE session** is in force, so delayed candidates from before an ICE restart can be recognised (by their ufrag) and ignored; - carry an **end-of-candidates** indication that names the ICE session it applies to; - give the parties a way to discover trickle support before the session begins (a SHOULD). When gathering for a transport completes, the W3C API fires an `icecandidate` event whose `candidate.candidate` is an empty string. The application forwards that like any other candidate, and the peer's `addIceCandidate` receives it as the end-of-candidates indication. A further event with a `null` candidate exists only for backwards compatibility and need not be sent. ## Common misreadings - **"Trickle means waiting for gathering to finish."** That is the non-trickle mode trickle replaces. - **"The agent buffers early candidates for me."** It rejects them; the queue is the application's. - **"Removing candidates from what I send hides my address."** RFC 9429's security considerations say editing candidates out of SDP or suppressing trickled ones does not stop the agent checking from them. An endpoint that must hide its public address configures the ICE agent to use relay candidates only. - **"Order on the channel is irrelevant."** RFC 8838 makes in-order, exactly-once delivery a MUST for the using protocol.

  • Can a WebRTC peer keep its public address private by not trickling its server-reflexive candidates?
    No. RFC 9429's security considerations say that editing candidates out of the SDP or suppressing trickled ones does not stop the implementation performing checks from them, so the remote peer can still learn the address. An endpoint that must conceal it configures the ICE agent to use relay candidates only.
  • In WebRTC, what happens to a trickled candidate that belongs to an ICE generation abandoned by a restart?
    Its `usernameFragment` names the old generation, so the agent can recognise it as stale and ignore it. RFC 8838 requires the using protocol to let both sides agree on the ICE session in force for exactly this reason; without the ufrag, JSEP assumes the most recently received description.
  • How does a WebRTC application signal that it has no more candidates to trickle?
    When gathering for a transport completes, the W3C API fires an `icecandidate` event whose candidate string is empty. The application forwards it like any candidate, and the peer's `addIceCandidate` treats it as the end-of-candidates indication for that generation. The later event with a `null` candidate is legacy and needs no forwarding.

saying these in an interview costs you the question

  • Trickle ICE means the offer waits until gathering completes.
  • addIceCandidate buffers candidates that arrive before the offer is applied.
  • The STUN server, not the application, delivers trickled candidates.
  • Not sending srflx candidates keeps the public address hidden.
  • Duplicate or reordered candidate messages are harmless to ICE.