π¬ Meshcore β P2P Chat
**Serverless peer-to-peer chat with an automatic relay fallback.** It runs on static hosting (GitHub Pages) β zero servers, zero databases, zero accounts.
π¬ Meshcore β P2P Chat
π§ͺ View animated test results β 22/22 β
Serverless peer-to-peer chat with an automatic relay fallback. It runs on static hosting (GitHub Pages) β zero servers, zero databases, zero accounts.
Try it now: π Open Meshcore (opens in a new tab)
How it works
βββββββββββββββ WebRTC data channel βββββββββββββββ
β Peer A ββββββββββββββββββββββββββΊβ Peer B β
β (your tab) β (direct, P2P) β (their tab) β
ββββββββ¬βββββββ ββββββββ¬βββββββ
β SDP offer/answer/ICE via β
β public MQTT topic (signaling only) β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Public MQTT broker (per-room topic) β
β presence + signaling + fallback for messages β
βββββββββββββββββββββββββββββββββββββββββββββββββββLayer 1 β P2P (WebRTC)
- Peers announce their presence on a per-room MQTT topic (public broker, no account β the same way messengers discover each other).
- When two peers see each other, they exchange WebRTC offer/answer/ICE candidates through that topic (the classic signaling-server pattern used by PeerJS & co.). The broker only introduces peers β it never sees message payloads.
- Once connected, chat messages travel over the WebRTC data channel directly between browsers β real peer-to-peer.
Layer 2 β Relay (automatic fallback)
Pure browser P2P cannot connect on mobile networks: carriers use CGNAT and block NAT hole-punching, and the free public TURN servers that used to bridge it are dead or paid (2026). That is why every message is also published in parallel to a per-room topic on a public MQTT broker (WSS, no account). Every receiver deduplicates by message ID, so:
- peers that can connect P2P β messages travel directly over the WebRTC data channel,
- devices that cannot (phones on LTE/5G) β exchange messages via the relay.
P2P first, relay as a fallback β the same pattern real messengers use.
Why not WebTorrent trackers? The original build found peers through public WebTorrent WebSocket trackers (
tracker.webtorrent.dev,tracker.openwebtorrent.com). Those trackers now accept announces and see the swarm, but no longer relay WebRTC offers between peers (verified live: two peers registered in the same swarm, zero offers ever returned). Since the browser build of WebTorrent can only use WebSocket trackers (no UDP/DHT in the browser), peers could never find each other β so signaling moved to the MQTT relay.
Features
- π Rooms β the same room name = the same signaling topic = the same peer group
- π‘ Relay fallback β a dependency-free MQTT 3.1.1 client (~100 lines, no
libraries), publishing to
n2mesh/{room}, room isolation by exact topic - π Deduplication by ID β a message received over P2P and relay and the local bridge is displayed once
- π¬ True P2P messages β over WebRTC data channels, with MQTT fallback
- π·οΈ Nicknames, peer counter, connection status (P2P / P2P+relay / relay)
- π Shareable room links (
#/room-name) - π Dark, keyboard-accessible interface, zero dependencies (no CDN, no build)
- π₯οΈ Local bridge β tabs of the same browser cannot connect via WebRTC
(browsers block WebRTC loopback), so a
BroadcastChannelbridge connects them locally
How to use it
- Open Meshcore on two devices (or two tabs of one browser).
- Set the same room on both sides (default:
lobby). - Pick a nickname and send messages β on a desktop they travel P2P, on a phone automatically via the relay. Both cases work from the same link.
β οΈ This is a demo-grade mesh: scrollback is cached per room in your browser (last 100 messages), but there is no server-side history β messages sent while you are offline are lost (no broker-side queueing).
Run locally
git clone https://github.com/BartoszOsiej/Meshcore.git
cd n2-mesh
python3 -m http.server 8080
# open http://localhost:8080Security
- P2P mode: messages travel exclusively peer-to-peer; the MQTT broker only performs signaling and never receives content.
- Relay mode: messages pass through a public MQTT broker β a fallback for networks where P2P is impossible. Rooms are isolated (each subscriber only gets its own topic).
- Everything is plain JavaScript (zero dependencies β no CDN), no tracking, no data stored.