Self-hosted service
muety/wakapi avatar
muety/wakapi

Wakapi: a self-hosted WakaTime-compatible backend, installed with Docker

📊 A minimalist, self-hosted WakaTime-compatible backend for coding statistics

4,437 stars303 forksGoMIT

At a glance

What is it?
Wakapi is an MIT-licensed Go server that accepts WakaTime heartbeats and turns them into coding statistics you host yourself. The Docker path is short, but there are real constraints around pull requests, database choice and client configuration.
Who is it for?
Adopt Wakapi if you want WakaTime-style statistics on infrastructure you control and you are comfortable editing ~/.wakatime.cfg on every machine you code on. Skip it if you need a vendor support contract or if you depend on WakaTime features that the README only describes as partially compatible.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Wakapi solves for developers who track their time

WakaTime's client plugins are open source. The service they report to is not. That split is the gap Wakapi fills: it reimplements the server side of the protocol so the same editor plugins can send heartbeats somewhere you control. The README describes the project as "a minimalist, self-hosted WakaTime-compatible backend for coding statistics", and the feature list covers projects, languages, editors, hosts and operating systems, plus badges, weekly email reports, a REST API and Prometheus exports.

The audience is narrow and specific. You are a developer or a small team that already likes WakaTime's per-language and per-project breakdowns, and you either cannot or do not want to send that data to a third party. It is not a general productivity tracker. It does not watch your screen or classify activity; it stores what the WakaTime client tells it and renders aggregates. If you never install a WakaTime plugin, Wakapi has nothing to display.

How Wakapi works: heartbeats in, aggregates out

The data flow starts in the editor. WakaTime plugins periodically emit heartbeats: small records of file, project, language, editor, host and operating system. The client is configured to POST those to an api_url, which for a local instance is http://localhost:3000/api. Wakapi authenticates the request with an API key, stores the heartbeat, and later serves aggregated views and badge images.

The repository layout matches that shape. main.go is the entry point, with routes/, services/, repositories/ and models/ as the main layers, migrations/ for schema changes, and views/ plus static/ for the server-rendered frontend. The Go module list shows chi for routing, GORM drivers for storage, robfig/cron for scheduled work such as the weekly email reports, go-webauthn and argon2id for authentication, and go-badge for generating badge images. The frontend is built with Tailwind through npm scripts that compile static/assets/css/app.css into a minified app.dist.css and bundle icons via scripts/bundle_icons.js.

The container image is built from a multi-stage Dockerfile: a golang:alpine build stage compiles wakapi and a separate healthcheck binary, and the runtime stage is gcr.io/distroless/static:nonroot. That choice is deliberate and the Dockerfile explains it: the static image carries no libc, which suits a CGO-disabled Go binary, and the healthcheck binary exists because curl is not available in a distroless image.

Installing Wakapi with Docker and sending your first heartbeat

The README lists four deployment options: the hosted service at wakapi.dev, a quick-run script, Docker, and compiling from source. Docker is the one most people will reach for. Create a persistent volume first, generate a salt, then run the container on port 3000 with the volume mounted at /data.

bash
docker volume create wakapi-data
SALT="$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w ${1:-32} | head -n 1)"
docker run -d \
  --init \
  -p 3000:3000 \
  -e "WAKAPI_PASSWORD_SALT=$SALT" \
  -v wakapi-data:/data \
  --name wakapi \
  --restart unless-stopped \
  ghcr.io/muety/wakapi:latest

After that, open port 3000, create an account, and copy the API key from the web interface. The README notes that SQLite is the default database and points at the Dockerfile and config.default.yml for MySQL or Postgres. If you prefer Compose, the repository ships a compose.yml that pairs Wakapi with postgres:17 and reads secrets from files; it expects WAKAPI_PASSWORD_SALT, WAKAPI_DB_PASSWORD and WAKAPI_MAIL_SMTP_PASS to be supplied either as environment variables or as mounted secret files.

bash
export WAKAPI_PASSWORD_SALT=changeme
export WAKAPI_DB_PASSWORD=changeme
export WAKAPI_MAIL_SMTP_PASS=changeme
docker compose up -d

The client side is where the setup actually completes. Install the WakaTime plugin for your editor, then edit ~/.wakatime.cfg so the client points at your instance rather than WakaTime's servers.

ini
[settings]
api_url = http://localhost:3000/api
api_key = 406fe41f-6d69-4183-a4cc-121e0c524c2b

Replace the api_key with the one your instance issued. The README also documents a dual-destination setup, where the default [settings] key goes to WakaTime and an [api_urls] section adds Wakapi alongside it. It warns explicitly not to add multiple .* entries, because duplicate keys are invalid in an INI file and wakatime-cli ignores them.

Where Wakapi stops being the right tool

The README says the project is "partially compatible with WakaTime". That phrase carries the main risk. Any WakaTime feature that depends on server-side behaviour Wakapi has not implemented will either fail or silently do nothing, and the README does not enumerate which ones. If your workflow depends on a specific WakaTime report or integration, test it against Wakapi before you migrate.

There is a second, more immediate constraint. A prominent note in the README states that due to limited maintainer time, pull requests are temporarily not accepted. The last push to master was on 2026-08-31 and the most recent release, 2.17.6, dates from 2026-08-19, so the codebase is not abandoned, but you should assume that a bug you find will not be fixed by a patch you submit. Self-hosting here means self-supporting.

Operationally, the defaults are permissive. The Dockerfile sets WAKAPI_INSECURE_COOKIES to true and WAKAPI_ALLOW_SIGNUP to true. That is convenient for a first run on localhost and wrong for anything reachable from the internet. The README points readers at the comments in the config file for security configuration, which is where those two need to be revisited.

Finally, the database choice is a real decision, not a detail. SQLite is the default and keeps everything in one file at /data/wakapi.db, which makes backups trivial and concurrent writes less so. The Compose file takes the other path with Postgres. If you expect multiple users or a busy instance, decide this before you accumulate data, because migrating later means moving it.

Wakapi compared with WakaTime itself

The honest comparison is not feature against feature, because WakaTime is the reference implementation and Wakapi is a compatible reimplementation of it. The difference is who runs the server and who holds the data.

With WakaTime, you install the same client plugins, point them at the hosted API, and get dashboards, reports and integrations without operating anything. You pay in data custody: your heartbeat history lives on someone else's infrastructure, and the free tier has limits the paid tier removes. With Wakapi, you keep the same client experience, and everything after the heartbeat arrives is yours to run. You gain control over retention, exports and access; you take on the container, the volume, the database, the SMTP settings for weekly reports, and the upgrades.

A middle path exists and the README documents it: run both. The [api_urls] configuration sends heartbeats to Wakapi and WakaTime simultaneously, so you can evaluate the self-hosted instance against the hosted one with the same data. The README also mentions a relay option under Settings, Integrations, which forwards heartbeats from Wakapi to WakaTime server-side. The README calls the client-side approach preferred, and that preference is sensible: the client already knows how to fan out, and adding a server hop means Wakapi becomes a dependency for data reaching WakaTime.

Maintenance, upgrades and the MIT licence

Wakapi is MIT licensed, which is about as permissive as it gets: you can run it commercially, modify it and redistribute it, provided the licence and copyright notice travel with it. The repository ships a LICENSE file and a SECURITY.md, so there is a stated channel for reporting vulnerabilities. None of this is legal advice; if you are embedding Wakapi in a product, read the licence text yourself.

Upgrade cost depends on how you installed it. With Docker, pulling a newer ghcr.io/muety/wakapi image and restarting the container is the routine; the application applies migrations from the migrations/ directory on startup. With a source install, the README's flow is go install github.com/muety/wakapi@latest followed by running the binary with a config file. Either way, the thing you must protect is the data: the SQLite file under /data, or the Postgres volume in the Compose setup. The README does not document rollback, so if a migration goes wrong there is no documented path back to the previous schema. Take a backup before you pull.

The pull-request freeze is the maintenance fact that matters most for planning. Releases have continued through 2026, but the maintainers have said they do not have the time to review contributions right now. Treat Wakapi as software you can fork and maintain yourself if you need changes, not as a project that will absorb your fixes.

Editorial conclusion

Adopt Wakapi if you want WakaTime-style statistics on infrastructure you control and you are comfortable editing ~/.wakatime.cfg on every machine you code on. Skip it if you need a vendor support contract or if you depend on WakaTime features that the README only describes as partially compatible. Before committing, verify three things: that your database of choice is wired up correctly, that a heartbeat sent from one of your editors actually lands in the web interface, and that you have a backup routine for the volume holding the SQLite file at /data/wakapi.db.

Frequently asked questions

What is wakapi.dev?

It is the hosted cloud instance of Wakapi, offered as the first of four usage options in the README. You create an account there and then configure your WakaTime client against it, instead of running the server yourself.

How do I install Wakapi with Docker?

The README's Docker option creates a volume named wakapi-data, generates a password salt, and runs ghcr.io/muety/wakapi:latest with port 3000 published and the volume mounted at /data. The WAKAPI_PASSWORD_SALT environment variable must be set, and SQLite is the default database.

What API URL should I put in my WakaTime client config for Wakapi?

The README's client setup example sets api_url to http://localhost:3000/api for a local instance, or https://wakapi.dev/api when using the cloud server. The api_key value comes from the web interface after you create an account.

Can I use Wakapi and WakaTime at the same time?

Yes. The README documents client-side configuration where the [settings] api_key targets WakaTime's default API and an [api_urls] section adds Wakapi as an additional destination. It warns against adding multiple .* entries, since duplicate INI keys are ignored.

Does Wakapi accept pull requests?

The README carries a note stating that, due to limited maintainer time, pull requests are temporarily not accepted. Plan on maintaining your own fork if you need changes.

Official sources

  1. License: MIT
  2. muety/wakapi on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/muety-wakapi.svg)](https://hysenlabs.com/projects/muety-wakapi)