A lightweight Chrome/Edge browser extension that allows multiple users to watch any HTML5 video in perfect sync across devices, with real-time chat, and no external database.
Watch videos together with friends in perfect synchronization across any website with HTML5 video support (Cineby, FMovies, or any other HTML-based streaming site). Privacy-friendly, lightweight, and fast.
- Universal Video Sync: Works on any website with
<video>elements - Peer-to-Peer: Direct WebRTC connections for low latency
- Real-time Chat: Integrated chat overlay with drag/resize support
- No Database: Ephemeral rooms stored only in memory
- Sub-100ms Accuracy: Automatic drift correction for perfect sync
- Privacy First: All traffic goes peer-to-peer after initial handshake
- Lightweight: Under 1 MB total bundle size
- Node.js (v18 or higher)
- npm or yarn
- Chrome or Edge browser
- Clone the repository
git clone https://github.com/Echo2f13/syncwatch-extension.git
cd syncwatch-extension- Install dependencies
npm install- Start the signalling server
npm run serverThe signalling server will start on ws://localhost:3000
- Build the extension
For development (with watch mode):
npm run devFor production:
npm run build- Load the extension in your browser
Chrome:
- Open
chrome://extensions/ - Enable "Developer mode" (top right)
- Click "Load unpacked"
- Select the
distfolder
Edge:
- Open
edge://extensions/ - Enable "Developer mode" (left sidebar)
- Click "Load unpacked"
- Select the
distfolder
- Navigate to any website with an HTML5 video player
- Click the SyncWatch extension icon
- Enter your username
- Click "Create Room"
- Share the generated 6-character room key with friends
- Navigate to the same URL as the host
- Click the SyncWatch extension icon
- Enter your username
- Enter the 6-character room key
- Click "Join Room"
- The chat overlay appears automatically when connected
- Drag the header to move it around
- Use the resize handle (bottom-right) to adjust size
- Click the minimize button to collapse
- Click the close button to disconnect
syncwatch-extension/
├── src/
│ ├── background/
│ │ └── background.js # Service worker (MV3)
│ ├── content/
│ │ └── content_script.js # Video detection & sync logic
│ ├── popup/
│ │ ├── popup.html # Extension popup UI
│ │ ├── popup.js # Popup controller
│ │ └── popup.css # Popup styles
│ └── webrtc/
│ └── webrtc.js # WebRTC connection manager
├── server/
│ └── server.js # WebSocket signalling server
├── icons/ # Extension icons
├── manifest.json # Chrome extension manifest (MV3)
├── vite.config.js # Build configuration
└── package.json
| Component | Technology |
|---|---|
| Extension UI | HTML5, CSS3, Vanilla JavaScript |
| Content Script | Pure JavaScript with MutationObserver |
| Sync Logic | WebRTC DataChannels |
| Signalling | Node.js + Express + WebSocket |
| Build Tool | Vite |
| Manifest | Chrome Extension Manifest V3 |
-
Room Creation/Join
- User connects to signalling server via WebSocket
- WebRTC handshake (offer/answer + ICE candidates)
- Peers establish direct P2P connection
-
Video Synchronization
- Host sends periodic sync messages (every 2 seconds)
- Peers adjust playback position if drift > 500ms
- Play/pause/seek events broadcast to all peers
-
Chat System
- Messages sent via WebRTC data channels
- No server storage - ephemeral only
- Auto-scroll and timestamps
-
Session Management
- Rooms exist only in memory
- Auto-cleanup after 24 hours or when empty
- No persistent data storage
By default, the extension connects to ws://localhost:3000. You can change this in the popup settings.
Environment Variables:
PORT=3000 # Change signalling server portWebRTC uses public STUN servers by default. To add custom TURN servers, edit src/webrtc/webrtc.js:13-17:
this.iceServers = [
{ urls: 'stun:stun.l.google.com:19302' },
{
urls: 'turn:your-turn-server.com:3478',
username: 'user',
credential: 'pass'
}
];- manifest.json: Extension configuration (permissions, content scripts, etc.)
- background.js: Background service worker for state management
- content_script.js: Injected into web pages to detect and sync videos
- webrtc.js: Handles peer connections and data channels
- server.js: Minimal WebSocket server for peer discovery
- popup.*: User interface for creating/joining rooms
npm run buildThis creates an optimized build in the dist/ folder with:
- Minified JavaScript
- Removed console logs
- Bundled dependencies
For production deployment, use a process manager like PM2:
npm install -g pm2
pm2 start server/server.js --name syncwatch-server
pm2 save
pm2 startupOr use Docker:
FROM node:18-alpine
WORKDIR /app
COPY server/server.js package.json ./
RUN npm install --production
EXPOSE 3000
CMD ["node", "server.js"]SyncWatch works on any website with HTML5 <video> elements, including:
- ✅ Cineby
- ✅ FMovies
- ✅ Custom video hosting sites
- ✅ Self-hosted media players
- ❌ DRM-protected platforms (Netflix, Disney+, etc.) - not supported
- Ensure the page has an HTML5
<video>element - Wait for the video player to fully load before connecting
- Try refreshing the page
- Verify the room key is correct (6 characters)
- Ensure the host has created the room first
- Check if the signalling server is running
- Both users must be on the exact same URL
- Check browser console for WebRTC errors
- Verify firewall/NAT allows WebRTC connections
- Try using a TURN server if behind restrictive NAT
- Ensure WebRTC connection is established (check status)
- Verify data channels are open (check console logs)
- Try reconnecting
- Verify the server is running:
npm run server - Check the server URL in popup settings
- Ensure WebSocket port (3000) is not blocked
- No data storage: All rooms are ephemeral (memory only)
- Peer-to-peer: Video sync and chat go directly between peers
- No tracking: Extension doesn't collect any user data
- Open source: Full code transparency
Security Note: The signalling server only facilitates initial peer discovery. All subsequent traffic (video sync, chat) goes directly peer-to-peer via encrypted WebRTC connections.
- Throttled sync messages (500ms intervals)
- Debounced seek correction
- Lazy content script injection
- Minimal DOM manipulation
- Single persistent chat overlay
- CPU: < 2% on modern systems
- Memory: ~20-30 MB per session
- Network: Minimal (only sync/chat data, no video streaming)
- Bundle Size: < 500 KB minified
- Firefox support
- Mobile browser support (experimental)
- Screen sharing feature
- Playlist synchronization
- Public room discovery
- End-to-end encryption for chat
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow existing code style
- Test on both Chrome and Edge
- Update README if adding features
- Keep bundle size minimal
This project is licensed under the MIT License - see the LICENSE file for details.
echo2f13
- GitHub: @Echo2f13
- Extension: Made with ❤️ for seamless watch parties
- WebRTC for P2P technology
- Chrome Extensions API
- Node.js & Express community
- All contributors and testers
If you encounter issues or have questions:
- Check the Troubleshooting section
- Search existing GitHub Issues
- Create a new issue with detailed information
Made by echo2f13 | Follow on GitHub
- ICE Servers: Google STUN (public)
- Data Channels: Ordered, reliable delivery
- Connection Timeout: 30 seconds
- Reconnection: Automatic on disconnect
1. Host sends sync message every 2 seconds
2. Peers compare received time with local time
3. If drift > 500ms, adjust playback position
4. Sync play/pause state
5. Sync playback rate (speed)
All messages sent via WebRTC data channels use JSON format:
Video Sync:
{
"type": "video_sync",
"action": "play|pause|seeked",
"currentTime": 123.45,
"paused": false,
"playbackRate": 1.0,
"timestamp": 1234567890
}Chat:
{
"type": "chat",
"username": "Alice",
"message": "Hello!",
"timestamp": 1234567890
}The chat overlay uses CSS variables for easy theming. Edit src/content/content_script.js:379 to customize:
--bg-primary: rgba(17, 24, 39, 0.95);
--bg-secondary: rgba(31, 41, 55, 0.8);
--accent-color: #3b82f6;
--text-primary: #e5e7eb;
--text-secondary: #9ca3af;Enjoy seamless watch parties! 🍿