Documentation

Everything you need to add Dendri to your app — or run the whole stack yourself.

Quickstart

Install the framework-neutral client:

npm install @afterrealism/dendri-client

Create a store and join a room. On the hosted tier, pass your url and apiKey:

import { createDendriStore } from "@afterrealism/dendri-client";

const room = createDendriStore({
  url: "wss://signal.dendri.dev",
  apiKey: "dk_your_key",
});

room.subscribe(() => {
  console.log(room.connectionState, room.peers);
});

room.join("design-review");
room.broadcast({ type: "cursor", x, y });
Where's my API key? Grab a plan on the pricing page; the key arrives by email. Manage and rotate it any time in the dashboard.

Configuration

The client takes a single URL plus an optional key. Self-hosters can pass the parts individually instead.

OptionTypeNotes
urlstringFull server URL, e.g. wss://signal.dendri.dev.
apiKeystringTenant key for the hosted tier.
host / port / secure / pathstring / number / bool / stringSelf-host alternative to url.
signalingTransport"websocket" | "sse" | "polling" | "auto"Transport, or auto-fallback. Default websocket.
enableRelayboolAllow encrypted TLS relay when P2P fails.

Framework bindings

Official bindings ship as subpath exports. The Svelte adapter has no dependency; React and Vue are optional peers.

// React
import { useDendriStore } from "@afterrealism/dendri-client/react";
const { connectionState, peers } = useDendriStore(room);

// Vue
import { useDendriStore } from "@afterrealism/dendri-client/vue";

// Svelte
import { toSvelteStore } from "@afterrealism/dendri-client/svelte";

For collaborative editing, the @afterrealism/dendri-y package bridges a Yjs document over a Dendri room.

Self-hosting

The signaling server is open source (AGPL-3.0) and free to run. Point the SDK at your own host instead of the hosted endpoint — the client API is identical.

const room = createDendriStore({
  host: "signal.example.com",
  port: 443,
  secure: true,
  path: "/",
});

Run the Rust server from source, or use the Podman/Quadlet stack in dendri-infrastructure/. You'll want a TURN server (coturn) alongside it for peers behind strict NATs. See the server repo for deploy details.

No hidden defaults. The SDK never connects anywhere on its own — you always pass an explicit endpoint, whether that's your server or ours.

Architecture

Dendri is signaling, not a media relay. It brokers the WebRTC handshake, then gets out of the way so data flows peer-to-peer. When a direct connection isn't possible, it degrades gracefully:

TierPathWhen
1Direct P2PSame network or open NAT.
2STUNPeers discover public addresses.
3TURNSymmetric NAT — relay through coturn.
4TLS relayEverything else — encrypted relay through the server.

The signaling server itself is a small Rust (Axum/Tokio) binary backed by Redis-compatible storage, with multi-transport support (WebSocket, HTTP/SSE, long-poll) so it works through hostile proxies.

Licensing

The client SDKs (@afterrealism/dendri-client, @afterrealism/dendri-y) are Apache-2.0 — use them anywhere. The signaling server is AGPL-3.0, or available under a commercial licence from Afterrealism for closed-source hosted use.

Need something that isn't here? Open an issue on GitHub.