WatchParty: a self-hosted watch together site that syncs playback over a websocket
WatchParty: Watch anything together in-sync with your friends
At a glance
- What is it?
- WatchParty is a React, TypeScript and Node.js application for watching video together, synchronising play, pause and seek across a room and supporting screen sharing, a cloud virtual browser, WebTorrent magnet links, HLS streams, YouTube and local files converted in the browser with WebCodecs. It runs as a Vite front end plus a Node server with Redis, and every feature is optional, including login.
- Who is it for?
- WatchParty suits a group that wants to watch something together on its own infrastructure rather than on a hosted service, and that is prepared to supply the optional pieces, a Firebase project for accounts, a YouTube API key for search, a Postgres database for room persistence and Redis for the realtime layer.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What WatchParty is: a watch together site you host yourself
WatchParty is a website for watching videos together, and the project description is a single line, watch anything together in-sync with your friends. The mechanism has two parts. The video being watched is synchronised with the current room, and play, pause and seek are synced to all watchers. Everything else in the feature list is about where the video comes from, and the list is wide. It supports screen sharing, either full screen, a browser tab or an application. It can launch a shared virtual browser in the cloud, similar to rabb.it. It can play your own file, optionally converted in the browser via WebCodecs for formats browsers cannot play. It plays video files on the Internet, anything accessible via HTTP, YouTube videos, magnet links via WebTorrent, and .m3u8 streams over HLS. On top of that there are rooms created on demand for users, text chat and video chat.
Getting it running: a Vite front end, a Node server and a .env file
The Quick Start is four steps and it is worth noticing that the server and the client run as two processes. You clone the repository, install the npm dependencies, and start the server with npm run dev, which runs node with a watch path over the project so the server restarts when a file changes. The server defaults to port 8080 and is customised with the PORT environment variable, and SSL_KEY_FILE and SSL_CRT_FILE enable HTTPS. Then you start the React application in a separate shell and port with npm run ui, and point it at the server with VITE_SERVER_HOST if you changed the port. Finally you duplicate the.env.example file, rename it to.env, and add configuration for the features you want. The README notes that HTTPS is required by the browser for some WebRTC features, camera and the like, which is why the SSL variables are mentioned for both sides.
git clone [email protected]:howardchung/watchparty.git
npm install
npm run devThe virtual browser: a container running neko, reached over SSH and VNC
The most unusual capability is the shared virtual browser in the cloud, and the setup instructions reveal how it works. The project supports creating virtual browsers using neko, either on a cloud provider or with Docker containers, and for development Docker is said to be easiest. The virtual browser needs an SSH key pair set up on the server, in the ~/.ssh directory as id_rsa, generated with ssh-keygen if you do not have one, and DOCKER_VM_HOST_SSH_USER is configurable if root is not the correct user. If the web client is not on the same physical machine as the server, DOCKER_VM_HOST also has to be set to a publicly resolvable value rather than localhost, because the browser has to reach the container directly. Managed instance pools, on cloud or with Docker, are configured with VM_MANAGER_CONFIG and the vmWorker service. The npm scripts show how this is exercised in development, with a testvBrowser script running a container with a display, a neko password, a bind port and an H264 flag.
Optional features, and the Firebase configuration that unlocks accounts
The Advanced Setup section says all of these are optional and the application should work without them, although some functionality may be missing. The YouTube API section covers video search, which needs a YouTube Data API V3 key, and without one you cannot search for videos via the searchbox, so a YouTube URL still plays but the search does not work. The Firebase section covers user authentication, which is used for user login, account management, subscriptions, and handling features like room locking and permanence. The setup is a Firebase web app whose SDK configuration JSON you stringify in the browser console and put in VITE_FIREBASE_CONFIG, and for server verification of accounts you also need FIREBASE_ADMIN_SDK_CONFIG, produced the same way. The .env.example file confirms the shape, and it includes a commented Firebase configuration block and a note that leaving VITE_FIREBASE_CONFIG blank allows access to all features without login.
Room persistence needs Postgres, and Redis sits underneath the realtime layer
Room Persistence is a short section with a clear dependency. You configure Postgres by adding DATABASE_URL to the .env file and then setting up the database schema, and that is what allows rooms to persist between server restarts. The repository has a sql/ directory for the schema and a .env.example line showing a connection string of the form postgresql://postgres@localhost:5432/postgres?sslmode=disable. The Tech list at the end of the README names the stack: React, TypeScript, Node.js, Redis, PostgreSQL and Docker. Redis is not given its own configuration section in the README, only a REDIS_URL line in the .env.example, which suggests it is the pub-sub and presence layer rather than the durable store. The distinction matters for deployment planning, because Postgres is what you lose if you misconfigure it and Redis is what you lose if the rooms go blank, and the two are configured in completely different places.
The deployment scripts, and a Dockerfile that is four instructions
The package.json describes how the thing is run in production. start runs the server file directly with node, and pm2 starts it under the process manager, and deploy is a hard reset to the origin/release branch followed by pm2 flush, pm2 delete all and a start from an ecosystem config file. The build script chains the React build with the type checking, and there are separate typecheck scripts for the server and the client, the client one using noEmit. The Dockerfile is unusually short: it starts from node 24 on alpine, copies the source to /usr/src, runs npm ci, runs the build, and sets the entrypoint to run npm start. There is also a dev/ directory, a words/ directory, a global.d.ts, a vite.config.ts, and a CHANGELOG.md. The releases are dated rather than versioned, with tags for 2025-11-09, 2025-01-30 and 2024-03-19, and the last push to the repository was on 2026-10-14.
FROM node:24-alpine
COPY . /usr/src
WORKDIR /usr/src
RUN npm ci
RUN npm run build
ENTRYPOINT ["/bin/sh", "-c" , "npm start"]What the media support list implies about scope
The source list is a good summary of what the project is willing to take on, and it spans four quite different mechanisms. YouTube goes through the YouTube API for search and the ordinary player for playback. Magnet links go through WebTorrent, which means peer to peer and a tracker, with the legal and practical weight that carries. HLS streams are just a URL the player understands. A local file is converted in the browser via WebCodecs when the format is one the browser cannot play, which is a genuinely clever solution to the file format problem and moves the transcode to the client. A shared virtual browser covers everything else, because anything a browser can play, a browser in a container can play, and that container is shared between the viewers. The cost of that last one is the SSH, VNC and H264 configuration described above.
Licence, community and the shape of the project
The licence is MIT, with the LICENSE file at the repository root, and the homepage is watchparty.me. The project has a hacktoberfest topic, which tells you it is a project that takes outside contributions, and the repository has a .github/ directory with the workflows. The last push was on 2026-10-14 and the repository is not archived, and the release tags are dated snapshots rather than semantic versions, so there is no way to pin a version by a version number. The application version in package.json is 0.1.0 and the package is marked private, so the repository is not published as a reusable library. The realistic evaluation is that this is a well-featured, self-hostable application that a group can run for itself, with a feature set that goes well beyond simple video synchronisation and a configuration surface that grows with each optional feature you turn on.
Editorial conclusion
WatchParty suits a group that wants to watch something together on its own infrastructure rather than on a hosted service, and that is prepared to supply the optional pieces, a Firebase project for accounts, a YouTube API key for search, a Postgres database for room persistence and Redis for the realtime layer. It is the wrong choice for a group that just wants a link, because the room and the account handling live in your deployment, and a poor fit if you need DRM, since a browser based player and a virtual browser in a container are not a path to protected content. Before adopting it, copy .env.example to .env and decide which features you actually need, because the project states that the application should work without any of them and that some functionality may be missing, and note that HTTPS is required by the browser for some WebRTC features.
Frequently asked questions
What media sources can WatchParty play?
It supports screen sharing of a full screen, browser tab or application, a shared virtual browser in the cloud, your own files optionally converted in the browser via WebCodecs, video files on the Internet accessible via HTTP, YouTube videos, magnet links through WebTorrent, and .m3u8 streams over HLS.
How do I run WatchParty locally?
Clone the repository, run npm install, then start the server with npm run dev, which defaults to port 8080 and is customised with the PORT variable. Start the React app separately with npm run ui and point it at the server with VITE_SERVER_HOST, then copy .env.example to .env and add the config for the features you want.
Do I need Firebase to use WatchParty?
No, the advanced setup is described as optional and the application should work without it, though some functionality may be missing. Firebase is used for user login, account management, subscriptions and room locking or permanence, and leaving VITE_FIREBASE_CONFIG blank allows access to all features without login.
How do rooms persist between server restarts in WatchParty?
You configure Postgres by adding DATABASE_URL to the .env file and then setting up the database schema. The .env.example shows a connection string of the form postgresql://postgres@localhost:5432/postgres?sslmode=disable. Redis is a separate optional URL used alongside it.
How does the WatchParty virtual browser work?
The project supports creating virtual browsers using neko on a cloud provider or with Docker containers, and Docker is easiest for development. You need an SSH key pair on the server, DOCKER_VM_HOST_SSH_USER if root is wrong, and DOCKER_VM_HOST set to a publicly resolvable value if the web client is on a different machine. Managed instance pools need VM_MANAGER_CONFIG and the vmWorker service.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/howardchung-watchparty)Was this useful?