v148 · WebRTC · demo
Negotiation Modes Comparison
Code and SDP output side by side — see how alwaysNegotiateDataChannels changes the offer SDP and what that means for timing safety.
Default — on-demand negotiation
JavaScript
// Default: no special option const pc = new RTCPeerConnection({ iceServers: [...] }); // createDataChannel() must be called // BEFORE createOffer() for the channel // to appear in the SDP offer. // ↑ timing-sensitive! const dc = pc.createDataChannel('chat'); const offer = await pc.createOffer();
SDP offer (excerpt)
m=application 9 UDP/DTLS/SCTP webrtc-datachannel a=sctp-port:5000 a=max-message-size:262144 ↑ Present only because createDataChannel() was called before createOffer()
Race condition risk: HIGH
If createDataChannel() is called after
createOffer(), data channel is NOT in SDP.
A renegotiation must then occur.
If createDataChannel() is called after
createOffer(), data channel is NOT in SDP.
A renegotiation must then occur.
Chrome 148+ — always negotiated
JavaScript
// Chrome 148+: pre-include data channel const pc = new RTCPeerConnection({ iceServers: [...], alwaysNegotiateDataChannels: true, }); // createDataChannel() can be called at // ANY point — before OR after createOffer() // without triggering renegotiation. const offer = await pc.createOffer(); // ↑ already includes m=application const dc = pc.createDataChannel('chat');
SDP offer (excerpt)
m=application 9 UDP/DTLS/SCTP webrtc-datachannel a=sctp-port:5000 a=max-message-size:262144 ↑ Always present regardless of when (or whether) createDataChannel() is called
Race condition risk: NONE
Data channel section is in every offer
unconditionally. createDataChannel() can
be called freely, any time.
Data channel section is in every offer
unconditionally. createDataChannel() can
be called freely, any time.
Key differences
| Behaviour | Default | alwaysNegotiateDataChannels: true |
|---|---|---|
| m=application in offer | Only if createDataChannel() called first | Always included |
| createDataChannel() timing | Must precede createOffer() | Any time — before or after |
| Late createDataChannel() | Triggers renegotiation | No renegotiation needed |
| SDP size | Smaller if no channel needed | Slightly larger (always has m=application) |
see also
- Connection Timeline Walkthrough — animated signaling flow
- Back to feature index
- ChromeStatus entry
scenario focus
Select a scenario to focus its rendered example and summary.
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗