v154 · network · local network access
targetAddressSpace for WebSockets
A page on https:// cannot open a ws:// connection — that is mixed content, and it is the rule that stops a hijacked page talking to your router. It also stops a legitimate web app talking to a printer, a 3D printer, or a dev server on the same desk. targetAddressSpace is the declared, permission-gated exception, and Chrome 154 brings it to WebSockets to match fetch().
concepts
-
Does this browser read it?
The option lives in the
WebSocketInitdictionary, so it can be probed with a getter — no version sniffing, no connection required. The demo also checks the accepted values and shows what an invalid one does. -
What counts as local
Loopback, private, and public are three different address spaces with three different rules, and which one a hostname falls into is not always obvious. Classify a set of addresses and see which connections need the option at all.
-
Opening one
A real connection to this origin's echo endpoint, opened with and without the option, side by side. On a same-origin
ws://fromhttp://localhostnothing is blocked — which is itself the useful lesson about when the option is and is not needed.
why it shipped
Local Network Access exists because a public web page reaching a device on your home network is a genuine attack, and the browser cannot tell a malicious page from a helpful one by looking at the request. So it asks: a page that declares it is deliberately targeting a local address gets a permission prompt, and the user decides.
fetch() has had targetAddressSpace for a while; WebSockets did not, which left long-lived connections to local devices — the transport those devices actually want — with no escape hatch at all. Declaring the intent up front is what makes the prompt meaningful: the browser can say which local address the page wants, rather than asking about a request the user cannot see.
the API
// Only expressible because the options bag exists.
const socket = new WebSocket("ws://printer.local:9100/stream", {
protocols: ["escpos"],
targetAddressSpace: "local",
});
// "loopback" is the narrower case: 127.0.0.1 and ::1 only.
new WebSocket("ws://127.0.0.1:8000/hmr", { targetAddressSpace: "loopback" });
The option is a declaration, not a bypass: it tells the browser what to ask the user about. A page that lies about the address space does not get a connection, it gets a failed one.