The Puter.js Peer API gives you WebRTC data channels with built-in signaling and TURN relays, so you can connect clients directly without running your own signaling server.
Use the Peer API to build peer-to-peer applications without the need for a server or proxy. Multiplayer games, collaborative editing, and real-time communication are all possible with the Peer API!
Peer connections require authentication. On websites, Puter.js will prompt the user to authenticate if needed.
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<h3>Peer Chat</h3>
<p>Open this page in two tabs. Start a server in one tab, then connect from the other.</p>
<div style="margin-bottom: 10px;">
<button id="start-server">Start server</button>
<span id="invite" style="margin-left: 10px;"></span>
</div>
<div style="margin-bottom: 10px;">
<input id="invite-input" placeholder="Invite code" style="width: 220px;" />
<button id="connect">Connect</button>
</div>
<div style="margin-bottom: 10px;">
<input id="message" placeholder="Message" style="width: 220px;" />
<button id="send" disabled>Send</button>
</div>
<pre id="log" style="background:#f4f4f4; padding:10px; height:200px; overflow:auto;"></pre>
<script>
const logEl = document.getElementById('log');
const inviteEl = document.getElementById('invite');
const inviteInput = document.getElementById('invite-input');
const messageInput = document.getElementById('message');
const sendBtn = document.getElementById('send');
let activeConn = null;
function log (...args) {
logEl.textContent += `${args.join(' ')}\n`;
logEl.scrollTop = logEl.scrollHeight;
}
function setConnection (conn, role) {
activeConn = conn;
sendBtn.disabled = true;
conn.addEventListener('open', () => {
log(`[${role}] connected`);
sendBtn.disabled = false;
});
conn.addEventListener('message', (event) => {
log(`[${role}] received:`, event.data);
});
conn.addEventListener('close', (event) => {
log(`[${role}] closed`, event.reason ? `(${event.reason})` : '');
sendBtn.disabled = true;
});
conn.addEventListener('error', (event) => {
log(`[${role}] error`, event.error?.message || event.error || 'unknown error');
});
}
document.getElementById('start-server').addEventListener('click', async () => {
inviteEl.textContent = 'Starting...';
try {
const server = await puter.peer.serve();
inviteEl.textContent = `Invite code: ${server.inviteCode}`;
log('[server] ready, waiting for connection');
server.addEventListener('connection', (event) => {
log('[server] client connected');
setConnection(event.conn, 'server');
});
} catch (err) {
inviteEl.textContent = 'Failed to start server.';
log('[server] error', err?.message || err);
}
});
document.getElementById('connect').addEventListener('click', async () => {
const inviteCode = inviteInput.value.trim();
if ( !inviteCode ) {
log('[client] enter an invite code first');
return;
}
try {
const conn = await puter.peer.connect(inviteCode);
log('[client] connecting...');
setConnection(conn, 'client');
} catch (err) {
log('[client] error', err?.message || err);
}
});
sendBtn.addEventListener('click', () => {
const message = messageInput.value.trim();
if ( !message || !activeConn ) return;
activeConn.send(message);
log('[you] sent:', message);
messageInput.value = '';
});
</script>
</body>
</html>
These peer features are supported out of the box when using Puter.js:
puter.peer.serve() - Create a peer server and generate an invite codeputer.peer.connect() - Connect to a peer server using an invite codeputer.peer.ensureTurnRelays() - Preload TURN relays for faster connections