How server and client plugins talk to each other.
Server ↔ Client Communication
Server and client plugins communicate through named channels — a simple message-passing system.

Server → Client#
Send to one player#
// In a server plugin:
ctx.sendToClient(entityId, "quest-tracker", {
questId: "clear_mine",
progress: 7,
target: 10,
});Broadcast to all players#
ctx.broadcastToClients("world-event", {
type: "boss-spawn",
bossName: "Dragon King",
startsIn: 60,
});Receive on client#
// In a client plugin:
ctx.on("quest-tracker", function(data) {
ctx.updateWidget(questWidgetId, {
html: "Quest: " + data.questId +
" — " + data.progress + "/" + data.target,
});
});
ctx.on("world-event", function(data) {
if (data.type === "boss-spawn") {
ctx.addLocalChatMessage(
"[EVENT] " + data.bossName + " spawns in " + data.startsIn + "s!"
);
}
});Client → Server#
Send from client#
ctx.send("auction-bid", {
itemId: "rare-sword-001",
amount: 500,
});Receive on server#
ctx.onClientMessage("auction-bid", (entityId, data) => {
ctx.log.info(`Player ${entityId} bid ${data.amount} on ${data.itemId}`);
ctx.sendToClient(entityId, "auction-result", {
success: true,
message: "Bid placed!",
});
});Best Practices#
- Use descriptive channel names —
"auction:bid"not"data" - Always validate on the server — never trust client data
- Keep payloads small — only send what's needed
- Handle missing data — check for undefined/null in handlers