Websocket Router

A public address space for realtime messages.

Open a websocket to any URL you like. Everything you send is delivered to every other client on that same URL — and to nobody else. No accounts, no SDK, no schema, no setup.

It is the smallest useful piece of realtime plumbing: a channel is just a name, a client is just a websocket, and a message is just bytes you chose the meaning of.

The one rule: a message goes to every listener on the channel except the sender. That single asymmetry is what makes peers able to talk to each other without echoing themselves.

Watch it work

Three real websockets, open right now from this page to a freshly-generated channel on this server. Send from one and watch the other two receive it — while the sender does not.

channel: connecting…
Anything POSTed to the channel URL reaches all listeners — there is no sender socket to exclude.

The whole API

There are two verbs. Connect a websocket to listen and send, or POST to broadcast from anything that can make an HTTP request.

Browser / Deno / Node — join a channel
const ws = new WebSocket(
  "wss://router.metapage.io/my-secret-channel"
);

ws.onmessage = (e) => console.log("peer said", e.data);

// goes to every other listener, never back to us
ws.onopen = () => ws.send(JSON.stringify({ hello: "world" }));
Anything else — fire a message in
curl -X POST \
  https://router.metapage.io/my-secret-channel \
  -d '{"temperature": 21.4}'

# every listener on the channel receives the body verbatim,
# on whichever server instance they happen to be connected to

Getting a phone into the loop

This is what the router is best at, and it needs no app, no pairing code and no account. Open a channel URL in a browser and the page renders a QR code of its own URL. Point a phone camera at it, and the phone is on the channel.

  1. Open a channel on the big screen Any URL is a channel, so pick a name nobody can guess: https://router.metapage.io/kitchen-7f3a91. The page that loads shows a QR code for exactly that address.
  2. Scan it with the phone The camera app is enough — no install. The phone opens the identical URL, which puts both devices on the same channel.
  3. Send anything, either direction Whatever the phone sends arrives at the screen, and whatever the screen sends arrives at the phone. Neither hears its own echo.
On the phone — become a motion controller
const ws = new WebSocket(
  "wss://router.metapage.io/kitchen-7f3a91"
);

addEventListener("deviceorientation", (e) => {
  if (ws.readyState !== WebSocket.OPEN) return;
  ws.send(JSON.stringify({ a: e.alpha, b: e.beta, g: e.gamma }));
});

What people build with it

Anywhere two things need to talk and you do not want to stand up a backend to introduce them.

📱

Phone as a controller

A gamepad, a slide clicker, a motion sensor or a remote for whatever is on the big screen. One scan and it is wired up.

🧩

Wiring apps together

Two browser tabs, two iframes, two metaframes — a channel is a pipe between components that were never designed to know about each other.

🛰️

Telemetry and dashboards

A device or a script POSTs readings to a channel; any number of dashboards subscribe and render them live.

🔁

Bridging a local process

Give a script on your laptop and a page on the public internet the same channel name and they are connected, no tunnel or port forwarding.

👥

Presence and shared state

Cursors, selections, "who's here" — the kinds of small collaborative touches that are not worth a whole realtime platform.

🔔

Nudging a running app

CI finished, a job completed, a webhook fired: POST once and every open tab reacts immediately.

How it works

Identical stateless instances, joined by redis pub/sub. That is the entire design — there is no broker, no queue and no stored state anywhere in the path a message takes.

client A client B client C client D router instance 1 router instance 2 router instance 3 redis pub/sub

Be honest about what this is

It is a router, not a database and not a platform. Knowing the edges up front is what makes it pleasant to build on.

What you get

  • Fan-out to every listener but the sender
  • Works across server instances, via redis pub/sub
  • Any payload you like — it is never parsed
  • Channels appear the instant someone connects
  • Plain websockets and plain HTTP, from anywhere

What you do not

  • No persistence — messages sent to nobody are gone
  • No history or replay for clients that join later
  • No delivery guarantee, no acks, no retries
  • No accounts: the channel name is the only secret
  • No server-side validation of what you send

Free to use, and free to walk away from

This runs as public infrastructure. A channel is a name — there is nothing to sign up for, no account to be locked out of, and no per-seat tier waiting further down the road.

A lot of realtime glue never gets built, because standing up a server is not worth it for one figure, one instrument or one workshop. The work stays on somebody's laptop, or it ends up inside a platform that outlives the grant that paid for it.

So everything needed to run your own copy is in the repository, MIT licensed: a redis and a single process. If router.metapage.io disappears tomorrow, change the hostname and what you built keeps working.

Your own router, start to finish
git clone https://github.com/metapages/websocket-router
cd websocket-router

# anything that speaks redis will do
REDIS_URL=redis://localhost:6379 \
  deno run -A src/serve.ts

# now every snippet on this page works
# against your host instead of ours