v148 · webrtc · web api · shipped
WebRTC Datachannel: Always negotiate data channels
A new alwaysNegotiateDataChannels option for RTCPeerConnection that pre-negotiates the application m-section in SDP offers, allowing either endpoint to call createDataChannel() later without a full SDP renegotiation. Ships in Chrome 148 on all platforms.
at a glance
| Shipped in | Chrome 148 (desktop, Android, WebView) |
|---|---|
| Status | Enabled by default |
| Spec | WebRTC Extensions — Always negotiating datachannels |
| ChromeStatus | 5113419982307328 — WebRTC Datachannel: Always negotiate data channels |
background: the SDP data channel problem
In WebRTC, data channels use SCTP over DTLS, negotiated via an application m-section in SDP. The problem: an application m-section only appears in the SDP offer if createDataChannel() has already been called on that connection. This creates a chicken-and-egg situation:
- If only one side calls
createDataChannel()before the initial offer/answer, the other side can receive data channels viaondatachannel. - If neither side calls
createDataChannel()before the offer, no application m-section is negotiated. Adding a data channel later requires a full SDP renegotiation.
For many applications — particularly those that conditionally open data channels based on user action — this means an extra round-trip of renegotiation just to establish a data channel.
the new option: alwaysNegotiateDataChannels
Setting alwaysNegotiateDataChannels: true in the RTCPeerConnection constructor makes Chrome include the application m-section in SDP offers from the start — even before any createDataChannel() call. This means:
- Either endpoint can call
createDataChannel()any time after the connection is established, without renegotiation. - The remote endpoint receives data channels via
ondatachannelas usual.
const pc = new RTCPeerConnection({
alwaysNegotiateDataChannels: true,
});
// Later, create a data channel without triggering renegotiation:
pc.addEventListener('connectionstatechange', () => {
if (pc.connectionState === 'connected') {
const channel = pc.createDataChannel('chat');
channel.addEventListener('open', () => {
channel.send('Hello!');
});
}
});
// The remote endpoint receives the channel via ondatachannel:
remotePc.addEventListener('datachannel', ({ channel }) => {
channel.addEventListener('message', (e) => console.log(e.data));
});
Source: WebRTC Extensions specification.
without alwaysNegotiateDataChannels
Without the option, the typical workaround is to call createDataChannel() before creating the initial offer — usually creating a throw-away "placeholder" channel just to force the m-section into the SDP — and close or ignore it once the connection is established. The new option eliminates this workaround.
// Before Chrome 148: workaround — create a dummy channel to force m-section
const pc = new RTCPeerConnection();
const placeholder = pc.createDataChannel('_placeholder'); // forced m-section
const offer = await pc.createOffer();
// After answering, immediately close the placeholder
pc.addEventListener('connectionstatechange', () => {
if (pc.connectionState === 'connected') {
placeholder.close();
}
});
browser support
| Chrome / Edge | 148 (all platforms) |
|---|---|
| Firefox | No signal |
| Safari | No signal |