29 Jul, 2025
TLDR: we explain how to make libcurl based applications work in webassembly without changes by tunneling all traffic over a websocket proxy.
For a quick demo, check out https://github.com/r-wasm/ws-proxy
Porting R to WebAssembly
Webr is a port of the R language and its package ecosystem to WebAssembly. Many R packages rely on well-known C/C++ libraries to do the heavy lifting, and fortunately most of these libraries can be built with emscripten without too much trouble. However one major barrier that remains is the limited networking capabilities in wasm.
Data science makes heavy use of http for all kinds of things, and a lot of R code directly or indirectly depends on our libcurl bindings for networking. Somewhat surprisingly, libcurl can be compiled with emscripten without needing any patches. However by default it is not very useful because the browser runtime does not have capabilities to open tcp connections, which are needed for doing pretty much anything in libcurl.
To understand why, one should realize that WebAssembly does not have sockets, as it effectively needs to wrap JavaScript networking interfaces from the browser, like fetch. This provides far more restricted functionality than what we need for libcurl, and many things just won’t work at all with fetch (see e.g. pyodide constraints for an overview of the same problem from our Python colleagues).
However it turns out there is a relatively simple way to make existing code work in WebAssembly, by letting libcurl route all traffic over a websocket based proxy server. This solution is secure and easy to implement, but it is not very well explained in the docs, so hopefully this post helps to clear some things up.
Sockets as Websockets
The emscripten documentation on networking hints at the first part of the solution:
... continue reading