A lightweight network connection monitor for vanilla JavaScript. Polls a URL at a set interval to reliably detect online/offline status, going beyond the unreliable navigator.onLine.
Built on top of emttr.
npm install pulsemonA ping.json file is included in the package. Copy it to your public/assets folder:
cp node_modules/pulsemon/ping.json public/ping.jsonOr point to any existing static file on your server instead:
const pulsemon = new Pulsemon({ url: '/any-existing-file.json' });import Pulsemon, { NETWORK_STATUS, EVENTS } from 'pulsemon';
const pulsemon = new Pulsemon({
url: '/ping.json', // path to any static file on your server
interval: 5000 // polling interval in ms (default: 5000)
});
const network$ = pulsemon.init();
network$.subscribe(EVENTS.NETWORK, ({ isOnline, latency, status, timestamp }) => {
console.log(status); // 'ONLINE' | 'OFFLINE'
console.log(latency); // '0.12 s'
console.log(timestamp); // '2026-03-04T10:32:05.123Z'
});
// Get current status at any time
console.log(pulsemon.networkStatus()); // 'ONLINE' | 'OFFLINE' | 'CHECKING'
// Stop polling when done
pulsemon.stop();Every network event publishes the following object:
| Field | Type | Description |
|---|---|---|
isOnline |
boolean |
Whether the network is reachable |
status |
string |
'ONLINE' or 'OFFLINE' |
latency |
string |
Time taken for the poll to resolve, e.g. '0.12 s' |
timestamp |
string |
ISO timestamp of when the poll resolved |
| Option | Type | Default | Description |
|---|---|---|---|
url |
string |
'/pulsemon/ping.json' |
URL to poll against |
interval |
number |
5000 |
Polling interval in milliseconds |
Starts polling and returns an Emttr event bus instance. Subscribe to network events on the returned instance.
Stops polling and clears all subscribers.
Returns the current network status as a string: 'ONLINE', 'OFFLINE', or 'CHECKING'.
import { NETWORK_STATUS } from 'pulsemon';
NETWORK_STATUS.ONLINE // 'ONLINE'
NETWORK_STATUS.OFFLINE // 'OFFLINE'
NETWORK_STATUS.CHECKING // 'CHECKING'import { EVENTS } from 'pulsemon';
EVENTS.NETWORK // 'network'pulsemon pairs naturally with emttr for app-wide network event broadcasting:
import Emttr from 'emttr';
import Pulsemon, { EVENTS, NETWORK_STATUS } from 'pulsemon';
const bus = new Emttr();
const pulsemon = new Pulsemon({ url: '/ping.json' });
const network$ = pulsemon.init();
network$.subscribe(EVENTS.NETWORK, ({ isOnline, status, latency, timestamp }) => {
bus.publish('networkChanged', { isOnline, status, latency, timestamp });
});
// Anywhere in your app
bus.subscribe('networkChanged', ({ status, latency }) => {
console.log(`${status} · ${latency}`);
});Instead of relying on navigator.onLine (which returns true even without real internet access), pulsemon makes real HTTP requests to a URL you control. If the request resolves, the network is online. If it throws, the network is offline.
Concurrent requests are automatically deduplicated. If a poll is still in progress when the next interval fires, the pending poll is skipped and the last known status is preserved.
MIT