A self-hosted Flask time tracker for real project work, not just toy pomodoro sessions.
It is built for people who juggle billable client work, internal work, personal projects, API-driven automation, and backfilled time entry without wanting their data locked into a SaaS. The app stores everything in SQLite, runs well on small hardware, and keeps billing snapshots on entries so reports stay historically accurate even after rates change.
Most lightweight trackers are good at one narrow workflow and awkward at the rest. This project aims to cover the actual messy cases:
- a live timer when you are actively working
- manual logs when you forgot to track something in the moment
- fixed-fee work where you still want to know your effective hourly rate
- client rollups across multiple projects
- standalone projects that do not belong to a client at all
- payment tracking so billed work and collected cash are not treated as the same thing
- API-controlled timers so external tools can start and stop sessions
- Start, pause, resume, and stop live timers
- Edit running timer notes without stopping the timer
- Adjust the start time of an active timer
- Log manual entries by exact start/end range
- Log hours-only entries when you just want to enter total time
- Keep timer and manual workflows side by side
- Standalone projects
- Clients with multiple linked projects
- Business and personal project categories
- Active and archived project states
- Per-project colors and descriptions
- Hourly billing projects
- Fixed-fee projects
- Effective hourly rate calculation for fixed-fee work
- Per-entry hourly snapshots
- Payments ledger
Incurred Charge,Billed amount,Discounted amount, andPaid amountviews
- Project-scoped API keys
- Separate API hourly value
- API/manual overlap billing rules
- API timer status, start, and stop endpoints
- Dashboard summaries
- Project detail views
- Client rollups
- Date-filtered reports
- CSV export
- Full SQLite backup export/import
- Flask
- SQLite
- Waitress
- Vanilla HTML/CSS/JS
- Docker Compose for simple self-hosting
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
$env:PORT = "5300"
python app.pyThen open http://127.0.0.1:5300.
cp .env.example .env
# edit .env and set a real SECRET_KEY
docker compose up -d --buildBy default the app publishes on host port 5300, but you can change that in .env.
The app reads these environment variables:
PORT: listening port. Default is5000forpython app.pyHOST: listening host. Default is0.0.0.0SECRET_KEY: Flask session secret. Set this in productionFLASK_DEBUG: set to1only for local developmentAPP_TIMEZONE: app wall-clock timezone for stored timestamps
Each project can have its own API key, API hourly rate, and API/manual overlap policy from the project edit screen.
POST /api/timer/startPOST /api/timer/stopGET /api/timer/status
Authenticate with either:
X-Api-Key: <project api key>Authorization: Bearer <project api key>
Optional JSON fields:
notesstarted_atis_billable
Optional JSON fields:
notesended_at
Per project, you can choose:
Count manual + API time separatelySuppress API cost while manual timed work overlaps
That second mode is useful when external automation is tracking context, but you only want the manual timed work to count for overlapping billable windows.
- SQLite database path:
instance/time_tracker.db - In Docker, SQLite is persisted under
./data/time_tracker.dbthrough the mounted/app/instancevolume - The app creates the database and tables automatically on first boot
- Timestamps are stored as local wall-clock values in the app's configured timezone
Run the test suite:
python -m unittest discover -s tests- Do not commit
.env - Do not commit live database files
- Do not commit generated project API keys
- Rotate any keys used in private environments before exposing a public instance
- Set a real
SECRET_KEYbefore deploying anywhere real
If Time Tracker helps you stay organized, recover missed billable hours, or run your own self-hosted workflow with less friction, consider supporting the project. Support helps fund ongoing polish, new features, and the time it takes to keep the app useful in real-world work.
Support the project: https://www.buymeacoffee.com/benralph