An independent Chrome extension and realtime backend for synchronized listening sessions on YouTube Music.
TogetherTune is not affiliated with, endorsed by, or sponsored by Google LLC. YouTube and YouTube Music are trademarks of Google LLC.
- Read the privacy policy before creating or joining a party.
- Report bugs through GitHub Issues.
- Report vulnerabilities according to SECURITY.md.
- Shared TypeScript protocol and sync helpers in
packages/shared. - WXT extension scaffold in
apps/extension. - Cloudflare Worker and Durable Object room backend in
apps/backend.
The preview links to the editable two-page draw.io source, which shows the extension contexts, Cloudflare backend, room setup and WebSocket synchronization loop. Open it with diagrams.net or the draw.io editor integration in your IDE.
Install dependencies first:
npm installRun the backend:
npm run dev:backendRun the extension:
npm run dev:extensionRun type checks and automated regression tests:
npm run check
npm testPull requests and pushes to main run the same checks, production builds, and
Playwright browser suite through .github/workflows/ci.yml.
Run the live Chrome extension smoke test:
npx playwright install chromium
npm run test:browserThe browser command builds the extension, starts an isolated local Wrangler backend, runs two-client room flows, validates selector fixtures on the YouTube Music origin, and checks extension loading.
Browser tests use http://127.0.0.1:8797 so they do not reuse or disturb the normal development backend.
Development defaults to http://localhost:8787. Production builds load the public backend URL from apps/extension/.env.production. That value is compiled into the extension JavaScript and scopes the generated manifest's host_permissions to that backend origin plus music.youtube.com.
The backend uses two provisioned KV namespaces: INVITES for invite-code mappings and RATE_LIMITS for short-lived fixed-window request counters. Their bindings and the Durable Object migration live in apps/backend/wrangler.jsonc.
After changing backend bindings or compatibility flags, regenerate the checked-in runtime and binding types with npm --workspace apps/backend run types.
Run the verified production packager:
npm run release:extension
npm run verify:extensionTo publish against a different backend, either update the non-secret WXT_PUBLIC_PARTY_API_BASE_URL in apps/extension/.env.production, or override it for one Bash build:
WXT_PUBLIC_PARTY_API_BASE_URL=https://api.example.com npm run release:extensionChrome Web Store does not receive or inject environment variables. Upload the ZIP produced by the command; the selected URL is already compiled into it. Run npm run verify:extension after a normal .env.production build. If you use a one-command override, inspect the ZIP manifest because the verifier intentionally compares it with the committed production environment.
WXT writes the uploadable ZIP under apps/extension/.output. Before submitting, inspect its generated manifest.json, confirm that the backend host is HTTPS, and complete the listing using the drafts in store/.
For automatic releases, follow the one-time Chrome Web Store CI setup. After setup, pushing a version tag builds, verifies, uploads, and submits the extension through Chrome Web Store API v2; Google publishes it after the normal review passes.