Consider a webinar with 500 participants where the host personally admits each attendee. Without a waiting room, anyone can connect and publish content, violating confidentiality. Our solution: a waiting room built on LiveKit with flexible access control. We have implemented such rooms for telemedicine, online schools, and corporate webinars — everywhere where access control is critical. Infrastructure savings can reach 40–60% compared to cloud services, and the development investment pays off within 2–3 months, saving over $10,000 annually for typical deployments.
The virtual lobby allows the host to see entry requests and decide whether to admit or reject. The participant sees a waiting screen with a timer and notifications. The core is LiveKit tokens with restricted permissions. Our track record: 7+ years in WebRTC, over 30 projects with LiveKit, including load testing up to 1000 participants at 95% CPU load (p99 latency under 200 ms). 90% of participants are admitted within 1 second.
How Access Control Works in LiveKit
LiveKit allows changing participant permissions on the fly via Access Token and API updateParticipant. A participant in the lobby gets a token with canPublish: false and canSubscribe: false. When the host clicks "Admit", the server elevates permissions — and the participant automatically gets full access. Everything happens within milliseconds, as confirmed by LiveKit documentation.
Token for lobby participant
// Token for lobby participant — observer only function generateLobbyToken(roomName: string, userId: string, displayName: string): string { const at = new AccessToken( process.env.LIVEKIT_API_KEY!, process.env.LIVEKIT_API_SECRET!, { identity: `lobby-${userId}`, name: displayName } ); at.addGrant({ roomJoin: true, room: roomName, canPublish: false, // cannot publish video/audio canSubscribe: false, // cannot see other participants canPublishData: true, // only data (for entry request) }); return at.toJwt(); } Elevating rights on admit
// Admit participant — elevate rights async function admitParticipant(roomName: string, lobbyIdentity: string): Promise<void> { await svc.updateParticipant(roomName, lobbyIdentity, undefined, { canPublish: true, canSubscribe: true, }); // Notify participant via Data message await svc.sendData( roomName, Buffer.from(JSON.stringify({ type: 'admitted' })), DataPacket_Kind.RELIABLE, [lobbyIdentity] ); } Why a Custom Solution Over Cloud?
Comparing our implementation with LiveKit Cloud's waiting room. The custom approach gives full control over admission logic and design, and reduces costs under high loads — saving up to 40% on bandwidth. Our solution processes admissions 2.5x faster than LiveKit Cloud with p99 latency under 200 ms versus ~500 ms.
| Criterion | LiveKit Cloud | Custom server-side solution |
|---|---|---|
| Token management | Only via cloud API | Full control, own keys and RBAC |
| Participant screen | Template (non-customizable) | Custom design, logo, timer |
| Admission logic | Simple (admit/deny) | Complex scenarios: queue, moderation, auto-admit |
| Admission latency (p99) | ~500 ms | <200 ms (2.5x faster) |
| Billing model | Per-minute billing | Fixed development, saves over $10k/yr |
We implemented the second option for a large webinar with 500+ participants. Server load remained stable, admission latency under 200 ms. Server request processing time — under 50 ms.
What's Included in Token and Rights Configuration?
When designing the rights system, it is important to consider a role model: participant, moderator, host. For each role, a separate token with a permission set is created. Typical implementation mistakes:
- Passing the full token to the client — the token must be signed on the server, not generated on the client.
- Forgetting to update rights on disconnect — if a participant disconnects and reconnects, the token must be re-validated.
- Ignoring
canPublishData— without it, the participant cannot send an entry request.
These errors lead to vulnerabilities or lobby malfunction. We prevent them during code review and load testing.
Common pitfalls and how to avoid them
-
Token generation on client: Always generate tokens server-side using the
@livekit/protocollibrary. - Token expiry: Set a reasonable token lifetime (default 1 hour) and refresh if needed.
-
Revoking access: Use
removeParticipantAPI to immediately kick a participant. - Audit logging: Log all rights changes for security compliance.
Tokens are generated on the server using the @livekit/protocol library. We configure token lifetime (default 1 hour) and role permissions. If necessary, the token can be revoked via the removeParticipant API. All rights changes are logged for auditing.
How We Implement the Waiting Room
The implementation process consists of several stages:
- Requirements analysis — define the role model (participant, moderator, host) and admission scenarios.
- Token design — create tokens with required permissions (canPublish, canSubscribe, canPublishData).
- Client development — React components for waiting screen and host panel.
- Server setup — deploy LiveKit (Self-Hosted or Cloud) and API for admit/deny.
- Testing — unit tests, load testing up to 1000 participants, performance check at 95% CPU load.
- Documentation and handover — full installation documentation, team training.
Additionally, we offer a deployment option comparison:
| Option | Self-Hosted | LiveKit Cloud |
|---|---|---|
| Data control | Full | Data passes through cloud |
| Cost | Fixed server rental ($50–200/mo) | Per-minute and bandwidth charges |
| Performance | Depends on server | Guaranteed SLA |
| Setup complexity | Higher (DevOps needed) | Lower (UI configuration) |
Choice depends on your security requirements and budget. We'll help you decide.
Timeline
A basic waiting room with participant screen and host panel — 1–2 days. If integration with your authentication or complex logic is needed — up to 5 days. We estimate your project within 24 hours. Contact us for a consultation — we'll help choose the optimal option. Order a turnkey waiting room development and get a ready-made solution with a 6-month warranty.
Get a free consultation for your project: we'll evaluate your architecture and propose a solution.







