P2P Poll App

A peer-to-peer polling app built with Automerge and Vanilla JS. No backend required — polls sync in real time across browsers using CRDTs and a WebSocket relay.

Features

  • Add options — type an option and press Enter or click "Add Option". Duplicate options (case-insensitive) are rejected with an inline error message.
  • Vote on options — click the vote button next to any option. You can vote on multiple options, but only once per option.
  • Toggle votes — click your vote again to remove it (the button turns green with a checkmark when you've voted).
  • Live vote counts — options are sorted by vote count in descending order and update in real time as votes come in from other users.
  • 2-minute countdown timer — click "Start 2-min Vote" to begin a shared countdown. Voting is open before and during the countdown. Once the timer expires, all vote buttons are disabled.
  • Shared timer — the deadline is stored in the Automerge document, so all peers see the same countdown and voting closes simultaneously for everyone.
  • Copy URL — click "Copy URL" to copy the poll link to your clipboard. Share it with others to join the same poll.
  • P2P sync — all state (options, votes, timer) syncs across browsers in real time with no central server handling your data.

How it works

Tech stack

  • Automerge via @automerge/vanillajs — a CRDT library that lets multiple clients concurrently edit shared documents and merge changes without conflicts.
  • BroadcastChannelNetworkAdapter — syncs between tabs in the same browser instantly via the browser's BroadcastChannel API.
  • WebSocketClientAdapter — syncs across different browsers/devices via a WebSocket relay (wss://sync.automerge.org). The relay only forwards CRDT messages; it does not store or interpret your data.
  • IndexedDBStorageAdapter — persists the document locally so it survives page refreshes.
  • Vite — bundles the app with WebAssembly support (required by Automerge).

Data model

The poll is a single Automerge document with three fields:

{
  options: string[],       // list of poll options in insertion order
  votes: { [option]: number }, // vote count per option
  deadline: number | null  // Unix timestamp (ms) when voting closes, or null
}

URL-based sharing

Each document gets a unique Automerge URL (e.g. automerge:abc123...) stored in the page's URL hash. Opening the same URL in any browser loads and syncs the same document. Creating a new poll generates a new document and updates the hash automatically.

Voting rules

  • Voted options are tracked in localStorage (keyed by document URL), so they persist across page refreshes but are isolated per browser.
  • One vote per option per user. Votes can be toggled off and back on until the timer expires.
  • The timer (doc.deadline) is set once by whoever clicks "Start 2-min Vote" and is shared via the Automerge document, so all peers use the same deadline.

Running locally

pnpm install
pnpm dev

Open the printed localhost URL. To test cross-browser sync, copy the URL (including the #automerge:... hash) and open it in a different browser.

Description
No description provided
Readme 3.9 MiB