# WebSocket Endpoints for Real-Time Updates in Kaneo

> Discover Kaneo's WebSocket endpoints for real-time updates: /ws/user for user events and /ws/:projectId for project updates. Enhance your application with instant data.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: api-reference
- Published: 2026-08-29

---

**Kaneo exposes two primary WebSocket endpoints at `/ws/user` for user-specific events and `/ws/:projectId` for project-scoped updates, both registered in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) and powered by Hono's WebSocket adapter with a pluggable broadcast system.**

Kaneo is an open-source project management platform that delivers live collaboration features through persistent WebSocket connections. The real-time layer is implemented in the `apps/api` directory, where the Hono framework handles connection upgrades and message broadcasting via adapter-based architecture.

## Available WebSocket Endpoints

The API defines scoped endpoints to separate user-specific notifications from project-wide activity. These routes are registered before any other `/ws/*` handlers in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts), ensuring they match incoming upgrade requests first.

### User-Scoped Endpoint (/ws/user)

The `/ws/user` endpoint streams events specific to the authenticated user. This includes personal notifications, direct mentions, and user-only broadcasts that are not visible to other project members. Connections to this route require a valid session and maintain a persistent link for the duration of the user's session.

### Project-Scoped Endpoint (/ws/:projectId)

The `/ws/:projectId` endpoint delivers real-time updates for a specific project identified by the `:projectId` parameter. This channel broadcasts task changes, activity feed entries, status updates, and other project-level events to all connected clients viewing that project. Multiple clients can subscribe to the same project ID simultaneously.

## Broadcasting Architecture

Kaneo uses an adapter pattern to handle message distribution, allowing the platform to scale from single-instance deployments to multi-server clusters. The broadcast system lives in `apps/api/src/ws/` and consists of three core components:

- **[`broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/broadcast-adapter.ts)** – Defines the `BroadcastAdapter` interface and the message schema used across all implementations.
- **[`redis-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/redis-broadcast-adapter.ts)** – Implements the adapter using Redis Pub/Sub on channels prefixed with `kaneo:ws:*`, enabling horizontal scaling across multiple API instances.
- **[`in-memory-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/in-memory-broadcast-adapter.ts)** – Provides a fallback implementation that manages connections within a single Node.js process when Redis is not configured.

The system uses `upgradeWebSocket` from Hono's `createNodeWebSocket` integration to handle the HTTP upgrade handshake in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts), after which messages are routed through the active adapter.

## Client Connection Examples

To connect to the user-scoped endpoint from a browser client:

```javascript
const socket = new WebSocket(
  `${window.location.origin.replace(/^http/, 'ws')}/ws/user`
);

socket.addEventListener('message', (event) => {
  const data = JSON.parse(event.data);
  console.log('User event received:', data);
});

```

To subscribe to project-specific updates:

```javascript
const projectId = 'your-project-id';
const socket = new WebSocket(
  `${window.location.origin.replace(/^http/, 'ws')}/ws/${projectId}`
);

socket.addEventListener('message', (event) => {
  const update = JSON.parse(event.data);
  console.log(`Project ${projectId} update:`, update);
});

```

## Server-Side Publishing

The server emits events using the `publish` or `publishToUser` functions imported from the broadcast module. When calling `publish`, the system inspects the message payload to determine the target project and forwards it to all matching connections.

```typescript
import { publish } from '@kaneo/api';

await publish({
  projectId: '12345',
  message: {
    type: 'task.updated',
    projectId: '12345',
    taskId: '67890',
    timestamp: Date.now()
  },
});

```

If the Redis adapter is active, the message is serialized and published to the `kaneo:ws:project:12345` channel, where all subscribed API instances receive it and push it to their local WebSocket connections.

## Summary

- **Two dedicated endpoints**: `/ws/user` for personal events and `/ws/:projectId` for project collaboration.
- **Central registration**: Both routes are defined in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) using Hono's WebSocket integration.
- **Pluggable adapters**: The system supports both Redis-backed and in-memory broadcast strategies via files in `apps/api/src/ws/`.
- **Scoped broadcasting**: Messages target specific users or projects, preventing unauthorized data leakage between contexts.
- **Horizontal scaling**: The Redis adapter ([`redis-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/redis-broadcast-adapter.ts)) enables real-time sync across multiple server instances using `kaneo:ws:*` channels.

## Frequently Asked Questions

### What WebSocket library does Kaneo use?

Kaneo leverages Hono's native WebSocket support through `createNodeWebSocket`, which provides the `upgradeWebSocket` method used in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts). This integration handles the HTTP upgrade process and wraps Node.js WebSocket connections for use within Hono's middleware stack.

### How does Kaneo handle WebSocket scaling across multiple servers?

When `REDIS_URL` is configured, Kaneo uses [`redis-broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/redis-broadcast-adapter.ts) to publish messages to Redis channels prefixed with `kaneo:ws:*`. All API instances subscribe to these channels and forward messages to their locally connected WebSocket clients, ensuring clients on different servers receive the same real-time updates.

### Can a client connect to multiple project WebSockets simultaneously?

Yes. Clients can open separate WebSocket connections to multiple `/ws/:projectId` endpoints concurrently, with each connection maintaining independent event streams for its respective project. There is no hard limit imposed by the server architecture in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts).

### What message format does Kaneo use for WebSocket events?

The broadcast system in [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts) defines a JSON-based schema where messages include a `type` field (e.g., `task.updated`, `activity.created`) and contextual data such as `projectId` or `userId`. All payloads are serialized to JSON strings before transmission.