Exports Prometheus metrics from Wakatime.
702
wakatime_exporter is a Prometheus exporter for Wakatime statistics. It intends to extend the existing Wakatime ecosystem via allowing users to make use of Prometheus (and therefore any consumers of its API) as companion services alongside the traditional Wakatime web application. This could be anything from including some of your coding statistics in Grafana, to forecasting your coding time with prophet.
Warning
**WakaTime.com: Basic auth stops working on 2026-11-01.** Classic API keys become write-only, so they can no longer read stats, summaries, goals or organizations. Set `WAKA_API_KEY` to an OAuth token (`waka_tok_...`) instead; `--wakatime.auth-mode=auto` (the default) selects Bearer automatically. Basic auth remains supported for self-hosted equivalents, which do not follow this change.
Actively maintained: this repository (thib3113/wakatime_exporter) continues the project MacroPower/wakatime_exporter, which appears unmaintained (last upstream commit: February 2023). It is published as a standalone repository (not a GitHub fork) so it can be found via GitHub search. Many thanks to Jacob Colvin (MacroPower) for creating the project and maintaining it up to v0.1.0 — all of his work is preserved as-is, including the full git history and the original license headers. On top of upstream, this repository adds: OAuth 2.0 Bearer authentication, a new
aicollector exposing AI coding statistics from the/durationsendpoint, astatscollector exposing range totals (including all-time per-project totals) from the/stats/{range}endpoint, and additional collectors for AI breakdowns, insights, external durations, user agents, projects, machines, private leaderboards, organizations and heartbeats.
NOTE: wakatime_exporter is currently in ALPHA. Expect things to break and change.
Click here to see an example of the exported metrics.
Click here for a simple dashboard you can use to get started.
In most cases, you should only need to provide a credential (an OAuth token, or a classic API key for self-hosted equivalents). All other parameters are for advanced use-cases only and you should be able to leave them set to their defaults.
You can get your Wakatime API key by visiting: https://wakatime.com/api-key
Provide arguments via parameters:
usage: wakatime_exporter --wakatime.api-key=WAKATIME.API-KEY [<flags>]
Flags:
--help, -h Show context-sensitive help.
--collector.ai Enable the ai collector (default: enabled).
--collector.ai-breakdown Enable the ai-breakdown collector (default: enabled).
--collector.all-time Enable the all-time collector (default: enabled).
--collector.external-durations Enable the external-durations collector (default: enabled).
--collector.goal Enable the goal collector (default: enabled).
--collector.heartbeats Enable the heartbeats collector (default: disabled).
--collector.insights Enable the insights collector (default: disabled).
--collector.leader Enable the leader collector (default: enabled).
--collector.machines Enable the machines collector (default: enabled).
--collector.orgs Enable the orgs collector (default: disabled).
--collector.private-leaderboards Enable the private-leaderboards collector (default: disabled).
--collector.projects Enable the projects collector (default: enabled).
--collector.stats Enable the stats collector (default: enabled).
--collector.summary Enable the summary collector (default: enabled).
--collector.user-agents Enable the user-agents collector (default: enabled).
--collector.disable-defaults Set all collectors to disabled by default.
--web.listen-address=":9212" Address to listen on for web interface and telemetry.
--web.metrics-path="/metrics" Path under which to expose metrics.
--web.disable-exporter-metrics Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).
--wakatime.scrape-uri="https://wakatime.com/api/v1"
Base path to query for Wakatime data.
--wakatime.user="current" User to query for Wakatime data.
--wakatime.api-key Token to use when getting stats from Wakatime: a WakaTime OAuth access token
(Bearer auth, waka_tok_...) or, for self-hosted equivalents, a classic API key (Basic auth).
--wakatime.auth-mode="auto" Auth mode for the Wakatime API: auto (Bearer for waka_tok_ tokens, Basic otherwise),
basic, or bearer. Basic is only for self-hosted equivalents.
--wakatime.timeout=5s Timeout for trying to get stats from Wakatime.
--wakatime.ssl-verify Flag that enables SSL certificate verification for the scrape URI.
--stats.range="all_time" Time range for the stats collector: all_time, last_7_days, last_30_days,
last_6_months, last_year, YYYY, or YYYY-MM.
--stats.cache-ttl=1h How long to cache the stats response between scrapes.
--stats.top=50 Keep at most N entries per stats dimension and AI model lines (0 = all).
--stats.min-seconds=60 Drop stats entries below this many seconds (0 = keep all).
--stats.include=REGEX Regex matched against dimension:name for stats.
--stats.exclude=REGEX Regex matched against dimension:name; matching entries are dropped.
--ai.breakdown="language" Comma-separated durations slice_by dimensions for AI breakdown
(language, editor, os, category, machine, project, entity, dependencies).
--ai.top=50 Keep at most N AI entries (projects, models and breakdown dimensions; 0 = all).
--ai.min-tokens=1000 Drop AI breakdown entries below this many total tokens (0 = keep all).
--ai.min-seconds=60 Drop AI project entries below this many seconds (0 = keep all).
--ai.cache-ttl=15m How long to cache AI breakdown responses between scrapes.
--ai.include=REGEX Regex matched against <slice>:<name> for AI breakdown metrics.
--ai.exclude=REGEX Regex matched against <slice>:<name>; matching entries are dropped.
--insights.types="weekdays,best_day,daily_average,ai_days"
Comma-separated insight types.
--insights.range="all_time" Time range for insights.
--insights.cache-ttl=1h How long to cache insights responses between scrapes.
--insights.top=50 Keep at most N entries per insights dimension (0 = all).
--insights.min-seconds=60 Drop insights entries below this many seconds (0 = keep all).
--inventory.top=50 Keep at most N user agents/projects/machines by recency (0 = all).
--inventory.include=REGEX Regex matched against editor:, project:, machine: for inventory.
--inventory.exclude=REGEX Regex matched against editor:, project:, machine:; matching entries are dropped.
--inventory.cache-ttl=1h Cache duration for user agents, projects and machines.
--projects.filter="" Only export projects whose name matches this regex.
--external-durations.date="today" Date for the external durations collector.
--external-durations.include=REGEX Regex matched against project:, provider:, category:, language:.
--external-durations.exclude=REGEX Regex matched against project:, provider:, category:, language:; matching entries are dropped.
--external-durations.cache-ttl=15m How long to cache external durations between scrapes.
--external-durations.top=50 Keep at most N external duration entries (0 = all).
--external-durations.min-seconds=60 Drop external duration entries below this many seconds.
--private-leaderboards.boards="" Comma-separated private leaderboard IDs (empty = all).
--private-leaderboards.types="time,ai,spend"
Comma-separated leaderboard types.
--private-leaderboards.max-pages=1 Maximum number of pages per leaderboard.
--private-leaderboards.top=50 Keep at most N leaders per board and type (0 = all).
--private-leaderboards.cache-ttl=1h
How long to cache private leaderboards between scrapes.
--orgs.ids="" Comma-separated organization IDs (empty = all).
--orgs.cache-ttl=1h How long to cache organizations between scrapes.
--heartbeats.top=50 Keep at most N heartbeat projects (0 = all).
--heartbeats.min-count=1 Drop heartbeat projects below this many heartbeats (0 = keep all).
--heartbeats.include=REGEX Regex matched against project:<name> for heartbeat metrics.
--heartbeats.exclude=REGEX Regex matched against project:<name>; matching projects are dropped.
--heartbeats.cache-ttl=15m How long to cache heartbeats between scrapes.
--log.level=info Only log messages with the given severity or above.
One of: [debug, info, warn, error]
--log.format=logfmt Output format of log messages.
One of: [logfmt, json]
--version Show application version.
and/or via environment variables:
WAKA_LISTEN_ADDRESS=":9212" # Address to listen on for web interface and telemetry.
WAKA_METRICS_PATH="/metrics" # Path under which to expose metrics.
WAKA_SCRAPE_URI="https://wakatime.com/api/v1" # Base path to query for Wakatime data.
WAKA_USER="current" # User to query for Wakatime data.
WAKA_API_KEY="" # Token to use when getting stats from Wakatime.
WAKA_AUTH_MODE="auto" # Auth mode: auto, basic, or bearer.
WAKA_TIMEOUT="5s" # Timeout for trying to get stats from Wakatime.
WAKA_SSL_VERIFY="true" # SSL certificate verification for the scrape URI.
WAKA_DISABLE_EXPORTER_METRICS="false" # Exclude metrics about the exporter itself.
WAKA_DISABLE_DEFAULT_COLLECTORS="false" # Start with all collectors disabled.
WAKA_COLLECTOR_AI="true" # Enable the ai collector.
WAKA_COLLECTOR_AIBREAKDOWN="true" # Enable the ai-breakdown collector.
WAKA_COLLECTOR_ALLTIME="true" # Enable the all-time collector.
WAKA_COLLECTOR_EXTERNALDURATIONS="true" # Enable the external-durations collector.
WAKA_COLLECTOR_GOAL="true" # Enable the goal collector.
WAKA_COLLECTOR_HEARTBEATS="false" # Enable the heartbeats collector.
WAKA_COLLECTOR_INSIGHTS="false" # Enable the insights collector.
WAKA_COLLECTOR_LEADER="true" # Enable the leader collector.
WAKA_COLLECTOR_MACHINES="true" # Enable the machines collector.
WAKA_COLLECTOR_ORGS="false" # Enable the orgs collector.
WAKA_COLLECTOR_PRIVATELEADERBOARDS="false" # Enable the private-leaderboards collector.
WAKA_COLLECTOR_PROJECTS="true" # Enable the projects collector.
WAKA_COLLECTOR_STATS="true" # Enable the stats collector.
WAKA_COLLECTOR_SUMMARY="true" # Enable the summary collector.
WAKA_COLLECTOR_USERAGENTS="true" # Enable the user-agents collector.
WAKA_STATS_RANGE="all_time" # Time range for the stats collector.
WAKA_STATS_CACHE_TTL="1h" # Cache duration for the stats response.
WAKA_STATS_TOP="50" # Max entries per stats dimension and AI model lines.
WAKA_STATS_MIN_SECONDS="60" # Drop stats entries below this many seconds.
WAKA_STATS_INCLUDE="" # Regex on dimension:name for stats (include).
WAKA_STATS_EXCLUDE="" # Regex on dimension:name for stats (exclude).
WAKA_AI_BREAKDOWN="language" # AI breakdown dimensions (comma-separated).
WAKA_AI_TOP="50" # Max AI entries (projects, models, breakdown dimensions).
WAKA_AI_MIN_TOKENS="1000" # Drop AI breakdown entries below this many tokens.
WAKA_AI_MIN_SECONDS="60" # Drop AI project entries below this many seconds.
WAKA_AI_CACHE_TTL="15m" # Cache duration for AI breakdown responses.
WAKA_AI_INCLUDE="" # Regex on <slice>:<name> for AI breakdown (include).
WAKA_AI_EXCLUDE="" # Regex on <slice>:<name> for AI breakdown (exclude).
WAKA_INSIGHTS_TYPES="weekdays,best_day,daily_average,ai_days"
WAKA_INSIGHTS_RANGE="all_time" # Time range for insights.
WAKA_INSIGHTS_CACHE_TTL="1h" # Cache duration for insights responses.
WAKA_INSIGHTS_TOP="50" # Max entries per insights dimension.
WAKA_INSIGHTS_MIN_SECONDS="60" # Drop insights entries below this many seconds.
WAKA_INVENTORY_TOP="50" # Keep N most recent user agents/projects/machines.
WAKA_INVENTORY_INCLUDE="" # Regex on editor:, project:, machine: (include).
WAKA_INVENTORY_EXCLUDE="" # Regex on editor:, project:, machine: (exclude).
WAKA_INVENTORY_CACHE_TTL="1h" # Cache duration for user agents, projects, machines.
WAKA_PROJECTS_FILTER="" # Only export projects matching this regex.
WAKA_EXTERNAL_DURATIONS_DATE="today" # Date for external durations.
WAKA_EXTERNAL_DURATIONS_INCLUDE="" # Regex on project:, provider:, category:, language: (include).
WAKA_EXTERNAL_DURATIONS_EXCLUDE="" # Regex on project:, provider:, category:, language: (exclude).
WAKA_EXTERNAL_DURATIONS_CACHE_TTL="15m" # Cache duration for external durations.
WAKA_EXTERNAL_DURATIONS_TOP="50" # Max external duration entries (0 = all).
WAKA_EXTERNAL_DURATIONS_MIN_SECONDS="60" # Drop external durations below this many seconds.
WAKA_PRIVATE_LEADERBOARDS_BOARDS="" # Leaderboard IDs (empty = all).
WAKA_PRIVATE_LEADERBOARDS_TYPES="time,ai,spend"
WAKA_PRIVATE_LEADERBOARDS_MAX_PAGES="1" # Max pages per leaderboard.
WAKA_PRIVATE_LEADERBOARDS_TOP="50" # Max leaders per board and type (0 = all).
WAKA_PRIVATE_LEADERBOARDS_CACHE_TTL="1h" # Cache duration for private leaderboards.
WAKA_ORGS_IDS="" # Organization IDs (empty = all).
WAKA_ORGS_CACHE_TTL="1h" # Cache duration for organizations.
WAKA_HEARTBEATS_TOP="50" # Max heartbeat projects (0 = all).
WAKA_HEARTBEATS_MIN_COUNT="1" # Drop projects below this many heartbeats.
WAKA_HEARTBEATS_INCLUDE="" # Regex on project:<name> for heartbeats (include).
WAKA_HEARTBEATS_EXCLUDE="" # Regex on project:<name> for heartbeats (exclude).
WAKA_HEARTBEATS_CACHE_TTL="15m" # Cache duration for heartbeats.
WAKA_LOG_LEVEL="info" # Log level: debug, info, warn, error.
WAKA_LOG_FORMAT="logfmt" # Log format: logfmt or json.
docker run -p 9212:9212 -e WAKA_API_KEY="YOUR_API_KEY" thib3113/wakatime-exporter:latest
Or use Docker Compose:
# Linux & Darwin
WAKA_API_KEY="YOUR_API_KEY" docker compose up
# Windows
$env:WAKA_API_KEY="YOUR_API_KEY"; docker compose up
--wakatime.api-key (WAKA_API_KEY) accepts a WakaTime OAuth access token
(waka_tok_..., Authorization: Bearer) or, for self-hosted equivalents only,
a classic Wakatime API key (Basic auth).
--wakatime.auth-mode (WAKA_AUTH_MODE, default auto) selects the scheme:
auto uses Bearer for waka_tok_ tokens and Basic otherwise;
basic / bearer force the mode (useful for testing, unprefixed tokens, and
self-hosted equivalents).
For personal use (your own account), grab a ready-made OAuth token at https://wakatime.com/oauth ("Your secret OAuth token") — no app to register. It can read your email, summaries, stats, goals, organizations, and coding activity, so keep it secret and prefer it over your API key, which becomes write-only.
To get an OAuth token for other users, register an app at https://wakatime.com/apps (see https://wakatime.com/developers#authentication) with at least the scopes required by the collectors you enable:
| Collector(s) | Required OAuth scope(s) |
|---|---|
summary, insights | read_summaries |
all-time, stats | read_stats |
projects | read_stats.projects |
machines | read_stats.machines |
user-agents | read_stats.editors |
goal | read_goals |
leader, private-leaderboards | read_private_leaderboards |
ai, ai-breakdown, external-durations, heartbeats | read_heartbeats |
orgs | read_orgs |
Note that the ai, ai-breakdown, external-durations and heartbeats
collectors need the broader read_heartbeats scope.
insights, heartbeats, orgs and private-leaderboards are disabled by default.
Disable any collector you don't need with --collector.<name>=false
(or WAKA_COLLECTOR_<NAME>=false) to follow the least-privilege principle.
The ai collector (enabled by default, endpoint GET /users/{user}/durations?date=today)
exposes AI coding statistics:
| Metric | Type | Labels | Description |
|---|---|---|---|
wakatime_ai_lines_total | counter | origin (ai/human), kind (additions/deletions) | Lines written by AI vs. typed by a human |
wakatime_ai_tokens_total | counter | kind (input/output) | AI tokens consumed / produced |
wakatime_ai_cost_usd_total | counter | model | Estimated AI cost in USD according to WakaTime pricing |
wakatime_ai_sessions_total | counter | – | Sum of per-duration AI sessions (may double-count overlapping sessions) |
wakatime_ai_prompt_events_total | counter | – | Prompts sent to AI tools |
wakatime_ai_prompt_length_chars_sum | counter | – | Sum of prompt characters |
wakatime_ai_prompt_length_avg_chars | gauge | – | Mean prompt length in characters |
wakatime_durations_seconds_total | counter | name | Coded seconds per project, summed from durations (same label as wakatime_project_seconds_total) |
It requires the OAuth scope read_heartbeats (see Authentication)
and returns no data (ErrNoData, never a fatal error) when the endpoint has nothing to report.
Disable it with --collector.ai=false or WAKA_COLLECTOR_AI=false.
The stats collector (enabled by default, endpoint GET /users/{user}/stats/{range})
exposes totals for a configurable range. The default is all_time, i.e. the same
lifetime data the WakaTime UI shows: a project at 120 h is exported as
wakatime_stats_project_seconds{range="all_time",name="..."} 432000.
Unlike the summary and ai collectors (which query today and therefore restart
every day), these metrics are gauges whose value depends on --stats.range.
They are cached for --stats.cache-ttl (default 1h) to avoid one API call per
scrape. When WakaTime reports stale stats (is_up_to_date=false), the exporter
still emits the last known values with wakatime_stats_up_to_date{range="..."} 0
and retries after one minute.
| Metric | Type | Labels | Description |
|---|---|---|---|
wakatime_stats_seconds | gauge | range | Total seconds, excluding Other |
wakatime_stats_seconds_including_other | gauge | range | Total seconds, including Other |
wakatime_stats_daily_average_seconds | gauge | range | Average seconds per day, excluding Other |
wakatime_stats_daily_average_seconds_including_other | gauge | range | Average seconds per day, including Other |
wakatime_stats_best_day_seconds | gauge | range, date | Seconds on the best day |
wakatime_stats_days | gauge | range, kind | Days including/minus holidays, or holidays |
wakatime_stats_percent_calculated | gauge | range | Background calculation progress |
wakatime_stats_is_including_today | gauge | range | Whether today is included |
wakatime_stats_is_cached | gauge | range | Whether the API served cached stats |
wakatime_stats_timeout_minutes | gauge | range | Keystroke timeout used for the stats |
wakatime_stats_writes_only | gauge | range | Whether writes-only mode was used |
wakatime_stats_project_seconds | gauge | range, name | Seconds per project |
wakatime_stats_language_seconds | gauge | range, name | Seconds per language |
wakatime_stats_editor_seconds | gauge | range, name | Seconds per editor |
wakatime_stats_category_seconds | gauge | range, name | Seconds per category |
wakatime_stats_operating_system_seconds | gauge | range, name | Seconds per operating system |
wakatime_stats_machine_seconds | gauge | range, id, name | Seconds per machine |
wakatime_stats_dependency_seconds | gauge | range, name | Seconds per dependency |
wakatime_stats_ai_tokens | gauge | range, kind | AI tokens used (input/output) |
wakatime_stats_ai_cost_usd | gauge | range, model | Estimated AI cost in USD according to WakaTime pricing |
wakatime_stats_ai_lines | gauge | range, origin, kind | Lines attributed to AI vs human |
wakatime_stats_ai_model_lines | gauge | range, model | Lines added/removed by each AI model |
wakatime_stats_ai_sessions | gauge | range | Distinct AI sessions for the configured range |
wakatime_stats_ai_prompt_events | gauge | range | Prompts sent to AI tools |
wakatime_stats_project_ai_tokens | gauge | range, name, kind | AI tokens per project |
wakatime_stats_project_ai_cost_usd | gauge | range, name, model | Estimated AI cost per project in USD according to WakaTime pricing |
wakatime_stats_project_ai_lines | gauge | range, name, origin, kind | Lines |
Content type
Image
Digest
sha256:f5bb8da41…
Size
5.5 MB
Last updated
6 days ago
docker pull thib3113/wakatime-exporter