Real-time browser tab collaboration with ghost cursors, annotations, and an AI agent that can act inside the host's Chrome tabs.
Screen sharing lets teammates watch, but it does not let them naturally point, highlight, annotate, or help operate the browser. TabTwin lets a guest or AI agent appear inside the host's real browser tab as a live ghost collaborator while the host stays in control.
Hosts install the Chrome extension, start a session, share the generated link, and can revoke control at any time. The extension injects the cursor and annotation overlay, manages WebRTC signaling, and executes approved actions.
Guests open the session link in any modern browser. There is nothing to install. They enter a name, join the session, move a ghost cursor, annotate, highlight, scroll, and request click/type actions when the host grants permission.
| Browser | Guest support | Install required |
|---|---|---|
| Chrome | Yes | No |
| Firefox | Yes | No |
| Edge | Yes | No |
| Safari | Yes | No |
- The Chrome extension starts a host session and injects cursor, annotation, and action scripts into tabs.
- The server handles REST session creation plus WebSocket signaling for WebRTC, cursor events, actions, and Yjs-style updates.
- The guest web app joins by link and sends cursor/actions over WebRTC data channels with WebSocket fallback.
- Clone the repo.
git clone https://github.com/itzzavdhesh/TabTwin.git
cd TabTwin
npm install- Run the signaling server.
cp .env.example server/.env
npm run server- Run the guest web app.
npm run dev:web- Build the extension popup.
npm run build --workspace extension- Load the unpacked extension in Chrome from the
extension/folder.
- Build the popup UI first:
npm run build --workspace extension(this generatespopup-dist/). - Open
chrome://extensions. - Enable Developer mode.
- Click Load unpacked.
- Select the
extension/folder. - Pin TabTwin, open the popup, and click Start Session.
Open the link the host shares. That is it.
The participant currently viewing the guest session page can opt in to session recording from the session UI. When enabled, the guest-side session captures a lightweight timeline of collaboration events that stays isolated from the live WebRTC/WebSocket transport. The current recorder captures session lifecycle events, cursor movement, scroll events, annotation additions, click requests, and typing approvals.
Playback is available in the session UI once a recording has been collected. The current implementation supports play, pause, resume, seek, and timeline review for the captured events. The recording timeline is held in memory for the active session and is exposed through the existing session UI; it is not currently persisted to disk or exported as a standalone file.
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY |
Optional for local fallback, required for Claude actions | Claude API key used by the AI agent. |
PORT |
No | Server port. Defaults to 3001. |
CLIENT_URL |
No | Web app origin used when generating join links. Defaults to http://localhost:5173. |
REDIS_URL |
Yes | ioredis connection URL for session storage. Example: redis://localhost:6379. |
TabTwin stores session state in Redis so sessions survive server restarts and the server can scale horizontally. You must have a Redis instance running before starting the server.
Local development (Docker)
docker run -d -p 6379:6379 --name tabtwin-redis redis:7-alpineThen add the following to your .env file (already present in .env.example):
REDIS_URL=redis://localhost:6379If REDIS_URL is not set the server will exit immediately with a clear error message telling you what to do.
Screenshot placeholder: docs/screenshots/chrome-extensions-developer-mode.png
Screenshot placeholder: docs/screenshots/load-unpacked-extension-folder.png
Screenshot placeholder: docs/screenshots/tabtwin-popup-start-session.png
The host extension is Chrome-only for the MVP because it depends on Chrome Manifest V3 extension APIs. Guests can join from Chrome, Firefox, Edge, or Safari through the web app.
MIT