Skip to content

Use cases

Everything below is the same primitive — fan-out to a shared name — used in different shapes. They are worth reading even if none is exactly your problem, because the shapes recur.

Phone as a controller

The original motivation. A laptop drives a projector; a phone in someone's hand should drive the laptop.

  1. The laptop page generates a random channel and renders it as a QR code.
  2. Someone scans it and their phone opens a page on the same channel.
  3. The phone streams orientation, touch or button events into the channel.
  4. The laptop applies them.
js
// phone
addEventListener("deviceorientation", (e) => {
  send(JSON.stringify({ type: "tilt", alpha: e.alpha, beta: e.beta }));
});

// laptop
onMessage((data) => {
  const msg = JSON.parse(data);
  if (msg.type === "tilt") applyTilt(msg);
});

No pairing protocol, no app install, no server of your own. Works for slide clickers, gamepads, remote laser pointers, and audience polls.

Wiring components together

Two iframes, two tabs, or two entirely separate applications that share nothing but a channel name. Because senders never see their own messages, both sides can run identical code and simply react to whatever arrives.

This is the metaframe case: a channel becomes a pipe between composable UI pieces that were never written to know about each other.

Telemetry and live dashboards

A device, a cron job or a CI step POSTs readings; any number of dashboards subscribe.

sh
while true; do
  curl -sX POST "$ROUTER/$CHANNEL" \
    -d "{\"cpu\": $(get_cpu), \"at\": $(date +%s)}"
  sleep 1
done

The producer needs nothing but curl, and dashboards can come and go freely. Nothing is stored, so a dashboard that opens later starts from the next reading — usually exactly what you want for live metrics.

Bridging a local process to the public internet

A script on your laptop and a page hosted anywhere agree on a channel name and are connected. No tunnel, no ngrok, no port forwarding, no inbound firewall rule — both sides make outbound connections.

js
// on your laptop, deno run -A bridge.ts
const ws = new WebSocket(`wss://router.metapage.io/${channel}`);
ws.onmessage = async (e) => {
  const result = await runLocally(JSON.parse(e.data));
  ws.send(JSON.stringify(result));
};

Good for driving local hardware from a hosted UI, exposing a local model or dataset to a demo, and remote-controlling a build.

Presence and collaborative touches

Cursors, selections, typing indicators, "three people are here". Small, live, and worthless the moment they are stale — which is exactly the class of state that suits an ephemeral router.

See the presence pattern for an implementation.

Nudging running apps

A webhook fires, a job finishes, a deploy completes: POST once and every open tab reacts immediately, without polling.

sh
# last line of a CI job
curl -X POST "$ROUTER/$CHANNEL" -d '{"type":"build","status":"green"}'

Multiplayer prototypes and workshops

Room-based games, shared whiteboards, classroom exercises. The setup cost is a random string, so you can hand a room out as a link and spend your time on the actual idea instead of the plumbing.

Where to use something else

Be deliberate about the boundary:

You needUse instead
Late joiners to see historyA database, or a peer that replays state on request
Guaranteed deliveryA real queue (SQS, NATS, Kafka)
Per-user authorizationYour own server, with the router as transport underneath
Conflict-free shared documentsA CRDT library — which you can happily transport over a channel
High-volume binary streamsWebRTC, or a direct connection

Released under the MIT License.