Built on LiveKit · multi-node · zero-config start

One node per room,one publish URL per person.

Push your screen to everyone in the room — with OBS, or with nothing but a browser. Each room is bound to its own LiveKit credentials, so its media traffic and free tier burn on that node and nobody competes for anyone else's.

  • Two environment variables to run
  • WHIP passthrough, no transcode quota
  • Authorisation at the protocol layer
LiveKit nodesSeparate quotas
Node AYours
wss://your-project.livekit.cloud
7K3M9Q3 onlineB2W8XRIdle
Node BA colleague's
wss://her-project.livekit.cloud
QF4L2N1 online
Built-in nodeAdmin-shared · 20 rooms max
wss://mx-builtin.livekit.cloud
M9ZP6T5 online

A room lives on exactly one node — its traffic and its free tier are charged there.

01 · Publish routes

There are two publish routes, and they are separate

The browser route touches this site exactly once — to get a token; after that the video goes straight to LiveKit. The OBS route needs an ingress created on the server first. That's why turning off "OBS publishing" leaves browser sharing working.

Share from the browser

BrowsergetDisplayMediaLiveKit node

One click, nothing to install. 1920×1080@15fps — desktop sharing favours resolution over frame rate. The video passes through neither Vercel nor Ingress.

Publish with OBS (WHIP)

OBSWHIP passthroughIngressLiveKit node

In the room, click "Generate publish URL", then put the Server and Bearer Token into OBS's stream settings (service: WHIP). Passthrough means no transcoding, so it barely touches the machine and never eats the 60-minute quota.

02 · Why bring your own node

The free tier is a pilot allowance, not a product allowance

LiveKit Cloud's free Build plan is metered per project; over the limit, requests simply fail and nothing is billed — and multiple free projects on one account share a single allowance.

5,000WebRTC participant minutes. Publishers don't count — only viewers burn them
50 GBEgress bandwidth. In most scenarios this is the wall you hit first
60 minutesTranscode quota. RTMP input always transcodes — one hour a month
Publish bitrateViewer minutes on 50 GBIn viewer hours
4 Mbps1080p high bitrate
1,667≈ 28 h
2.5 Mbps1080p typical
2,667≈ 44 h
1.5 Mbps720p
4,444≈ 74 h
0.8 MbpsLow bitrate
5,000≈ 83 h

About 1.33 Mbps is the dividing line: above it the 50 GB of bandwidth runs out first, below it the 5,000 minutes do. Viewer hours still get divided by the number of viewers — one person sharing to three at 1080p is roughly 15 hours a month.

So this project makes nodes a first-class citizen: everyone connects their own project, and the allowance goes from "one for the whole site" to "one each". The built-in node is only there as a fallback — remember to cap its room count.

03 · Features

Everything that matters is enforced on the server

A check you can bypass in the client is not a check. All of the following happen where tokens are signed and ingresses are created.

Authorisation at the protocol layer, not front-end filtering

Not in the member table → no token → no connection → no track subscription. The grant's room field holds exactly one room name, so the token physically cannot open another one. Non-members always get a 404, so a room code reveals nothing.

Bring your own node, burn your own quota

Connect your own LiveKit Cloud project and pick which set to use per room. Before saving, this site runs a real API health check with those credentials — wrong ones are never stored — and it also probes whether Ingress works and marks that on the node.

OBS over WHIP passthrough

enableTranscoding: false — it doesn't eat the 60 transcode minutes a month. One publish URL per person, rotatable and revocable; stream keys are encrypted at rest and only decrypted back to their owner.

"OBS publishing" is a real switch

When the owner turns it off, anything currently publishing drops: the ingress is deleted so old keys can never connect again, and the obs: participant is removed from the room. Not a flag that says "off" while the stream keeps flowing.

Synchronised playback

The owner opens a player and the whole room watches the same source. Position is broadcast over LiveKit's data channel, aligned after estimating the clock offset between machines with ping/pong; video bytes never touch this service.

Invite links

Only the hash of a token is stored; links can carry an expiry, a usage cap, and be revoked at any time. Redemption claims a slot atomically with a conditional UPDATE, so concurrency can't punch through max_uses; opening one while signed out routes through sign-in and then joins automatically.

Two environment variables to run

DATABASE_URL and ADMIN_PASSWORD. The admin account is created on first start, the credential encryption key generates itself into the database if unset, and LiveKit is configured in the web UI rather than in env vars. There is no install wizard.

Somewhere to look when it breaks

Rooms have an expandable audit log (it never records a secret). /api/health needs no sign-in and reports item by item: database reachability, whether all 12 tables exist, whether bootstrap ran — it lists exactly which tables are missing so you don't have to guess from a stack trace.

04 · Quick start

Three steps to run your own

This site ships no media server, so all you really need is a database and one set of LiveKit credentials.

1

Fill in two environment variables

Copy .env.example to .env.local — Next doesn't read the former, so editing the wrong file does nothing at all.

DATABASE_URL=postgresql://…@ep-xxx-pooler…/neondb?sslmode=require
ADMIN_PASSWORD=pick-your-own-password
2

Create the tables, start it

npm install
npm run db:migrate # creates 12 tables
npm run dev

Then sign in with admin@localhost and the password above: the admin account is created on first start, and there is no install wizard. On Vercel the migration is already wired into the build, so you don't run this by hand.

3

Connect a LiveKit node

Sidebar "LiveKit nodes" → "Connect a node", then fill in the wss:// URL and the API Key / Secret. LiveKit Cloud's free Build plan needs no card and takes about three minutes to get those three values; before saving, this site verifies them for real and refuses to store wrong ones.

Self-hosted LiveKit works too (the URL field accepts ws://), but publishing from OBS then requires deploying Ingress and Redis yourself.

05 · Preview

We're considering a desktop app:MX-Desktop-Sharing-APP

Self-hosted, end-to-end encrypted chat that can also share your screen — this site is only the screen half; the chat half can't be done cleanly in a browser.

Concept stage

Development hasn't started and there's no timeline — this section is a preview. It's here to find out whether anyone actually needs it, because that's what makes it worth building.

End-to-end encryption

Messages and shared content are encrypted and decrypted on the endpoints; the server only relays ciphertext — owning the server still doesn't reveal the conversation.

Self-hosted

Run the server yourself: accounts, messages and keys never have to be handed to a third party. Like this site, and with none of that mandatory phone-home activation.

Chat and screen in one place

Text, files and screen sharing in a single client, instead of running a meeting app next to a chat app.

Native desktop

Windows / macOS / Linux clients rather than a browser tab — capturing a whole desktop, staying resident, and starting with the system are things a browser can't give you.

If you're interested, or think something above is wrong, say so. The single most useful piece of feedback is what you would replace with it — far more valuable than "nice idea".

06 · Q&A

Frequently asked

Every answer below can be traced to the code or the README. For anything not covered here, use the two links in the previous section.

Do I need to provide a server?
No media server. This site deploys to Vercel + Neon (both have free tiers), video goes through LiveKit Cloud, and all you need is one set of LiveKit credentials — the free Build plan needs no card. Fully self-hosting works too: the URL field accepts ws://, but publishing from OBS then means deploying Ingress and Redis yourself.
How long does the free tier actually last?
In most cases you hit the 50 GB of egress before the 5,000 participant minutes. One person sharing to three viewers at 1080p is roughly 15 hours a month. That's why this project lets everyone connect their own LiveKit project: the allowance goes from "one for the site owner" to "one each".
Does the video pass through your servers?
No. For browser sharing this site is contacted exactly once — to get a token; after that the video connects straight to the LiveKit node. The sync player goes further: video bytes are fetched by your own browser directly from the source with Range requests, passing through neither this service nor LiveKit.
Do I have to install OBS?
No. One click shares from the browser (getDisplayMedia, 1920×1080@15fps — desktop sharing favours resolution over frame rate). The OBS route is for people who want multiple scenes, transitions and overlays; it uses WHIP passthrough and eats no transcode quota.
Can anyone with the room code get in?
No. The member table is the only thing authorisation looks at: not in it means no token, which means no track subscription. A signed token carries exactly one room name, so it physically cannot open another room; non-member requests always return 404, so you can't even learn whether a room exists.
If I turn off "OBS publishing", does a live stream drop?
Yes, immediately. At that moment the server deletes the ingress (old stream keys can never connect again) and removes the obs: participant from the room. It is not a flag that flips the label to "off" while the stream keeps flowing. Browser sharing is a separate route and is unaffected.
If the database is stolen, do third-party secrets leak with it?
No. GitHub / Google / Turnstile / Resend secrets are AES-256-GCM encrypted before they are stored, and the master key can live outside the database via CREDENTIAL_ENCRYPTION_KEY. No endpoint returns a plaintext secret; the admin UI shows a mask.
Can I keep it to myself and block strangers from signing up?
Yes. Admin → "Site settings" → turn off "Allow sign-ups": email/password registration, a first third-party sign-in and a first email-code sign-in are all blocked together and told "sign-ups are disabled on this site", while existing accounts sign in as usual. It's enforced on the server, not by hiding a button.
07 · Start here

Create a room, push your screen over

Signing up gives you your own workspace, where you can connect your own LiveKit nodes. If you were sent an invite link, just open it and sign in — you'll join the room automatically.

  1. 1Create a room
  2. 2Send the invite link
  3. 3Push your screen