Library / SDK
paullouisageneau/libdatachannel avatar
paullouisageneau/libdatachannel

libdatachannel: WebRTC Data Channels and WebSockets in C++ Without Google's Stack

C/C++ WebRTC network library featuring Data Channels, Media Transport, and WebSockets

2,749 stars581 forksC++MPL-2.0

At a glance

What is it?
libdatachannel is a standalone C++ implementation of WebRTC Data Channels, Media Transport and WebSockets with C bindings, aimed at native applications that need to talk to browsers. The design trade-off is a smaller, simpler stack that is not the reference implementation, so you inherit its coverage limits.
Who is it for?
Adopt libdatachannel if you are writing a native C++ or C application that must exchange data channels or media with a browser, and you want the peer connection, SCTP and ICE handled for you rather than importing Google's reference library. Do not adopt it if you need the full WebRTC feature surface or a managed runtime, since the library is C++ with C bindings and its own maintainers describe the API as simplified versions of the browser APIs.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem libdatachannel solves for native applications

A browser can open a WebRTC peer connection in a few lines of JavaScript. A C++ daemon, a desktop app, an Android service or an embedded process cannot, unless it links a WebRTC implementation. The obvious candidate is Google's reference library, and the README is blunt about why the project exists: it aims to enable direct connectivity between native applications and web browsers "without the pain of importing Google's bloated reference library." That is the whole pitch. The target user is an engineer who already has a native codebase and needs a peer-to-peer data path to a browser or to another native peer, without vendoring a large Chromium-derived tree.

The library covers three things: WebRTC Data Channels, WebRTC Media Transport, and WebSockets. The WebSocket part matters more than it first appears. If your application already speaks WebSockets, you can use the same library for the signaling channel that negotiates the peer connection, so a single dependency covers both halves of the setup. The README also notes that code using Data Channels and WebSockets can be compiled as is to WebAssembly for browsers through datachannel-wasm, which means the same source can run on both sides of the connection. That is a genuine architectural convenience, not a marketing line, and it is the strongest argument for choosing this library over assembling separate WebSocket and WebRTC dependencies.

How the WebRTC stack is assembled: ICE, SCTP and the TLS layer

The library is not self-contained in the sense of having no dependencies. It is self-contained in the sense of not depending on Google's WebRTC. The README lists the pieces: usrsctp for SCTP, plog for logging, nlohmann JSON for the examples, and a choice of TLS provider among GnuTLS, Mbed TLS and OpenSSL. The connectivity layer is the interesting one, because it has two options. By default the build uses libjuice, an ad-hoc ICE library by the same author, pulled in as a submodule. Alternatively you can build against libnice, the freedesktop ICE implementation, which brings GLib and GObject with it.

That split shows up directly in the Makefile. USE_NICE defaults to 0, and when it is 0 the build adds the libjuice include path and links libjuice.a; when it is nonzero the build links glib-2.0, gobject-2.0 and nice instead. The TLS choice is similarly explicit. USE_GNUTLS and USE_MBEDTLS both default to 0, and the Makefile raises a hard error if you set both, which is a sensible guard. With neither set, the build links OpenSSL and passes --enable-openssl to the libsrtp configure step. Media support is gated by NO_MEDIA, which defaults to 0 and defines RTC_ENABLE_MEDIA=1; setting it nonzero defines RTC_ENABLE_MEDIA=0 and drops libsrtp from the build. WebSockets have their own switch, NO_WEBSOCKET, controlling RTC_ENABLE_WEBSOCKET. So a data-channel-only application can compile out media and its SRTP dependency entirely. The API itself is a set of C++ classes mirroring the browser model: rtc::PeerConnection, rtc::DataChannel, rtc::WebSocket, rtc::Description and rtc::Candidate. The README says the interface consists of "somewhat simplified versions of the JavaScript WebRTC and WebSocket APIs present in browsers," which is a deliberate choice to make cross-environment code easier to write, and also a warning that the API is not a one-to-one match.

Installing libdatachannel and opening a first data channel

The README points to BUILDING.md for build instructions and does not reproduce them, so the canonical path is building from source with the submodules present. The library is also packaged for AUR, vcpkg, conan and FreeBSD ports, and the README lists Rust and Node.js bindings on crates.io and npm respectively. If your language has a binding, that is the shortest route; the C++ path below is what the README's own examples show.

The first block is the include the README uses in every example. Everything else in the library is reachable from this header.

cpp
#include "rtc/rtc.hpp"

Next, configure and construct a peer connection. The README's example emplaces a STUN server into the configuration, which is what lets the two peers discover a working path through NAT. Replace the hostname with your own STUN server; the README uses mystunserver.org:3478 as the placeholder.

cpp
rtc::Configuration config;
config.iceServers.emplace_back("mystunserver.org:3478");

rtc::PeerConnection pc(config);

A peer connection is useless until the two sides exchange session descriptions and candidates. libdatachannel does not provide signaling; the README's example leaves the transport as macros you implement, MY_SEND_DESCRIPTION_TO_REMOTE and MY_SEND_CANDIDATE_TO_REMOTE, and the matching receive callbacks call pc.setRemoteDescription and pc.addRemoteCandidate. This is the part that surprises people: the library handles ICE, DTLS and SCTP, but you still need a signaling channel, and the repository ships complete signaling server examples in Node.js, Python, Qt and Rust under examples/.

Once the connection is up, creating a data channel is one call, and the callbacks tell you when it opens and what arrives. The README's onMessage handler uses std::variant because a message is either binary or text.

cpp
auto dc = pc.createDataChannel("test");

dc->onOpen([]() {
    std::cout << "Open" << std::endl;
});

dc->onMessage([](std::variant<rtc::binary, rtc::string> message) {
    if (std::holds_alternative<rtc::string>(message)) {
        std::cout << "Received: " << get<rtc::string>(message) << std::endl;
    }
});

The receiving side is the mirror image. The peer that did not create the channel gets it through onDataChannel, and can send immediately.

cpp
std::shared_ptr<rtc::DataChannel> dc;
pc.onDataChannel([&dc](std::shared_ptr<rtc::DataChannel> incoming) {
    dc = incoming;
    dc->send("Hello world!");
});

If you only need WebSockets and not peer-to-peer, the same library covers that too, with onOpen and onMessage callbacks and an open call taking a wss:// URL. The repository has a copy-paste example and a copy-paste-capi example if you want the smallest possible starting point rather than the full client.

Where libdatachannel is the wrong tool

The README states that the WebRTC stack is "fully compatible with browsers like Firefox and Chromium," but compatibility with browsers is not the same as feature parity with the reference implementation. The library's own framing, that it implements simplified versions of the browser APIs, tells you the API surface is narrower. If your application depends on parts of WebRTC that the README does not list among its protocols, you should confirm they exist before designing around them, because the README's protocol list is the authoritative statement of what is implemented.

The second limitation is the dependency graph, which is easy to underestimate. Building from source means usrsctp, plog, libjuice or libnice, and libsrtp when media is enabled, plus a TLS provider. Choosing libnice pulls in GLib and GObject, which is a meaningful addition to a small native binary. Choosing libjuice avoids that but ties you to a second project by the same author, as a submodule. Neither choice is wrong; they are different bets on how much of the system you want to own.

The third is the signaling gap. There is no built-in signaling protocol. You supply one, and you supply it correctly, because a broken candidate exchange shows up as a connection that never establishes rather than as a clear error. The examples directory gives you working signaling servers to copy, but a production deployment still has to run one.

Finally, consider the language boundary. There are Rust and Node.js bindings, but if your application is in Java, Python or Go, the README does not point to an official binding for those, and you would be working through the C API or the C++ API from a foreign runtime. That is a real cost, not a footnote.

libdatachannel versus Google's WebRTC reference library

The direct alternative is the implementation libdatachannel was written to avoid: Google's WebRTC reference library, which the README links to and describes as bloated. The difference in approach is scope. The reference library is the full WebRTC implementation, maintained inside the Chromium project, with the complete codec and media pipeline and the API surface that browsers themselves use. If you need something libdatachannel does not implement, the reference library is where it lives. The cost is build complexity and dependency weight, which is precisely the trade the README is arguing against.

libdatachannel takes the opposite position: implement the protocols needed for data channels, media transport and WebSockets, keep the dependency list short, and expose an API close enough to the browser's that the same code shape works in both places. That makes it a better fit for a native application that needs a data path and maybe basic media, and a worse fit for anything that needs the full media stack.

There is a second comparison worth making, inside the library's own configuration. The ICE backend choice between libjuice and libnice is a real fork in the road. libnice is an established freedesktop project and may already be present in your environment; libjuice is smaller and is the default. If your platform already ships libnice and GLib, USE_NICE=1 costs you little. If you are shipping a minimal binary, the default libjuice path is the one the maintainers chose as the default for a reason.

Licence, maintenance and the cost of upgrading

libdatachannel is licensed under MPL 2.0, and the README states the licence changed at version 0.18: earlier versions were LGPLv2.1 or later. That matters if you are pinning an old release, because the obligations differ between the two. The examples and signaling servers under examples/ are also MPL 2.0, according to the README. MPL 2.0 is file-level copyleft, so modifications to the library's own files carry obligations while your separate files generally do not, but this is a summary of what the README says, not legal advice, and you should have counsel review your distribution model.

On maintenance, the repository is not archived and the last push was on 2026-09-23. The most recent release in the list is v0.24.5 from 2026-06-12, preceded by v0.24.4 on 2026-06-08 and v0.24.3 on 2026-05-09. The pattern of patch releases within a minor line suggests fixes are being shipped between feature releases, but the release notes are not in the repository description here, so you should read them yourself before upgrading. The README does not document a rollback procedure or a compatibility policy between minor versions, which is the gap to check first if you pin a version.

Upgrade cost depends on which backends you chose. A build using the default libjuice and OpenSSL has fewer moving parts to re-verify than one using libnice and GnuTLS, because the submodule versions move with the repository while system libraries move with your distribution. If you installed through vcpkg, conan or AUR, your upgrade cadence is set by that package's maintainers, not by the upstream release schedule, and those two can diverge.

Editorial conclusion

Adopt libdatachannel if you are writing a native C++ or C application that must exchange data channels or media with a browser, and you want the peer connection, SCTP and ICE handled for you rather than importing Google's reference library. Do not adopt it if you need the full WebRTC feature surface or a managed runtime, since the library is C++ with C bindings and its own maintainers describe the API as simplified versions of the browser APIs. Before committing, verify two things in the repository: which TLS backend and ICE backend your build selects, because the Makefile exposes USE_GNUTLS, USE_MBEDTLS and USE_NICE, and whether media support is compiled in, since NO_MEDIA=1 disables it entirely.

Frequently asked questions

What is libdatachannel used for?

It is a standalone C++ implementation of WebRTC Data Channels, WebRTC Media Transport and WebSockets, with C bindings, for platforms including GNU/Linux, Android, FreeBSD, macOS, iOS and Windows. The README frames its purpose as enabling direct connectivity between native applications and web browsers without importing Google's reference library.

Is libdatachannel compatible with browsers?

The README states that the WebRTC stack is fully compatible with browsers like Firefox and Chromium, and that code using Data Channels and WebSockets can be compiled as is to WebAssembly for browsers through datachannel-wasm.

How do I install libdatachannel?

The README points to BUILDING.md for build instructions and notes the library is available on AUR, vcpkg, conan and FreeBSD ports, with Rust and Node.js bindings on crates.io and npm. Building from source pulls in usrsctp, plog, libjuice or libnice, a TLS provider, and libsrtp when media support is enabled.

Which licence does libdatachannel use?

It is licensed under MPL 2.0, according to the README, and the examples including the signaling server are also MPL 2.0. The README notes the licence changed at version 0.18, with earlier versions under LGPLv2.1 or later.

Does libdatachannel provide signaling?

No. The README's peer connection example leaves the description and candidate transport to macros you implement, and the repository ships complete signaling server examples in Node.js, Python, Qt and Rust under examples/.

Official sources

  1. License: MPL-2.0
  2. paullouisageneau/libdatachannel on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/paullouisageneau-libdatachannel.svg)](https://hysenlabs.com/projects/paullouisageneau-libdatachannel)