Documentation

Realtime WebSocket

Subscribe to database change events as they happen. INSERT / UPDATE / DELETE through /sql fans out to every connected WebSocket client. Pro+ plans only.

Connect

const ws = new WebSocket(
  `wss://api.mosaic.site/v1/project/${slug}/realtime?apikey=${API_KEY}`
);

API key goes in the query param — browsers can't send custom headers on WebSocket handshake.

Subscribe to changes

ws.onopen = () => {
  // All changes on "tasks"
  ws.send(JSON.stringify({ type: "subscribe", table: "tasks", event: "*" }));

  // INSERTs only
  ws.send(JSON.stringify({ type: "subscribe", table: "messages", event: "INSERT" }));

  // With row filter
  ws.send(JSON.stringify({
    type: "subscribe", table: "tasks", event: "*",
    filter: "user_id=eq.abc-123"
  }));
};

Receive events

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "change") {
    // { type, table, event: "INSERT"|"UPDATE"|"DELETE",
    //   new: {...}, old: null, row_count, timestamp }
    console.log(msg.event, msg.table, msg.new);
  }
  if (msg.type === "ping") {
    ws.send(JSON.stringify({ type: "pong" }));
  }
};
Use RETURNING *To get row data in change events, the SQL that mutated the row needs to use RETURNING *. Without it, the event still fires but new will be null.

Filter syntax

Plan limits

PlanConnectionsSubscriptions
Free / Starter—Disabled
Pro1020
Enterprise100100

Message types

MessageDirectionDescription
subscribe→ Server{type, table, event?, filter?}
unsubscribe→ Server{type, table}
pong→ ServerHeartbeat response
system← ServerConnection status
subscribed← ServerSubscription confirmed
change← ServerDatabase change event
ping← ServerHeartbeat (every 30s)
error← ServerError message