Skip to main content
Sign In
Features

Realtime

Events enable realtime communication from actors to clients. While clients use actions to send data to actors, events allow actors to push updates to connected clients instantly.

Events can be sent to clients connected using .connect(). They have no effect on low-level WebSocket connections.

Publishing Events from Actors

Broadcasting to All Clients

Define event names and payload types with events and event<T>(), then use c.broadcast(eventName, ...args) to send events to all connected clients:

import { actor, event } from "rivetkit";

type Message = {
  id: string;
  userId: string;
  text: string;
  timestamp: number;
};

const chatRoom = actor({
  state: {
    messages: [] as Message[]
  },

  events: {
    messageReceived: event<Message>()
  },

  actions: {
    sendMessage: (c, userId: string, text: string) => {
      const message = {
        id: crypto.randomUUID(),
        userId,
        text,
        timestamp: Date.now()
      };
      
      c.state.messages.push(message);
      
      // Broadcast to all connected clients
      c.broadcast('messageReceived', message);
      
      return message;
    },
  }
});

Sending to Specific Connections

Send events to individual connections using conn.send(eventName, ...args):

import { actor, event } from "rivetkit";

interface ConnState {
  playerId: string;
  role: string;
}

const gameRoom = actor({
  state: {
    players: {} as Record<string, {health: number, position: {x: number, y: number}}>
  },

  events: {
    privateMessage: event<{
      from?: string;
      message: string;
      timestamp: number;
    }>()
  },

  connState: { playerId: "", role: "player" } as ConnState,

  createConnState: (c, params: { playerId: string, role?: string }) => ({
    playerId: params.playerId,
    role: params.role || "player"
  }),

  actions: {
    sendPrivateMessage: (c, targetPlayerId: string, message: string) => {
      // Find the target player's connection
      let targetConn = null;
      for (const conn of c.conns.values()) {
        if (conn.state.playerId === targetPlayerId) {
          targetConn = conn;
          break;
        }
      }

      if (targetConn) {
        targetConn.send('privateMessage', {
          from: c.conn?.state.playerId,
          message,
          timestamp: Date.now()
        });
      } else {
        throw new Error("Player not found or not connected");
      }
    }
  }
});

Send events to all connections except the sender:

import { actor, event } from "rivetkit";

interface ConnState {
  playerId: string;
  role: string;
}

const gameRoom = actor({
  state: {
    players: {} as Record<string, {health: number, position: {x: number, y: number}}>
  },

  events: {
    playerMoved: event<{
      playerId: string;
      position: { x: number; y: number };
    }>()
  },

  connState: { playerId: "", role: "player" } as ConnState,

  createConnState: (c, params: { playerId: string, role?: string }) => ({
    playerId: params.playerId,
    role: params.role || "player"
  }),

  actions: {
    updatePlayerPosition: (c, position: {x: number, y: number}) => {
      const playerId = c.conn?.state.playerId;
      if (!playerId) return;

      if (c.state.players[playerId]) {
        c.state.players[playerId].position = position;

        // Send position update to all OTHER players
        for (const conn of c.conns.values()) {
          if (conn.state.playerId !== playerId) {
            conn.send('playerMoved', { playerId, position });
          }
        }
      }
    }
  }
});

Subscribing to Events from Clients

Clients must establish a connection to receive events from actors. Use .connect() to create a persistent connection, then listen for events.

Basic Event Subscription

Use connection.on(eventName, callback) to listen for events:

One-time Event Listeners

Use connection.once(eventName, callback) for events that should only trigger once:

Removing Event Listeners

Use the callback returned from .on() to remove event listeners:

Debugging

  • GET /inspector/connections shows active connections and connection metadata.
  • Use this to confirm clients are connected before expecting broadcasts.
  • GET /inspector/summary provides connections, RPCs, and queue size in one response.
  • In non-dev mode, inspector endpoints require authorization.

More About Connections

For more details on actor connections, including connection lifecycle, authentication, and advanced connection patterns, see the Connections documentation.

API Reference