PolynomialHQdocs
Guides

Broadcast events

Send typed, transient events to the other connections in a room.

Broadcasts deliver a one-off event to the connections that are in the room right now. Use them for reactions, notifications, presentation controls, or other signals that do not need to be persisted.

Loading the broadcast demo…

Define events

Map each event name to its payload:

type Events = {
  reaction: {
    emoji: string;
    x: number;
    y: number;
  };
  slideChanged: {
    slideId: string;
  };
};

Pass the type to RoomProvider:

<RoomProvider<Presence, Storage, Events>
  id="presentation:launch"
  initialPresence={{ name: "Ada" }}
  initialStorage={{ currentSlideId: "intro" }}
>
  <Presentation />
</RoomProvider>

Send an event

import { useBroadcast } from "@polynomialhq/react";

function Reactions() {
  const broadcast = useBroadcast<Events>();

  return (
    <button
      onClick={() => {
        broadcast("reaction", {
          emoji: "πŸ‘",
          x: 320,
          y: 180,
        });
      }}
      type="button"
    >
      Applaud
    </button>
  );
}

TypeScript checks both the event name and its payload.

Listen for one event

import { useBroadcastEvent } from "@polynomialhq/react";

function ReactionLayer() {
  useBroadcastEvent<Events, "reaction">("reaction", ({ connectionId, payload }) => {
    showReaction({
      ...payload,
      sender: connectionId,
    });
  });

  return <div id="reaction-layer" />;
}

The listener receives:

FieldDescription
eventTyped event name
payloadTyped payload for that event
connectionIdSending connection

The sender receives its own broadcast

The realtime service fans an event out to every connection in the room, including the one that sent it. If your handler applies a visual effect, the sender will see it twice unless you filter:

const connection = useConnectionSnapshot();

useBroadcastEvent<Events, "reaction">("reaction", (event) => {
  if (event.connectionId === connection.connectionId) {
    return;
  }

  showReaction(event.payload);
});

Alternatively, let the echo be your confirmation and apply the effect only when it arrives.

Pass a stable listener. useBroadcastEvent resubscribes whenever the listener identity changes, so wrap it in useCallback if it closes over component state.

Framework-agnostic events

const { room } = client.enterRoom<Presence, Storage, Events>("presentation:launch", {
  initialPresence,
  initialStorage,
});

room.broadcast("slideChanged", { slideId: "results" });

room.subscribe((event) => {
  if (event.type === "broadcast" && event.event.event === "slideChanged") {
    navigateToSlide(event.event.payload.slideId);
  }
});

room.broadcastEvent(event) is a convenience form for objects that already carry a type field: it sends event.type as the event name and the whole object as the payload.

Broadcast from a server

A trusted backend can send an event through the management API:

import { PolynomialServer } from "@polynomialhq/server";

const polynomial = new PolynomialServer({
  secretKey: process.env.POLYNOMIAL_SECRET_KEY!,
});

await polynomial.broadcastEvent({
  event: {
    type: "deployment.finished",
    deploymentId: "deploy_123",
  },
  projectId: "project_123",
  roomId: "project-room:42",
});

Server broadcasts are useful for job progress, webhook results, or administrative signals. The event object must contain a type string; browser listeners receive it under that name.

When to use storage instead

Broadcasts are not retained or replayed. Use storage when:

  • a user joining later needs the value;
  • a reconnect must restore it;
  • the event changes the durable document;
  • you need undo and redo.

A broadcast sent while a client is reconnecting is lost for that client β€” there is no replay buffer. Anything that must survive a two-second network blip belongs in storage.

On this page