Skip to main content

Realtime

Air Pipe ships two realtime transports on one stack — native WebSocket channels and a real MQTT broker — with pub/sub, presence, history-rewind and retained state. Unlike a relay, the message can run your pipeline (validate, enrich, store, fan out), and unlike a raw broker it is multi-tenant-safe with per-org limits built in. One vendor for transport + logic + auth + billing, no message broker, Redis or NATS to operate.

WebSocket or MQTT?

Use…When
WebSocket channelsBrowser/app realtime — live dashboards, chat, presence, notifications, collaborative UIs. Simple JSON frames; browsers connect natively.
MQTT brokerIoT / devices / anything already speaking MQTT — telemetry, commands, sensor fleets. Full broker semantics (wildcards, retained, QoS, sessions).

Both deliver across all nodes over Air Pipe's private mesh, both can trigger your pipelines, and both are bounded by the same per-org limits.

What you get

  • Pub/sub + wildcards — publish to a channel/topic; every subscriber (on any node) receives it.
  • Presence — who's on a channel, with enter/leave events (WS).
  • History-rewind — replay the last N messages on subscribe (WS).
  • Retained state — a new subscriber immediately gets the channel's last value.
  • Flexible auth — fully open/public, Air Pipe-issued tokens, your own JWT (shared-secret or JWKS), or a backend API key.
  • In-pipeline processing — an interface-shaped message runs its Air Pipe pipeline.

A 30-second example

A public WebSocket feed — visitors subscribe with no auth, your backend publishes:

name: LiveUpdates
interfaces:
feed:
ws: "on" # realtime — no `output` needed
public: true # browsers connect with no credential (non-sensitive data)
# output: http # optional — ALSO serve this exact interface over HTTP (see Dual interface)
actions:
- name: Ping
input: a|body|

Dual interface

An interface's transport is set by markers, not by output: ws: "on" makes it a WebSocket interface, mqtt: makes it MQTT-triggered — no output field is required for realtime. Adding output: http doesn't change realtime; it additionally exposes the same interface, same pipeline over HTTP at /dev/pipe/<org>/<env>/<interface>. So one definition can serve WebSocket and MQTT and HTTP at once — pick per interface:

interfaces:
events:
ws: "on" # WebSocket
mqtt: "in" # + MQTT (production/events/in)
output: http # + HTTP (POST /dev/pipe/<org>/<env>/events)
actions:
- name: Handle
input: a|body|

Leave output off for realtime-only interfaces; add it when you want the same logic reachable as a plain HTTP endpoint too.

// browser
const ws = new WebSocket("wss://api.airpipe.io/ws/<ORG_UUID>/production/feed");
ws.onopen = () => ws.send(JSON.stringify({ ap_subscribe: "updates" }));
ws.onmessage = (e) => console.log(JSON.parse(e.data)); // {ap_channel:"updates", data:{…}}

Publish to every subscriber from any pipeline with a ws_publish action (or mqtt_publish for MQTT).

Ready-made packs: Realtime WebSocket Channels, Realtime MQTT Broker, Realtime Public Feed, Realtime MQTT Public Stream (Marketplace).

Next: WebSocket channels →