Rallly is a self-hosted scheduling tool — like Doodle but open source. Create polls, find the best meeting time, and integrate with your calendar.
Why Rallly?
- Self-hosted: Your server, no tracking
- No account needed: Participants vote without signing up
- Beautiful UI: Modern, responsive design
- API access: Programmatic poll management
- Email notifications: Updates when participants vote
- Time zones: Automatic timezone handling
- Free: Completely open source
Self-Host
git clone https://github.com/lukevella/rallly.git
cd rallly
# Configure
cp .env.example .env
# Edit .env: set DATABASE_URL, SECRET_PASSWORD, NEXT_PUBLIC_BASE_URL
docker compose up -d
Create a Poll
Through the UI:
- Enter title and description
- Add date/time options
- Share the link — no signup required
API: Create Poll
curl -X POST http://localhost:3000/api/polls \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"title": "Team Standup Time",
"description": "When should we have our daily standup?",
"options": [
{"startDate": "2026-04-01T09:00:00Z", "endDate": "2026-04-01T09:30:00Z"},
{"startDate": "2026-04-01T10:00:00Z", "endDate": "2026-04-01T10:30:00Z"},
{"startDate": "2026-04-01T14:00:00Z", "endDate": "2026-04-01T14:30:00Z"}
]
}'
API: Get Poll Results
curl http://localhost:3000/api/polls/POLL_ID \
-H 'Authorization: Bearer YOUR_TOKEN'
Response includes all participants and their votes.
API: Add Participant Vote
curl -X POST http://localhost:3000/api/polls/POLL_ID/participants \
-H 'Content-Type: application/json' \
-d '{
"name": "Alice",
"votes": [
{"optionId": "opt_1", "type": "yes"},
{"optionId": "opt_2", "type": "ifNeedBe"},
{"optionId": "opt_3", "type": "no"}
]
}'
Integrate with Slack Bot
app.command('/schedule', async ({ command, ack, say }) => {
await ack();
const poll = await fetch('http://rallly:3000/api/polls', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer TOKEN' },
body: JSON.stringify({
title: command.text,
options: generateNextWeekSlots(),
}),
}).then(r => r.json());
await say(`Vote for the best time: ${poll.url}`);
});
Docker Compose
services:
rallly:
image: lukevella/rallly:latest
ports:
- '3000:3000'
environment:
- DATABASE_URL=postgres://rallly:password@db:5432/rallly
- SECRET_PASSWORD=your-secret
- NEXT_PUBLIC_BASE_URL=https://schedule.example.com
depends_on:
- db
db:
image: postgres:16
environment:
- POSTGRES_USER=rallly
- POSTGRES_PASSWORD=password
- POSTGRES_DB=rallly
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Real-World Use Case
A remote team of 20 replaced Doodle Premium ($50/year) with self-hosted Rallly. They schedule 15+ meetings per week, and participants don't need accounts. The API integration with their Slack bot means scheduling starts with /schedule Team Retrospective.
Need to automate data collection? Check out my Apify actors for ready-made scrapers, or email spinov001@gmail.com for custom solutions.
Top comments (0)