Group Dates
A tiny self-hosted web app for scheduling get-togethers with your friend group. You circle dates on a calendar, optionally add a time per day, and share one link. Friends open the same calendar, circle the days that work for them, and the best date floats to the top. No accounts, no sign-up — the link is the key.
Built with Go standard library only: no external dependencies, one static binary, polls stored in a plain JSON file.
Run it
Requires Go 1.22+.
go build -o groupdates .
./groupdates
Open http://localhost:8080 — that's the page for creating a poll. þ Flags:
| Flag | Default | Meaning |
|---|---|---|
-addr |
:8080 |
Listen address |
-data |
data |
Directory for polls.json |
To let friends reach it, run it on a machine they can access (a small VPS, a Raspberry Pi behind a port forward, etc.) and put it behind HTTPS — e.g. a Caddy or nginx reverse proxy. The share links use whatever host your friends open the page on, so no configuration is needed.
How it works
- Create a poll — give it a title, click every date you want to offer on the calendar (only today and future dates are clickable), and optionally set a time for each date in the list below the calendar.
- Share — after creating you get two links:
- Share link (
/p/<id>) — send this to the group. - Admin link (
/p/<id>?admin=<token>) — keep this. It's the only way to close or delete the poll.
- Share link (
- Friends answer — they open the share link, see the same calendar with the offered days highlighted, circle the ones that work, enter their name, and send. Answering again with the same name (case-insensitive) replaces the earlier answer.
- Close or delete — polls can never be edited after creation. From the admin link you can close the poll (answers freeze, results stay visible) or delete it entirely.
The poll page refreshes results every 30 seconds while open.
API (if you're curious)
| Method | Path | What it does |
|---|---|---|
POST |
/api/polls |
Create a poll, returns id + admin token |
GET |
/api/polls/{id} |
Poll data (admin token never included) |
POST |
/api/polls/{id}/votes |
Submit / replace an answer |
POST |
/api/polls/{id}/close |
Close (admin token required) |
DELETE |
/api/polls/{id} |
Delete (admin token required) |
Admin token goes in the X-Admin-Token header or ?admin= query parameter.
Storage
Everything lives in <data-dir>/polls.json, written atomically on every
change. Back it up by copying that one file. Deleting a poll removes it from
the file immediately.
Project layout
main.go server, storage, API handlers (stdlib only)
static/index.html create-a-poll page
static/poll.html voting + results page
static/calendar.js the shared calendar widget both pages use
static/create.js create-page logic
static/poll.js poll-page logic
static/style.css styles
Static files are embedded into the binary with go:embed, so the compiled
groupdates binary is all you need to deploy.