Concepts

Events

Events enable real-time 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

Use c.broadcast(eventName, data) to send events to all connected clients:

import { actor } from "rivetkit";

const chatRoom = actor({
  state: { 
    messages: [] as Array<{id: string, userId: string, text: string, timestamp: number}>
  },
  
  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;
    },
  }
});
TypeScript

Sending to Specific Connections

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

import { actor } from "rivetkit";

const gameRoom = actor({
  state: { 
    players: {} as Record<string, {health: number, position: {x: number, y: number}}>
  },
  
  createConnState: (c, opts, 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
      const targetConn = c.conns.find(conn => 
        conn.state.playerId === targetPlayerId
      );
      
      if (targetConn) {
        targetConn.send('privateMessage', {
          from: c.conn.state.playerId,
          message,
          timestamp: Date.now()
        });
      } else {
        throw new Error("Player not found or not connected");
      }
    }
  }
});
TypeScript

Send events to all connections except the sender:

import { actor } from "rivetkit";

const gameRoom = actor({
  state: { 
    players: {} as Record<string, {health: number, position: {x: number, y: number}}>
  },
  
  createConnState: (c, opts, 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 (c.state.players[playerId]) {
        c.state.players[playerId].position = position;
        
        // Send position update to all OTHER players
        for (const conn of c.conns) {
          if (conn.state.playerId !== playerId) {
            conn.send('playerMoved', { playerId, position });
          }
        }
      }
    }
  }
});
TypeScript

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:

import { createClient } from "rivetkit/client";
import type { registry } from "./registry";

const client = createClient<typeof registry>("http://localhost:8080");

// Get actor handle and establish connection
const chatRoom = client.chatRoom.getOrCreate(["general"]);
const connection = chatRoom.connect();

// Listen for events
connection.on('messageReceived', (message) => {
  console.log(`${message.userId}: ${message.text}`);
  displayMessage(message);
});

// Call actions through the connection
await connection.sendMessage("user-123", "Hello everyone!");
TypeScript
import { useState } from "react";
import { useActor } from "./rivetkit";

function ChatRoom() {
  const [messages, setMessages] = useState<Array<{id: string, userId: string, text: string}>>([]);

  const chatRoom = useActor({
    name: "chatRoom",
    key: ["general"]
  });

  // Listen for events
  chatRoom.useEvent("messageReceived", (message) => {
    setMessages(prev => [...prev, message]);
  });

  // ...rest of component...
}
React

One-time Event Listeners

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

const gameRoom = client.gameRoom.getOrCreate(["room-456"]);
const connection = gameRoom.connect({
  playerId: "player-789",
  role: "player"
});

// Listen for game start (only once)
connection.once('gameStarted', () => {
  console.log('Game has started!');
  showGameInterface();
});
TypeScript
import { useState, useEffect } from "react";
import { useActor } from "./rivetkit";

function GameLobby() {
  const [gameStarted, setGameStarted] = useState(false);

  const gameRoom = useActor({
    name: "gameRoom",
    key: ["room-456"],
    params: {
      playerId: "player-789",
      role: "player"
    }
  });

  // Listen for game start (only once)
  useEffect(() => {
    if (!gameRoom.connection) return;
    
    const handleGameStart = () => {
      console.log('Game has started!');
      setGameStarted(true);
    };

    gameRoom.connection.once('gameStarted', handleGameStart);
  }, [gameRoom.connection]);

  // ...rest of component...
}
React

Removing Event Listeners

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

// Add listener
const unsubscribe = connection.on('messageReceived', (message) => {
  console.log("Received:", message);
});

// Remove listener
unsubscribe();
TypeScript
import { useState, useEffect } from "react";
import { useActor } from "./rivetkit";

function ConditionalListener() {
  const [isListening, setIsListening] = useState(false);
  const [messages, setMessages] = useState<string[]>([]);

  const chatRoom = useActor({
    name: "chatRoom",
    key: ["general"]
  });

  useEffect(() => {
    if (!chatRoom.connection || !isListening) return;

    // Add listener
    const unsubscribe = chatRoom.connection.on('messageReceived', (message) => {
      setMessages(prev => [...prev, `${message.userId}: ${message.text}`]);
    });

    // Cleanup - remove listener when component unmounts or listening stops
    return () => {
      unsubscribe();
    };
  }, [chatRoom.connection, isListening]);

  // ...rest of component...
}
React

More About Connections

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

API Reference