https://github.com/lopatnov/browser-tab-ipc
With this technology, you can exchange messages among browser tabs. This is a bus network, inter-process communication mechanism between browser tabs.
https://github.com/lopatnov/browser-tab-ipc
browser-tabs ipc javascript typescript
Last synced: about 1 month ago
JSON representation
With this technology, you can exchange messages among browser tabs. This is a bus network, inter-process communication mechanism between browser tabs.
- Host: GitHub
- URL: https://github.com/lopatnov/browser-tab-ipc
- Owner: lopatnov
- License: apache-2.0
- Created: 2021-10-06T10:20:02.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2022-08-02T12:23:53.000Z (almost 4 years ago)
- Last Synced: 2023-09-19T18:10:28.410Z (over 2 years ago)
- Topics: browser-tabs, ipc, javascript, typescript
- Language: TypeScript
- Homepage: https://lopatnov.github.io/browser-tab-ipc/
- Size: 660 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# browser-tab-ipc
> Lightweight cross-tab messaging library for TypeScript / JavaScript.
> Exchange messages between browser tabs with automatic transport selection and graceful fallback.
[](https://www.npmjs.com/package/@lopatnov/browser-tab-ipc)
[](https://www.npmjs.com/package/@lopatnov/browser-tab-ipc)
[](https://github.com/lopatnov/browser-tab-ipc/blob/master/LICENSE)
[](https://github.com/lopatnov/browser-tab-ipc/issues)
[](https://github.com/lopatnov/browser-tab-ipc/stargazers)
---
## Browser Support
| Transport | Chrome | Firefox | Safari | Edge | Notes |
| ---------------- | ------ | ------- | ------ | ---- | ------------------------------ |
| BroadcastChannel | 54+ | 38+ | 15.4+ | 79+ | Default — fastest, same-origin |
| SharedWorker | 4+ | 29+ | 16+ | 79+ | Cross-origin capable |
| SessionStorage | all | all | all | all | Universal fallback |
---
## Table of Contents
- [Installation](#installation)
- [Quick Start](#quick-start)
- [How It Works](#how-it-works)
- [API Reference](#api-reference)
- [class BrowserTabIPC](#class-browsertabipc)
- [ConnectionOptions](#connectionoptions)
- [ConnectionState](#connectionstate)
- [TransportType](#transporttype)
- [Events](#events)
- [SharedWorker Setup](#sharedworker-setup)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
---
## Installation
**npm:**
```shell
npm install @lopatnov/browser-tab-ipc
```
**yarn:**
```shell
yarn add @lopatnov/browser-tab-ipc
```
**CDN (UMD, no bundler required):**
```html
```
---
## Quick Start
```typescript
import {BrowserTabIPC} from '@lopatnov/browser-tab-ipc';
const ipc = new BrowserTabIPC();
// Listen for messages from other tabs
ipc.message((data) => {
console.log('Received:', data);
});
// Connect and send
await ipc.connect();
await ipc.postMessage({event: 'tab-opened', tabId: crypto.randomUUID()});
```
Open the same page in multiple tabs — every tab receives the message instantly.
---
## How It Works
`BrowserTabIPC` tries each transport in order and uses the first one that connects successfully:
```
BroadcastChannel → SharedWorker → SessionStorage
(fastest) (flexible) (always works)
```
You can override this by specifying a single transport or a custom fallback list via `ConnectionOptions`.
---
## API Reference
### class BrowserTabIPC
`BrowserTabIPC` extends Node's `EventEmitter` and provides a clean connect / send / receive interface.
#### `new BrowserTabIPC(options?: ConnectionOptions)`
Creates an instance. Options set here apply to all subsequent `connect()` calls.
```typescript
import {BrowserTabIPC, TransportType} from '@lopatnov/browser-tab-ipc';
// Default — auto-selects from all three transports
const ipc = new BrowserTabIPC();
// Force a single transport
const ipc = new BrowserTabIPC({
transportTypes: TransportType.broadcastChannel,
});
// Custom fallback chain
const ipc = new BrowserTabIPC({
transportTypes: [TransportType.sharedWorker, TransportType.sessionStorage],
sharedWorkerUri: '/ipc-worker.js',
});
```
#### `connect(options?: ConnectionOptions): Promise`
Establishes the connection. Options passed here are merged with constructor options.
```typescript
const state = await ipc.connect({
sharedWorkerUri: '/dist/ipc-worker.js',
storageKey: 'my-app-channel',
storageExpiredTime: 30_000,
});
console.log(state.connected); // true
console.log(state.type); // e.g. TransportType.broadcastChannel
```
#### `disconnect(): Promise`
Closes the active connection and cleans up all listeners and timers.
```typescript
const state = await ipc.disconnect();
console.log(state.connected); // false
```
#### `postMessage(message: any): Promise`
Broadcasts a serializable value to all connected tabs.
```typescript
await ipc.postMessage('ping');
await ipc.postMessage({type: 'STORE_UPDATE', payload: {count: 42}});
```
#### Event subscription methods
| Method | Trigger |
| --------------------------- | --------------------------------------- |
| `message(callback)` | A message was received from another tab |
| `connected(callback)` | Connection established successfully |
| `connectionError(callback)` | Connection attempt failed |
| `disconnected(callback)` | Connection was closed |
```typescript
ipc.message((data) => console.log('Message:', data));
ipc.connected((state) => console.log('Connected via', TransportType[state.type!]));
ipc.connectionError((state) => console.error('Connection failed:', state.error));
ipc.disconnected(() => console.log('Disconnected'));
```
You can also use the `EventEmitter` API directly with the exported event name constants:
```typescript
import {EventMessage, EventConnected, EventConnectionError, EventDisconnected} from '@lopatnov/browser-tab-ipc';
ipc.on(EventMessage, (data) => {
/* ... */
});
ipc.once(EventConnected, (state) => {
/* ... */
});
```
---
### ConnectionOptions
| Option | Type | Default | Description |
| -------------------- | ---------------------------------- | ----------------------- | ----------------------------------------------- |
| `transportTypes` | `TransportType \| TransportType[]` | All three, in order | Transport(s) to try, left to right |
| `sharedWorkerUri` | `string` | GitHub CDN fallback URL | URL to `ipc-worker.js` (SharedWorker transport) |
| `storageKey` | `string` | `'ipc'` | Namespace prefix for SessionStorage keys |
| `storageExpiredTime` | `number` | `30000` | Message TTL in milliseconds (SessionStorage) |
---
### ConnectionState
Returned by `connect()` and `disconnect()`, and passed to event callbacks.
| Field | Type | Description |
| ----------- | ----------------------- | --------------------------------------------- |
| `type` | `TransportType \| null` | Active transport, or `null` if none connected |
| `connected` | `boolean` | Whether the connection is currently active |
| `error?` | `unknown` | Error detail when a connection attempt fails |
---
### TransportType
```typescript
import {TransportType} from '@lopatnov/browser-tab-ipc';
TransportType.broadcastChannel; // BroadcastChannel API
TransportType.sharedWorker; // SharedWorker
TransportType.sessionStorage; // SessionStorage events
```
---
### Events
| Constant | When emitted |
| ---------------------- | ---------------------------------- |
| `EventConnected` | A transport connected successfully |
| `EventConnectionError` | A transport failed to connect |
| `EventDisconnected` | The connection was closed |
| `EventMessage` | A message arrived from another tab |
---
## SharedWorker Setup
The SharedWorker transport requires a worker script served from **your own origin** to avoid CORS issues. Copy the bundled file into your project:
```shell
cp node_modules/@lopatnov/browser-tab-ipc/dist/ipc-worker.js public/
```
Then point `connect()` to it:
```typescript
await ipc.connect({sharedWorkerUri: '/ipc-worker.js'});
```
> Without this step, the library falls back to a GitHub-hosted worker — which only works on the same origin as the CDN.
---
## Troubleshooting
**`Module '"events"' can only be default-imported using the 'allowSyntheticDefaultImports' flag`**
Add to `tsconfig.json`:
```json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true
}
}
```
**Messages are not received in other tabs**
- All tabs must be on the **same origin** (protocol + host + port).
- BroadcastChannel and SessionStorage are strictly same-origin.
- SharedWorker can bridge origins if the worker file is served from the target origin.
**SharedWorker fails silently**
- Open **DevTools → Application → Shared Workers** and check for errors.
- Verify the `sharedWorkerUri` path is accessible from the browser (check for 404).
- If the file is missing, copy `ipc-worker.js` to your `public/` folder as shown above.
**Connection established but no messages arrive**
- Both tabs must call `connect()` before any messages are sent.
- A tab does **not** receive its own messages — only other tabs do.
---
## Contributing
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
- Bug reports → [open an issue](https://github.com/lopatnov/browser-tab-ipc/issues)
- Security vulnerabilities → [GitHub Security Advisories](https://github.com/lopatnov/browser-tab-ipc/security/advisories/new) _(do not use public issues)_
- Questions → [Discussions](https://github.com/lopatnov/browser-tab-ipc/discussions)
- Found it useful? A [star on GitHub](https://github.com/lopatnov/browser-tab-ipc) helps others discover the project
---
## Built With
- [TypeScript](https://www.typescriptlang.org/) — strict typing throughout
- [Rollup](https://rollupjs.org/) — bundled to ESM, CJS, and UMD formats
- [BroadcastChannel API](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) — primary transport
- [SharedWorker API](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker) — cross-tab shared execution context
- [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) — universal fallback transport
- [Node.js EventEmitter](https://nodejs.org/api/events.html) — event-driven API
- [Yarn](https://yarnpkg.com/) — package management and script runner
- [Babel](https://babeljs.io/) — TypeScript transpilation pipeline for tests
- [Puppeteer](https://pptr.dev/) + [Jest](https://jestjs.io/) — cross-tab integration testing in a real browser
- [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) — linting and formatting
---
## License
[Apache-2.0](LICENSE) © 2019–2026 [Oleksandr Lopatnov](https://github.com/lopatnov) · [LinkedIn](https://www.linkedin.com/in/lopatnov/)
[eventemitter]: https://nodejs.org/api/events.html
[browsertabipc]: ./src/browser-tab-ipc.ts
[transporttype]: ./src/transport-type.enum.ts
[connectionoptions]: ./src/connection-options.ts
[connectionstate]: ./src/connection-state.ts
[eventemitter]: https://nodejs.org/api/events.html
[browsertabipc]: ./src/browser-tab-ipc.ts
[transporttype]: ./src/transport-type.enum.ts
[connectionoptions]: ./src/connection-options.ts
[connectionstate]: ./src/connection-state.ts