Sign inSign up

thib3113/wakatime-exporter

By thib3113

•Updated 6 days ago

Exports Prometheus metrics from Wakatime.

Image
0

702

thib3113/wakatime-exporter repository overview

GitHub go.mod Go version Docker Image Size (latest by date) Docker Pulls

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 ai collector exposing AI coding statistics from the /durations endpoint, a stats collector 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.

⁠Usage

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

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

⁠Authentication

--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, insightsread_summaries
all-time, statsread_stats
projectsread_stats.projects
machinesread_stats.machines
user-agentsread_stats.editors
goalread_goals
leader, private-leaderboardsread_private_leaderboards
ai, ai-breakdown, external-durations, heartbeatsread_heartbeats
orgsread_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.

⁠AI collector

The ai collector (enabled by default, endpoint GET /users/{user}/durations?date=today) exposes AI coding statistics:

MetricTypeLabelsDescription
wakatime_ai_lines_totalcounterorigin (ai/human), kind (additions/deletions)Lines written by AI vs. typed by a human
wakatime_ai_tokens_totalcounterkind (input/output)AI tokens consumed / produced
wakatime_ai_cost_usd_totalcountermodelEstimated AI cost in USD according to WakaTime pricing
wakatime_ai_sessions_totalcounter–Sum of per-duration AI sessions (may double-count overlapping sessions)
wakatime_ai_prompt_events_totalcounter–Prompts sent to AI tools
wakatime_ai_prompt_length_chars_sumcounter–Sum of prompt characters
wakatime_ai_prompt_length_avg_charsgauge–Mean prompt length in characters
wakatime_durations_seconds_totalcounternameCoded 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.

⁠Stats collector

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.

MetricTypeLabelsDescription
wakatime_stats_secondsgaugerangeTotal seconds, excluding Other
wakatime_stats_seconds_including_othergaugerangeTotal seconds, including Other
wakatime_stats_daily_average_secondsgaugerangeAverage seconds per day, excluding Other
wakatime_stats_daily_average_seconds_including_othergaugerangeAverage seconds per day, including Other
wakatime_stats_best_day_secondsgaugerange, dateSeconds on the best day
wakatime_stats_daysgaugerange, kindDays including/minus holidays, or holidays
wakatime_stats_percent_calculatedgaugerangeBackground calculation progress
wakatime_stats_is_including_todaygaugerangeWhether today is included
wakatime_stats_is_cachedgaugerangeWhether the API served cached stats
wakatime_stats_timeout_minutesgaugerangeKeystroke timeout used for the stats
wakatime_stats_writes_onlygaugerangeWhether writes-only mode was used
wakatime_stats_project_secondsgaugerange, nameSeconds per project
wakatime_stats_language_secondsgaugerange, nameSeconds per language
wakatime_stats_editor_secondsgaugerange, nameSeconds per editor
wakatime_stats_category_secondsgaugerange, nameSeconds per category
wakatime_stats_operating_system_secondsgaugerange, nameSeconds per operating system
wakatime_stats_machine_secondsgaugerange, id, nameSeconds per machine
wakatime_stats_dependency_secondsgaugerange, nameSeconds per dependency
wakatime_stats_ai_tokensgaugerange, kindAI tokens used (input/output)
wakatime_stats_ai_cost_usdgaugerange, modelEstimated AI cost in USD according to WakaTime pricing
wakatime_stats_ai_linesgaugerange, origin, kindLines attributed to AI vs human
wakatime_stats_ai_model_linesgaugerange, modelLines added/removed by each AI model
wakatime_stats_ai_sessionsgaugerangeDistinct AI sessions for the configured range
wakatime_stats_ai_prompt_eventsgaugerangePrompts sent to AI tools
wakatime_stats_project_ai_tokensgaugerange, name, kindAI tokens per project
wakatime_stats_project_ai_cost_usdgaugerange, name, modelEstimated AI cost per project in USD according to WakaTime pricing
wakatime_stats_project_ai_linesgaugerange, name, origin, kindLines

Tag summary

Content type

Image

Digest

sha256:f5bb8da41…

Size

5.5 MB

Last updated

6 days ago

docker pull thib3113/wakatime-exporter