FAQ and Limits
Quota and hard limits, authentication and networking questions, current implementation boundaries and known gaps.
This page collects the hard limits, deployment boundaries and common questions that matter most during integration.
Hard limits
| Item | Limit | Notes |
|---|---|---|
| Channel name | 1–128, character set [A-Za-z0-9_-] | Enforced by the server |
| rtcUid | 1..2147483647, never 0 | Checked when issuing a token and joining a channel |
| Token TTL | 60–86400 seconds | Finally clamped by the project's tokenTtlSeconds |
| Privilege window | min(ttl, project.privilegeTtlSeconds) | Privilege lifetime is separate from token lifetime |
| Renewal grace | renewal is allowed for 300 seconds after privileges expire | Re-issue the token afterwards |
| Expiry lead time | 30 seconds | Client event + callback 203 |
| uid mapping batch | at most 200 uids per call | POST /v1/uids:resolve |
| Quality sample batch | at most 5000 records per call | POST /v1/analytics/quality |
| Pagination | page_no ≥ 0, page_size 1–500, default 100 | Shared by list endpoints |
| Request body size | 2 MiB | 413 above the limit |
| Write request Content-Type | must be application/json | Otherwise 415 |
| Ban duration (platform) | 0–86430 seconds, default 600 (kick/mute), 3600 (rule) | 0 expires immediately |
| Ban duration (Agora-compatible) | time 0–1440 minutes or time_in_seconds 0–86430 | /dev/v1/kicking-rule |
| Recording maxDuration | 10–86400 seconds | Stops automatically after the limit |
| Streaming idleTimeout | 0–86400 seconds, default 300; 0 disables reclamation | Reclaimed when nobody is watching |
| entryPoint / streamName | [A-Za-z0-9_-], length 1–64 / 1–128 | Bypass streaming |
| Project default quotas | recording concurrency 5, streaming concurrency 5, unlimited channels | Adjustable in the console |
| Egress concurrency | 8 concurrent / 200 queued / 1000 ms polling | Configurable in self-hosted deployments |
Deployment boundaries
- Local development uses in-memory storage by default: after a restart, projects, credentials, channels, jobs, callback records and quality samples are cleared, and the demo project and credentials are regenerated. For production, use persistent storage as described in Self-hosted deployment.
- The control plane is designed as a single replica: the cloud-recording
resourceIdregistry, job scheduling and callback delivery live inside the control-plane process. Before scaling out, externalise the session state or pinacquire→startto the same replica. - Local development uses a media simulator by default: without an external SFU the in-memory SFU simulator is used; behaviour is testable but it is not real media. Connect LiveKit in production.
- Operator endpoints are not exposed publicly: they are reachable only from the cluster network; the public reverse proxy exposes
/v1/*,/dev/v1/*and/console/*only.
What each platform can do
- The current version supports token issuing and renewal, channel and user management, bans and mute, Cloud Recording, bypass streaming, Media Push / Pull / Gateway, cloud transcoding, Analytics, callbacks and error codes.
- Content Inspect, E2EE, channel media relay and client-side direct CDN push are not available in the current version; the corresponding methods return
-4(ERR_NOT_SUPPORTED). - AI (transcription, noise suppression, conversational AI) is outside the current product scope; only callback hooks are reserved.
- Recording files support local object storage; for S3/OSS see the storage configuration in Self-hosted deployment.
FAQ
Q: Can I hand a token straight to the browser? Yes, but only a short-lived token, and never together with customerSecret / appCertificate. If a token in the browser leaks, an attacker can at most use it within its validity window; a leaked secret means the project is compromised.
Q: Why does a request using a dev/v1 appid return 401 invalid_appid? The appid in a /dev/v1/* path must belong to the project of the current Basic credential. Cross-project access is rejected.
Q: Why does recording stay in starting? Check Egress node capacity and the job queue. In a real LiveKit environment Egress starts asynchronously and usually becomes running within seconds.
Q: Can the streaming URL be played directly? rtmpUrl is the ingest URL (for OBS/cloud streaming); use hlsUrl for playback. HLS has segment latency (a few seconds up to a dozen or so), so use RTC for interactive scenarios.
Q: What do I do when callbacks keep failing? Start with lastStatusCode / lastError from GET /v1/webhook/deliveries: 401/403 usually means a signature-verification bug on your side (using JSON.stringify(JSON.parse(body)) instead of the raw body); for timeouts, return 200 first and process asynchronously; you can replay manually within the retry budget.
Q: How do I verify my local environment? Follow the Quickstart to start the service and run the sample scripts; the samples check the health endpoint first, then verify the token, channel and telemetry paths in order.