Stop manually checking WebUntis every morning. Get an instant push notification the moment your timetable changes β room swaps, cancellations, teacher changes, and more.
untis-notifier polls your WebUntis timetable on a schedule and sends a push notification via ntfy whenever anything changes. Works with any school that uses WebUntis (common across Germany, Austria, Switzerland, and other European countries).
π
2 timetable change(s)
14.03.2025: M-LK (08:00 β 08:45)
β’ status: REGULAR β CANCELLED
15.03.2025: PH-GK3 (10:00 β 10:45)
β’ room: R101 β R204
β’ teacher: VV β KT
Delivered to your phone via the ntfy app (Android / iOS / web).
- Logs in to WebUntis using your school credentials on startup
- Fetches your timetable for today + the next
LOOK_AHEADdays everyCHECK_INTERVAL - Diffs the result against the previous fetch
- Sends a push notification via ntfy if anything changed (room, teacher, status, notes, time)
- Docker & Docker Compose
- A WebUntis account (ask your school if you don't have one)
- Your school's WebUntis URL β find it by logging in via browser and copying the base URL
Log in to WebUntis in your browser. The URL will look like:
https://<server>.webuntis.com/WebUntis/?school=<schoolname>#/basic/main
UNTIS_BASE_URLβhttps://<server>.webuntis.comUNTIS_SCHOOL_NAMEβ the value afterschool=
UNTIS_USER=your.username
UNTIS_PASS=yourpassword
UNTIS_BASE_URL=https://arche.webuntis.com
UNTIS_SCHOOL_NAME=your-school
NTFY_TOPIC=your-unique-secret-topicTip: make
NTFY_TOPICsomething unguessable (e.g.timetable-mustermann-xk92) so others can't subscribe to your notifications.
docker compose up -d- Browser: open
https://ntfy.sh/<your-topic> - App: install ntfy for Android or iOS and subscribe to your topic
All configuration is via environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
UNTIS_USER |
β | β | Your WebUntis username |
UNTIS_PASS |
β | β | Your WebUntis password |
UNTIS_BASE_URL |
β | β | Base URL of your school's WebUntis instance |
UNTIS_SCHOOL_NAME |
β | β | School identifier (from the login URL, see Quick Start) |
NTFY_BASE_URL |
https://ntfy.sh |
ntfy server URL (use your own for self-hosted) | |
NTFY_TOPIC |
untis-notifier |
ntfy topic to publish to β make this unique and secret | |
LOOK_AHEAD |
7 |
Number of days ahead to monitor for changes | |
CHECK_INTERVAL |
5m |
How often to poll. Accepts Go durations: 30s, 5m, 1h |
|
LOG_FORMAT |
text |
text for human-readable logs, json for log aggregators |
|
PORT |
8080 |
Port for the built-in HTTP server |
untis-notifier exposes a small HTTP server for health checks and monitoring integration.
| Endpoint | Description |
|---|---|
GET /health |
Returns 200 OK as long as the process is running. Use for liveness probes. |
GET /status |
Returns a JSON object with the current state of the notifier. |
Example /status response:
{
"ready": true,
"lastCheck": "2025-03-14T08:30:00Z"
}ready is false until the first timetable fetch has completed successfully. This is useful as a readiness probe β the process may be up but not yet functional if WebUntis login is still in progress.
Docker Compose health check example:
untis-notifier:
image: crwntec/untis-notifier:latest
restart: unless-stopped
env_file: .env
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3If you want notifications to stay fully private, run your own ntfy instance alongside the notifier:
# docker-compose.yml
services:
ntfy:
image: binwiederhier/ntfy
command: serve
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ntfy-data:/var/cache/ntfy
untis-notifier:
image: crwntec/untis-notifier:latest
restart: unless-stopped
env_file: .env
environment:
NTFY_BASE_URL: http://ntfy:80
depends_on:
- ntfy
volumes:
ntfy-data:Then point the ntfy app at your server's IP/domain instead of ntfy.sh.
Login fails immediately
- Double-check
UNTIS_BASE_URLβ it should not have a trailing slash and should not include/WebUntis - Verify
UNTIS_SCHOOL_NAMEmatches exactly what appears in the browser URL afterschool= - Try logging in manually in an incognito browser window to confirm credentials work
No notifications arriving
- Check that you subscribed to the exact topic name in
NTFY_TOPIC - Run
docker compose logs untis-notifierand look fornotification sentor any errors - If using self-hosted ntfy, ensure the
NTFY_BASE_URLis reachable from the container
"first run β baseline stored" then nothing
- This is expected. On the first run, the current timetable is saved as a baseline. Notifications are only sent when something changes from that baseline. Wait for the next poll after a real change occurs.
/status shows ready: false and never changes
- Login or the first timetable fetch is failing β check logs for errors above the HTTP server startup message
readyonly becomestrueafter the first successful fetch, not on process start
Seeing too many false positives
- Lower
LOOK_AHEADto reduce the window being monitored (e.g.LOOK_AHEAD=2for today and tomorrow only)
# Copy and fill in credentials
cp .env.example .env
# Build and run
go build -o untis-notifier . && ./untis-notifier
# Run tests
go test ./...
# Live reload (requires air)
go install github.com/air-verse/air@latest
airWebUntis is widely used across DACH. If your school uses WebUntis for its timetable, this tool should work without any changes.
Not sure if your school uses WebUntis? Check if your school's timetable URL contains webuntis.com.
Contributions are welcome! Please open an issue first for significant changes so we can discuss the approach.
- Bug reports: use the issue tracker
- Feature requests: open a discussion or issue
- Pull requests: please include tests for new logic