How Uptime Kuma Exposes Prometheus Metrics: A Complete Technical Guide
Uptime Kuma exposes Prometheus metrics through a built-in exporter in server/prometheus.js that registers gauges for each monitor and serves them via a basic-auth protected /metrics endpoint using the prometheus-api-metrics middleware.
Uptime Kuma ships with a native Prometheus exporter that transforms every monitor’s runtime data into labeled time-series metrics. This implementation leverages the prom-client library and integrates directly into the Express server architecture, allowing any Prometheus server to scrape monitoring data for alerting and dashboarding.
Architecture Overview
The exporter consists of four coordinated components that handle metric definition, endpoint exposure, per-monitor data updates, and push-based monitor support. The Prometheus class in server/prometheus.js acts as the central registry, while server/server.js mounts the scrape endpoint. Each monitor instance maintains its own Prometheus helper that updates gauges on every heartbeat.
Core Components
Metric Definitions in server/prometheus.js
The Prometheus class initializes all gauge families in its constructor or init() method. It registers six primary gauges:
monitor_cert_days_remaining– Days until TLS certificate expirymonitor_cert_is_valid– Boolean validity of TLS certificatesmonitor_uptime_ratio– Calculated uptime percentage over sliding windows (1d, 7d, 30d, 90d)monitor_response_time_seconds– Response time in secondsmonitor_response_time– Response time in millisecondsmonitor_status– Current monitor status (1 = up, 0 = down)
All gauges share a common label set defined at startup: monitor_id, monitor_name, monitor_type, monitor_url, monitor_hostname, monitor_port, plus every tag name existing in the database. The sanitizeForPrometheus() method strips illegal characters from tag names and values, keeping only alphanumerics and underscores.
The /metrics Endpoint in server/server.js
The scrape endpoint is registered in server/server.js:
app.get("/metrics", apiAuth, prometheusAPIMetrics())
The route uses apiAuth middleware, which enforces basic authentication using the first Uptime Kuma user’s credentials. The prometheus-api-metrics middleware reads the prom-client registry and renders the metrics in Prometheus text exposition format (text/plain; version=0.0.4).
Per-Monitor Updates in server/model/monitor.js
Each monitor instantiates a Prometheus helper during initialization:
// In server/model/monitor.js constructor
this.prometheus = new Prometheus(this, await this.getTags());
On every heartbeat, the monitor calls:
this.prometheus.update(bean, tlsInfo, uptime);
The update() method extracts TLS certificate information, response times, and uptime window calculations, then invokes .set() on each gauge with the monitor’s pre-calculated label values. Errors during update are caught and logged to prevent a single monitor from crashing the exporter.
Push Monitor Support in server/routers/api-router.js
For push-type monitors, the API router handles inbound heartbeats at /api/push/:monitorID. When a heartbeat is received, the router creates a temporary Prometheus instance:
new Prometheus(monitor, []).update(bean, undefined);
This updates the gauges immediately without requiring the monitor to maintain a persistent connection, ensuring push monitors appear in the metrics endpoint alongside polled monitors.
How Metrics Are Collected and Updated
The data flow follows this sequence:
- Startup:
Prometheus.init()registers gauge families and collects all tag names from the database to define the complete label schema. - Monitor Creation: Each monitor constructs a
Prometheusinstance with its static labels (ID, name, type, URL, hostname, port) and dynamic tag values. - Heartbeat Processing: On every check (or push), the monitor calls
prometheus.update(), which sets gauge values for response time, status, certificate validity, and uptime ratios. - Scrape: Prometheus server queries
GET /metrics, triggeringprometheus-api-metricsto serialize the registry into text format.
Important: Because tag names are collected once at startup, adding new tags via the UI requires restarting Uptime Kuma to expose them as metric labels.
Accessing the Metrics Endpoint
To scrape metrics, authenticate using the first user’s credentials created during setup:
curl -u admin:yourPassword http://localhost:3001/metrics
The endpoint returns standard Prometheus exposition format:
# HELP monitor_uptime_ratio Uptime ratio calculated over sliding window
# TYPE monitor_uptime_ratio gauge
monitor_uptime_ratio{monitor_id="1",monitor_name="Production API",monitor_type="http",monitor_url="https://api.example.com",tag_env="production",window="1d"} 0.9987
monitor_uptime_ratio{monitor_id="1",monitor_name="Production API",monitor_type="http",monitor_url="https://api.example.com",tag_env="production",window="30d"} 0.9854
Summary
- Uptime Kuma exposes Prometheus metrics via a built-in exporter using the
prom-clientlibrary andprometheus-api-metricsmiddleware. - Metric definitions reside in
server/prometheus.js, where gauges for response time, uptime ratios, certificate validity, and status are registered with a comprehensive label set including monitor fields and tags. - Data updates occur in
server/model/monitor.js, where each monitor maintains aPrometheusinstance that updates gauges on every heartbeat. - The
/metricsendpoint is mounted inserver/server.jswith basic authentication (apiAuth), allowing Prometheus to scrape metrics in standard text format. - Push monitors are supported via
server/routers/api-router.js, which creates temporaryPrometheusinstances to update metrics when heartbeats are pushed to the API.
Frequently Asked Questions
What authentication is required to access the Prometheus metrics endpoint?
The /metrics endpoint uses the same basic authentication as the Uptime Kuma web interface. You must provide the username and password of the first user created in the system. The apiAuth middleware enforces this in server/server.js before allowing access to the Prometheus exposition format.
Which metrics are exposed by Uptime Kuma?
Uptime Kuma exposes six primary gauge metrics: monitor_cert_days_remaining for TLS expiry countdown, monitor_cert_is_valid for certificate validity, monitor_uptime_ratio for availability percentages over 1d/7d/30d/90d windows, monitor_response_time_seconds and monitor_response_time for latency in seconds and milliseconds, and monitor_status indicating up (1) or down (0) states.
Why do new tags not appear in Prometheus metrics immediately?
Tag names are collected once during startup when Prometheus.init() runs in server/prometheus.js. Because the label schema is defined at initialization, any tags added through the UI after the server has started will not appear as metric labels until you restart Uptime Kuma to re-initialize the Prometheus registry.
How are push monitors handled differently from regular monitors?
Regular monitors update their Prometheus gauges automatically during the heartbeat processing loop in server/model/monitor.js. For push monitors, the API router in server/routers/api-router.js handles incoming heartbeats by instantiating a temporary Prometheus object with an empty tag array and calling update() directly, ensuring push-based checks still populate the metrics endpoint without requiring a persistent polling connection.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →