Open-source, developer-first real-time communication infrastructure. Raven lets a developer add real-time video, voice, chat, and data to their own application — create a project, create a room, generate a token, join, publish, message — without operating WebRTC or WebSocket infrastructure themselves.
Raven is infrastructure, not a video-calling app. Category peers: LiveKit
Cloud, Daily, Agora. See docs/architecture/ for the technical
architecture decisions.
Phase 13 of 19 — control plane, signaling, real WebRTC media (LiveKit +
coturn), a production-oriented TURN/NAT-traversal setup, a TypeScript
browser SDK (@corvidhq/rtc), React hooks/components on top of it
(@corvidhq/react), a developer dashboard (apps/dashboard), a terminal
CLI (@corvidhq/cli), a first observability/diagnostics layer, official
backend SDKs for TypeScript (@corvidhq/server) and Python (raven-sdk),
and — new in Phase 12 — a full real-time chat service (@corvidhq/chat)
with durable messages, presence, typing, read receipts, reactions,
threads, attachments and webhooks. All working end to end and verified
live, plus — new in Phase 13 — official mobile SDKs for React Native
(@corvidhq/react-native) and Flutter (raven_rtc + raven_chat),
covering RTC and messaging on iOS and Android. No recording, live
streaming, usage metering/billing, or a Go/Java/etc. SDK yet.
- Control plane (
apps/api, Phase 2): auth, projects, API keys, rooms, RTC tokens (now including TURNiceServers) — NestJS modular monolith, PostgreSQL (Prisma), Redis. - Signaling (
apps/api, Phase 3): a raw WebSocket gateway at/v1/rtc— authentication, room join/leave, participant presence, SDP offer/answer and ICE candidate routing. Metadata only, never media. Not used for the media path itself — seedocs/sfu.md. - RTC plane (Phase 0/1/4/5): LiveKit as the SFU and signaling layer for real media, coturn for TURN/STUN, with time-limited credentials issued per RTC token and a documented production NAT-traversal setup.
- Browser SDK (
packages/sdk, Phase 6):@corvidhq/rtc— join a room, publish camera/microphone, subscribe to remote media, without ever touching SDP, ICE, orRTCPeerConnectiondirectly. - React SDK (
packages/react-sdk, Phase 11):@corvidhq/react— hooks (useRaven,useConnectionState,useParticipants,useCamera, ...) and optional components (RavenRoom,ParticipantView, ...) on top of@corvidhq/rtc, which itself was not changed to build this — headless by default, no UI lock-in. - Dashboard (
apps/dashboard, Phase 7): create an account, manage projects and API keys, inspect rooms and their live LiveKit participant state, and read SDK integration instructions — a thin, server-rendered UI over the same Control API, never a second source of truth. - CLI (
packages/cli, Phase 8):@corvidhq/cli—raven login,raven projects create,raven init,raven dev— a terminal workflow tool over the same Control API, with browser-based auth (no password paste) and no direct access to the database, Redis, LiveKit, or coturn. - Observability (
apps/api, Phase 9): best-effort telemetry from@corvidhq/rtc(never blocking, never able to break an RTC connection) event-sources a realConnection/ErrorEventhistory, classified into Raven-facing categories (TOKEN_ERROR,ICE_ERROR,TURN_ERROR, ...) — surfaced in the dashboard's Connections/Errors tabs and viaraven connections/raven errors/raven diagnostics. - Chat (
apps/api, Phase 12): a messaging service that is entirely separate from the RTC plane — its own WebSocket gateway at/v1/chat/ws, its own short-lived tokens, PostgreSQL as the source of truth for messages and Redis for presence/typing/fan-out. A message is only acked once it is durably stored, retries are idempotent, and an offline client catches up from history rather than from the socket. Either plane can be used without the other, and either can fail without taking the other down. - Chat SDK (
packages/chat-sdk, Phase 12):@corvidhq/chat— connect, send, and listen without writing anew WebSocket(...), a reconnect loop, or a heartbeat.@corvidhq/reactgained matching hooks (useMessages,usePresence,useTyping,useReactions,useReadReceipts) alongside its existing RTC ones. - Webhooks (
apps/api, Phase 12): project-scoped, HMAC-signed, retried with exponential backoff, delivered by a worker that never sits on the message path. - Mobile SDKs (
packages/react-native-sdk,sdks/flutter, Phase 13):@corvidhq/react-nativereuses@corvidhq/rtcand@corvidhq/chatunmodified — React Native gets the WebRTC globals it lacks, and only rendering, permissions, app lifecycle and audio routing are platform-specific.raven_rtcandraven_chatare idiomatic Dart packages with the same concepts. A developer who knows Raven Web knows both. - Server SDKs (
packages/server-sdk,sdks/python, Phase 10):@corvidhq/serverandraven-sdk— mint short-lived RTC tokens and read rooms/connections/errors/metrics/diagnostics from your own backend using a permanent project API key, which never reaches a browser. Both also mint Raven Chat tokens and provision conversations (raven.chat.*). Same Control API every other client uses, no new endpoints invented beyond a couple of small API-key-guarded mirrors of existing dashboard reads.
Full rationale: docs/architecture/infrastructure-decisions.md,
docs/control-plane.md, docs/signaling.md, docs/sfu.md,
docs/media-flow.md, docs/turn.md, docs/nat-traversal.md,
docs/sdk.md, docs/dashboard.md, docs/cli.md, docs/observability.md,
docs/telemetry.md, docs/diagnostics.md, docs/error-codes.md,
docs/sdk/server/typescript.md, docs/sdk/server/python.md,
docs/security/server-sdk.md, docs/sdk/web.md, docs/sdk/react.md,
docs/chat/ (overview, architecture, websocket, messages, presence,
typing, read-receipts, reactions, threads, attachments, webhooks),
docs/sdk/chat.md, docs/security/chat.md, docs/sdk/react-native.md,
and docs/sdk/flutter.md.
cp .env.example .env # then fill in real local secrets
pnpm infra:up # start Postgres, Redis, LiveKit, coturn, api
pnpm infra:verify # confirm everything is healthy
pnpm db:seed # optional: demo developer + project + API key + roomInteractive API docs: http://localhost:4100/docs. Full instructions,
ports, and troubleshooting: docs/local-development.md.
To also run the dashboard locally:
pnpm --filter @raven/dashboard build
pnpm --filter @raven/dashboard start # http://localhost:3000The intended developer path through this repo:
- Dashboard (
apps/dashboard) — register, create a project, create an API key. - Quickstart tab (in the dashboard, per-project) — copy the exact
install command and code for your backend (token minting) and frontend
(join/publish/subscribe), matching the real
@corvidhq/rtcAPI. - SDK (
packages/sdk,@corvidhq/rtc) — the browser package those snippets use. Full reference:docs/sdk.md.
See docs/dashboard.md for the dashboard's own architecture,
authentication/authorization model, and security notes.
raven login # browser-based auth, no password paste
raven projects create my-video-app
raven init # link this directory (writes raven.json)
raven sdk install # installs @corvidhq/rtc via your package manager
raven dev # confirms this directory is ready for RTC developmentraven talks only to the Control API (never the database, Redis,
LiveKit, or coturn directly) and mirrors the dashboard's own security
model — API key secrets are shown exactly once, and the only thing it
stores permanently on disk is a session token under ~/.raven/
(600/700 permissions). Full reference: docs/cli.md. Canonical
walkthrough: examples/cli-workflow.md.
npm install @corvidhq/server # TypeScript / Node.js
pip install raven-sdk # Pythonimport { Raven } from '@corvidhq/server';
const raven = new Raven({ apiKey: process.env.RAVEN_API_KEY! });
const token = await raven.tokens.create({ room: roomId, identity: 'user-42' });
// hand `token` straight to your frontend — never mint one in the browserfrom raven import Raven, CreateTokenParams
raven = Raven(api_key=os.environ["RAVEN_API_KEY"])
token = raven.tokens.create(CreateTokenParams(room=room_id, identity="user-42"))Both wrap the same Control API every other client (dashboard, CLI,
@corvidhq/rtc) uses — a permanent API key that never reaches a browser,
short-lived RTC tokens, and read access to rooms/connections/errors/
metrics/diagnostics. Full reference: docs/sdk/server/typescript.md,
docs/sdk/server/python.md, security model: docs/security/server-sdk.md.
Runnable examples: examples/node-server/, examples/python-server/.
npm install @corvidhq/rtc @corvidhq/react'use client';
import { RavenRoom, useConnectionState, useCamera, ParticipantView, useLocalParticipant } from '@corvidhq/react';
function CallPage({ token, endpoint, room }) {
return (
<RavenRoom token={token} endpoint={endpoint} room={room} fallback={<p>Connecting…</p>}>
<Call />
</RavenRoom>
);
}
function Call() {
const state = useConnectionState();
const camera = useCamera();
const local = useLocalParticipant();
return (
<>
<p>Status: {state}</p>
<button onClick={() => (camera.enabled ? camera.disable() : camera.enable())}>Toggle camera</button>
{local && <ParticipantView participant={local} />}
</>
);
}Headless hooks (useRaven, useConnectionState, useParticipants,
useCamera, useMicrophone, ...) plus optional components
(RavenRoom, ParticipantView, RavenVideo, RavenAudio) — nothing
required beyond the hooks if you'd rather build your own UI. @corvidhq/rtc
itself is unchanged (see docs/sdk/web.md for the small, additive gaps
Phase 11 closed). Full reference: docs/sdk/react.md. Runnable example:
examples/react-video-call/.
Chat is a separate service from RTC, with its own SDK and its own credential. Use either alone, or both together.
npm install @corvidhq/chatYour backend mints a short-lived, per-user token (never ship a project API key to a browser):
import { Raven } from '@corvidhq/server';
const raven = new Raven({ apiKey: process.env.RAVEN_API_KEY });
const conversation = await raven.chat.createConversation({
name: 'support-room-42',
members: [{ userId: 'alice', role: 'ADMIN' }, { userId: 'bob' }],
});
const token = await raven.chat.createToken({
userId: 'alice', // from YOUR session, not the request body
conversations: [conversation.publicId],
});The browser gets three lines:
import { createChatClient } from '@corvidhq/chat';
const chat = createChatClient({ token: token.token, apiUrl: token.apiUrl });
await chat.connect({ room: conversation.publicId });
chat.on('message', (message) => console.log(`${message.senderId}: ${message.text}`));
await chat.sendMessage({ text: 'Hello everyone!' });No new WebSocket(...), no reconnect loop, no heartbeat, no ordering
logic, no dedupe. sendMessage() resolves only once the message is
durably in PostgreSQL, retries are idempotent, and a client that was
offline catches up from history rather than from the socket.
React:
import { RavenChat, useMessages, useTyping } from '@corvidhq/react';
<RavenChat token={token.token} apiUrl={token.apiUrl} room={roomId}>
<ChatPanel />
</RavenChat>Full reference: docs/sdk/chat.md. Runnable examples: examples/chat/
(chat alone) and examples/rtc-chat/ (a video call with a chat panel).
docs/architecture/— Phase 0 architecture decisions (WebRTC fundamentals, SFU comparison, TURN, signaling)docs/local-development.md— Phase 1 local infrastructure setupdocs/control-plane.md— Phase 2 API design (auth model, data model, RTC token permission mapping)docs/signaling.md/docs/signaling-protocol.md— Phase 3 WebSocket signaling layer and wire protocoldocs/sfu.md/docs/media-flow.md— Phase 4 SFU integration, TURN, and why media never touches the API or signaling serverdocs/turn.md/docs/nat-traversal.md— Phase 5 STUN/TURN reliability, production NAT-traversal checklist, and known local-environment limitsdocs/sdk.md— Phase 6 browser SDK (@corvidhq/rtc) API referencedocs/dashboard.md— Phase 7 dashboard architecture, auth/authorization, and security audit notesdocs/cli.md— Phase 8 CLI reference: authentication, config storage, commands, JSON output, exit codes, and security notesdocs/observability.md— Phase 9 architecture, data model, metrics, retention, and privacydocs/telemetry.md— Phase 9 what@corvidhq/rtcreports and how (best-effort, never blocking RTC)docs/diagnostics.md— Phase 9 the two diagnostic surfaces (server-side project diagnostics vs. client-sideroom.getDiagnostics())docs/error-codes.md— Phase 9 error categories and their explanationsdocs/sdk/server/typescript.md— Phase 10@corvidhq/serverreferencedocs/sdk/server/python.md— Phase 10raven-sdk(Python) referencedocs/security/server-sdk.md— Phase 10 server SDK security model (API key storage, authorization model, short-lived tokens)docs/sdk/web.md— Phase 11@corvidhq/rtcadditions (browser support, Next.js usage) — seedocs/sdk.mdfor the full API, unchangeddocs/sdk/react.md— Phase 11@corvidhq/reactreference: hooks, optional components, Next.js, Strict Modedocs/chat/overview.md— Phase 12 Raven Chat: what it guarantees, how authorization works, limits, retentiondocs/chat/architecture.md— Phase 12 services, PostgreSQL/Redis split, fan-out across instances, Redis key conventions, and measured load limits (with what those numbers do and don't mean)docs/chat/websocket.md— Phase 12 wire protocol, authentication, close codes, heartbeats, and the reconnection contractdocs/chat/messages.md— Phase 12 sending, idempotency, cursor pagination, editing, soft deletion, delivery semanticsdocs/chat/presence.md/typing.md/read-receipts.md/reactions.md/threads.md— Phase 12 per-feature referencesdocs/chat/attachments.md— Phase 12 signed direct-to-storage uploadsdocs/chat/webhooks.md— Phase 12 events, signature verification, retries, and idempotencydocs/sdk/chat.md— Phase 12@corvidhq/chatreferencedocs/security/chat.md— Phase 12 chat security audit, including residual risksdocs/sdk/react-native.md— Phase 13@corvidhq/react-nativereference: quickstart, permissions, video rendering, lifecycle, audio routing, troubleshootingdocs/sdk/flutter.md— Phase 13raven_rtc/raven_chatreference, including where the Dart API deliberately diverges and whyexamples/signaling-demo/— minimal two-tab browser demo of the signaling layer (no build step, no media)examples/media-demo/— minimal two-tab browser demo of real camera/microphone media through@corvidhq/rtc, plus a small Python backend usingraven-sdk(no frontend build step)examples/video-call/— minimal two-tab browser demo built entirely on@corvidhq/rtc's public API (no raw WebRTC types)examples/cli-workflow.md— the canonicalraven login→projects create→init→sdk install→devflowexamples/node-server/— Express backend minting RTC tokens with@corvidhq/serverexamples/python-server/— FastAPI backend minting RTC tokens withraven-sdkexamples/react-video-call/— real, buildable React app (Vite) using@corvidhq/react's hooks and components — camera/mic/screen-share/device selection/participants/leave/reconnect statusexamples/chat/— real chat app (Vite + Express) on@corvidhq/chat: history, typing, presence, read receipts, reactions, editing, deleting, reconnection. No mock message arrays anywhereexamples/rtc-chat/— a video call with a chat panel:@corvidhq/rtcand@corvidhq/chatside by side, independent connections, independent failure modesexamples/mobile-rtc-chat/— React Native app: a video call with a chat panel, on a phoneexamples/flutter-rtc-chat/— the same thing in Flutterscripts/chat-load-test.mjs— the load test behind the numbers indocs/chat/architecture.md#measured-limits