{"id":17757846,"url":"https://github.com/lopatnov/browser-tab-ipc","last_synced_at":"2026-05-15T22:01:40.003Z","repository":{"id":46535737,"uuid":"414164172","full_name":"lopatnov/browser-tab-ipc","owner":"lopatnov","description":"With this technology, you can exchange messages among browser tabs. This is a bus network, inter-process communication mechanism between browser tabs.","archived":false,"fork":false,"pushed_at":"2022-08-02T12:23:53.000Z","size":676,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2023-09-19T18:10:28.410Z","etag":null,"topics":["browser-tabs","ipc","javascript","typescript"],"latest_commit_sha":null,"homepage":"https://lopatnov.github.io/browser-tab-ipc/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lopatnov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2021-10-06T10:20:02.000Z","updated_at":"2023-04-11T15:40:58.000Z","dependencies_parsed_at":"2022-09-24T05:40:40.272Z","dependency_job_id":null,"html_url":"https://github.com/lopatnov/browser-tab-ipc","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopatnov%2Fbrowser-tab-ipc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopatnov%2Fbrowser-tab-ipc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopatnov%2Fbrowser-tab-ipc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lopatnov%2Fbrowser-tab-ipc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lopatnov","download_url":"https://codeload.github.com/lopatnov/browser-tab-ipc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246637020,"owners_count":20809537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser-tabs","ipc","javascript","typescript"],"created_at":"2024-10-26T17:09:13.712Z","updated_at":"2026-05-15T22:01:39.998Z","avatar_url":"https://github.com/lopatnov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# browser-tab-ipc\n\n\u003e Lightweight cross-tab messaging library for TypeScript / JavaScript.\n\u003e Exchange messages between browser tabs with automatic transport selection and graceful fallback.\n\n[![npm downloads](https://img.shields.io/npm/dt/@lopatnov/browser-tab-ipc)](https://www.npmjs.com/package/@lopatnov/browser-tab-ipc)\n[![npm version](https://badge.fury.io/js/%40lopatnov%2Fbrowser-tab-ipc.svg)](https://www.npmjs.com/package/@lopatnov/browser-tab-ipc)\n[![License](https://img.shields.io/github/license/lopatnov/browser-tab-ipc)](https://github.com/lopatnov/browser-tab-ipc/blob/master/LICENSE)\n[![GitHub issues](https://img.shields.io/github/issues/lopatnov/browser-tab-ipc)](https://github.com/lopatnov/browser-tab-ipc/issues)\n[![GitHub stars](https://img.shields.io/github/stars/lopatnov/browser-tab-ipc)](https://github.com/lopatnov/browser-tab-ipc/stargazers)\n\n---\n\n## Browser Support\n\n| Transport        | Chrome | Firefox | Safari | Edge | Notes                          |\n| ---------------- | ------ | ------- | ------ | ---- | ------------------------------ |\n| BroadcastChannel | 54+    | 38+     | 15.4+  | 79+  | Default — fastest, same-origin |\n| SharedWorker     | 4+     | 29+     | 16+    | 79+  | Cross-origin capable           |\n| SessionStorage   | all    | all     | all    | all  | Universal fallback             |\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [How It Works](#how-it-works)\n- [API Reference](#api-reference)\n  - [class BrowserTabIPC](#class-browsertabipc)\n  - [ConnectionOptions](#connectionoptions)\n  - [ConnectionState](#connectionstate)\n  - [TransportType](#transporttype)\n  - [Events](#events)\n- [SharedWorker Setup](#sharedworker-setup)\n- [Troubleshooting](#troubleshooting)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Installation\n\n**npm:**\n\n```shell\nnpm install @lopatnov/browser-tab-ipc\n```\n\n**yarn:**\n\n```shell\nyarn add @lopatnov/browser-tab-ipc\n```\n\n**CDN (UMD, no bundler required):**\n\n```html\n\u003cscript src=\"https://lopatnov.github.io/browser-tab-ipc/dist/library.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n---\n\n## Quick Start\n\n```typescript\nimport {BrowserTabIPC} from '@lopatnov/browser-tab-ipc';\n\nconst ipc = new BrowserTabIPC();\n\n// Listen for messages from other tabs\nipc.message((data) =\u003e {\n  console.log('Received:', data);\n});\n\n// Connect and send\nawait ipc.connect();\nawait ipc.postMessage({event: 'tab-opened', tabId: crypto.randomUUID()});\n```\n\nOpen the same page in multiple tabs — every tab receives the message instantly.\n\n---\n\n## How It Works\n\n`BrowserTabIPC` tries each transport in order and uses the first one that connects successfully:\n\n```\nBroadcastChannel  →  SharedWorker  →  SessionStorage\n    (fastest)          (flexible)       (always works)\n```\n\nYou can override this by specifying a single transport or a custom fallback list via `ConnectionOptions`.\n\n---\n\n## API Reference\n\n### class BrowserTabIPC\n\n`BrowserTabIPC` extends Node's `EventEmitter` and provides a clean connect / send / receive interface.\n\n#### `new BrowserTabIPC(options?: ConnectionOptions)`\n\nCreates an instance. Options set here apply to all subsequent `connect()` calls.\n\n```typescript\nimport {BrowserTabIPC, TransportType} from '@lopatnov/browser-tab-ipc';\n\n// Default — auto-selects from all three transports\nconst ipc = new BrowserTabIPC();\n\n// Force a single transport\nconst ipc = new BrowserTabIPC({\n  transportTypes: TransportType.broadcastChannel,\n});\n\n// Custom fallback chain\nconst ipc = new BrowserTabIPC({\n  transportTypes: [TransportType.sharedWorker, TransportType.sessionStorage],\n  sharedWorkerUri: '/ipc-worker.js',\n});\n```\n\n#### `connect(options?: ConnectionOptions): Promise\u003cConnectionState\u003e`\n\nEstablishes the connection. Options passed here are merged with constructor options.\n\n```typescript\nconst state = await ipc.connect({\n  sharedWorkerUri: '/dist/ipc-worker.js',\n  storageKey: 'my-app-channel',\n  storageExpiredTime: 30_000,\n});\n\nconsole.log(state.connected); // true\nconsole.log(state.type); // e.g. TransportType.broadcastChannel\n```\n\n#### `disconnect(): Promise\u003cConnectionState\u003e`\n\nCloses the active connection and cleans up all listeners and timers.\n\n```typescript\nconst state = await ipc.disconnect();\nconsole.log(state.connected); // false\n```\n\n#### `postMessage(message: any): Promise\u003cvoid\u003e`\n\nBroadcasts a serializable value to all connected tabs.\n\n```typescript\nawait ipc.postMessage('ping');\nawait ipc.postMessage({type: 'STORE_UPDATE', payload: {count: 42}});\n```\n\n#### Event subscription methods\n\n| Method                      | Trigger                                 |\n| --------------------------- | --------------------------------------- |\n| `message(callback)`         | A message was received from another tab |\n| `connected(callback)`       | Connection established successfully     |\n| `connectionError(callback)` | Connection attempt failed               |\n| `disconnected(callback)`    | Connection was closed                   |\n\n```typescript\nipc.message((data) =\u003e console.log('Message:', data));\nipc.connected((state) =\u003e console.log('Connected via', TransportType[state.type!]));\nipc.connectionError((state) =\u003e console.error('Connection failed:', state.error));\nipc.disconnected(() =\u003e console.log('Disconnected'));\n```\n\nYou can also use the `EventEmitter` API directly with the exported event name constants:\n\n```typescript\nimport {EventMessage, EventConnected, EventConnectionError, EventDisconnected} from '@lopatnov/browser-tab-ipc';\n\nipc.on(EventMessage, (data) =\u003e {\n  /* ... */\n});\nipc.once(EventConnected, (state) =\u003e {\n  /* ... */\n});\n```\n\n---\n\n### ConnectionOptions\n\n| Option               | Type                               | Default                 | Description                                     |\n| -------------------- | ---------------------------------- | ----------------------- | ----------------------------------------------- |\n| `transportTypes`     | `TransportType \\| TransportType[]` | All three, in order     | Transport(s) to try, left to right              |\n| `sharedWorkerUri`    | `string`                           | GitHub CDN fallback URL | URL to `ipc-worker.js` (SharedWorker transport) |\n| `storageKey`         | `string`                           | `'ipc'`                 | Namespace prefix for SessionStorage keys        |\n| `storageExpiredTime` | `number`                           | `30000`                 | Message TTL in milliseconds (SessionStorage)    |\n\n---\n\n### ConnectionState\n\nReturned by `connect()` and `disconnect()`, and passed to event callbacks.\n\n| Field       | Type                    | Description                                   |\n| ----------- | ----------------------- | --------------------------------------------- |\n| `type`      | `TransportType \\| null` | Active transport, or `null` if none connected |\n| `connected` | `boolean`               | Whether the connection is currently active    |\n| `error?`    | `unknown`               | Error detail when a connection attempt fails  |\n\n---\n\n### TransportType\n\n```typescript\nimport {TransportType} from '@lopatnov/browser-tab-ipc';\n\nTransportType.broadcastChannel; // BroadcastChannel API\nTransportType.sharedWorker; // SharedWorker\nTransportType.sessionStorage; // SessionStorage events\n```\n\n---\n\n### Events\n\n| Constant               | When emitted                       |\n| ---------------------- | ---------------------------------- |\n| `EventConnected`       | A transport connected successfully |\n| `EventConnectionError` | A transport failed to connect      |\n| `EventDisconnected`    | The connection was closed          |\n| `EventMessage`         | A message arrived from another tab |\n\n---\n\n## SharedWorker Setup\n\nThe SharedWorker transport requires a worker script served from **your own origin** to avoid CORS issues. Copy the bundled file into your project:\n\n```shell\ncp node_modules/@lopatnov/browser-tab-ipc/dist/ipc-worker.js public/\n```\n\nThen point `connect()` to it:\n\n```typescript\nawait ipc.connect({sharedWorkerUri: '/ipc-worker.js'});\n```\n\n\u003e Without this step, the library falls back to a GitHub-hosted worker — which only works on the same origin as the CDN.\n\n---\n\n## Troubleshooting\n\n**`Module '\"events\"' can only be default-imported using the 'allowSyntheticDefaultImports' flag`**\n\nAdd to `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true\n  }\n}\n```\n\n**Messages are not received in other tabs**\n\n- All tabs must be on the **same origin** (protocol + host + port).\n- BroadcastChannel and SessionStorage are strictly same-origin.\n- SharedWorker can bridge origins if the worker file is served from the target origin.\n\n**SharedWorker fails silently**\n\n- Open **DevTools → Application → Shared Workers** and check for errors.\n- Verify the `sharedWorkerUri` path is accessible from the browser (check for 404).\n- If the file is missing, copy `ipc-worker.js` to your `public/` folder as shown above.\n\n**Connection established but no messages arrive**\n\n- Both tabs must call `connect()` before any messages are sent.\n- A tab does **not** receive its own messages — only other tabs do.\n\n---\n\n## Contributing\n\nContributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.\n\n- Bug reports → [open an issue](https://github.com/lopatnov/browser-tab-ipc/issues)\n- Security vulnerabilities → [GitHub Security Advisories](https://github.com/lopatnov/browser-tab-ipc/security/advisories/new) _(do not use public issues)_\n- Questions → [Discussions](https://github.com/lopatnov/browser-tab-ipc/discussions)\n- Found it useful? A [star on GitHub](https://github.com/lopatnov/browser-tab-ipc) helps others discover the project\n\n---\n\n## Built With\n\n- [TypeScript](https://www.typescriptlang.org/) — strict typing throughout\n- [Rollup](https://rollupjs.org/) — bundled to ESM, CJS, and UMD formats\n- [BroadcastChannel API](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) — primary transport\n- [SharedWorker API](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker) — cross-tab shared execution context\n- [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) — universal fallback transport\n- [Node.js EventEmitter](https://nodejs.org/api/events.html) — event-driven API\n- [Yarn](https://yarnpkg.com/) — package management and script runner\n- [Babel](https://babeljs.io/) — TypeScript transpilation pipeline for tests\n- [Puppeteer](https://pptr.dev/) + [Jest](https://jestjs.io/) — cross-tab integration testing in a real browser\n- [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) — linting and formatting\n\n---\n\n## License\n\n[Apache-2.0](LICENSE) © 2019–2026 [Oleksandr Lopatnov](https://github.com/lopatnov) · [LinkedIn](https://www.linkedin.com/in/lopatnov/)\n\n[eventemitter]: https://nodejs.org/api/events.html\n[browsertabipc]: ./src/browser-tab-ipc.ts\n[transporttype]: ./src/transport-type.enum.ts\n[connectionoptions]: ./src/connection-options.ts\n[connectionstate]: ./src/connection-state.ts\n\n[eventemitter]: https://nodejs.org/api/events.html\n[browsertabipc]: ./src/browser-tab-ipc.ts\n[transporttype]: ./src/transport-type.enum.ts\n[connectionoptions]: ./src/connection-options.ts\n[connectionstate]: ./src/connection-state.ts\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flopatnov%2Fbrowser-tab-ipc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flopatnov%2Fbrowser-tab-ipc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flopatnov%2Fbrowser-tab-ipc/lists"}