React
Connect React applications to Rivet Actors with typed hooks for actor handles, actions, state, and realtime events.
Getting Started
See the React quickstart guide for getting started.
Install
npm install rivetkit @rivetkit/reactpnpm add rivetkit @rivetkit/reactyarn add rivetkit @rivetkit/reactbun add rivetkit @rivetkit/reactMinimal Client
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./index";
const { useActor } = createRivetKit<typeof registry>({
endpoint: "https://my-namespace:pk_...@api.rivet.dev",
});
function Counter() {
const { connection, connStatus } = useActor({ name: "counter", key: ["my-counter"] });
if (connStatus !== "connected" || !connection) return <div>Connecting...</div>;
return <button onClick={() => connection.increment(1)}>+</button>;
}
Stateless vs Stateful
import { createRivetKit } from "@rivetkit/react";
const { useActor } = createRivetKit();
function Counter() {
const counter = useActor({ name: "counter", key: ["my-counter"] });
const increment = async () => {
await counter.connection?.increment(1);
};
return <button onClick={increment}>+</button>;
}
// Stateless: use createClient for one-off calls (SSR or utilities)
import { createClient } from "rivetkit/client";
const client = createClient();
await client.counter.getOrCreate(["my-counter"]).increment(1);
Getting Actors
import { createRivetKit } from "@rivetkit/react";
import { createClient } from "rivetkit/client";
const { useActor } = createRivetKit();
function ChatRoom() {
const room = useActor({ name: "chatRoom", key: ["room-42"] });
return <div>{room.connStatus}</div>;
}
// For get/getOrCreate/create/getForId, use createClient
const client = createClient();
const handle = client.chatRoom.getOrCreate(["room-42"]);
const existing = client.chatRoom.get(["room-42"]);
const created = await client.game.create(["game-1"], { input: { mode: "ranked" } });
const byId = client.chatRoom.getForId("actor-id");
const resolvedId = await handle.resolve();
Connection Parameters
import { createRivetKit } from "@rivetkit/react";
const { useActor } = createRivetKit();
function Chat() {
const chat = useActor({
name: "chatRoom",
key: ["general"],
params: { authToken: "jwt-token-here" },
});
return <div>{chat.connStatus}</div>;
}
Subscribing to Events
import { createRivetKit } from "@rivetkit/react";
const { useActor } = createRivetKit();
function Chat() {
const chat = useActor({ name: "chatRoom", key: ["general"] });
chat.useEvent("message", (msg) => {
console.log("message:", msg);
});
return null;
}
Connection Lifecycle
import { createRivetKit } from "@rivetkit/react";
const { useActor } = createRivetKit();
function CounterStatus() {
const actor = useActor({ name: "counter", key: ["my-counter"] });
if (actor.connStatus === "connected") {
console.log("connected");
}
if (actor.error) {
console.error(actor.error);
}
return null;
}
Low-Level HTTP & WebSocket
Use the JavaScript client for raw HTTP and WebSocket access:
import { createClient } from "rivetkit/client";
const client = createClient();
const handle = client.chatRoom.getOrCreate(["general"]);
const response = await handle.fetch("history");
const history = await response.json();
const ws = await handle.webSocket("stream");
ws.addEventListener("message", (event) => {
console.log("message:", event.data);
});
ws.send("hello");
Calling from Backend
Use the JavaScript client on your backend (Node.js/Bun). See the JavaScript client docs.
Error Handling
import { ActorError } from "rivetkit/client";
import { createRivetKit } from "@rivetkit/react";
const { useActor } = createRivetKit();
function Profile() {
const actor = useActor({ name: "user", key: ["user-123"] });
const updateUsername = async () => {
try {
await actor.connection?.updateUsername("ab");
} catch (error) {
if (error instanceof ActorError) {
console.log(error.code, error.metadata);
}
}
};
return <button onClick={updateUsername}>Update</button>;
}
Concepts
Keys
Keys uniquely identify actor instances. Use compound keys (arrays) for hierarchical addressing:
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./index";
const { useActor } = createRivetKit<typeof registry>("http://localhost:6420");
function ChatRoom() {
const room = useActor({ name: "chatRoom", key: ["org-acme", "general"] });
return <div>{room.connStatus}</div>;
}
Don’t build keys with string interpolation like "org:${userId}" when userId contains user data. Use arrays instead to prevent key injection attacks.
Environment Variables
createRivetKit() (and the underlying createClient() instance) automatically read:
RIVET_ENDPOINTRIVET_NAMESPACERIVET_TOKENRIVET_POOL
Defaults to http://localhost:6420 when unset. RivetKit runs on port 6420 by default.
Endpoint Format
Endpoints support URL auth syntax:
https://namespace:token@api.rivet.dev
You can also pass the endpoint without auth and provide RIVET_NAMESPACE and RIVET_TOKEN separately. For serverless deployments, use your app’s /api/rivet URL. See Endpoints for details.
API Reference
Package: @rivetkit/react
createRivetKit- Create hooks for ReactuseActor- Hook for actor instances